@ukeyfe/hardware-transport 1.1.13
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/.eslintrc +24 -0
- package/README.md +29 -0
- package/__tests__/build-receive.test.js +117 -0
- package/__tests__/decode-features.test.js +72 -0
- package/__tests__/encode-decode-basic.test.js +272 -0
- package/__tests__/encode-decode.test.js +532 -0
- package/__tests__/messages.test.js +86 -0
- package/dist/constants.d.ts +6 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/index.d.ts +5203 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +942 -0
- package/dist/serialization/index.d.ts +6 -0
- package/dist/serialization/index.d.ts.map +1 -0
- package/dist/serialization/protobuf/decode.d.ts +6 -0
- package/dist/serialization/protobuf/decode.d.ts.map +1 -0
- package/dist/serialization/protobuf/encode.d.ts +5 -0
- package/dist/serialization/protobuf/encode.d.ts.map +1 -0
- package/dist/serialization/protobuf/index.d.ts +4 -0
- package/dist/serialization/protobuf/index.d.ts.map +1 -0
- package/dist/serialization/protobuf/messages.d.ts +11 -0
- package/dist/serialization/protobuf/messages.d.ts.map +1 -0
- package/dist/serialization/protocol/decode.d.ts +11 -0
- package/dist/serialization/protocol/decode.d.ts.map +1 -0
- package/dist/serialization/protocol/encode.d.ts +11 -0
- package/dist/serialization/protocol/encode.d.ts.map +1 -0
- package/dist/serialization/protocol/index.d.ts +3 -0
- package/dist/serialization/protocol/index.d.ts.map +1 -0
- package/dist/serialization/receive.d.ts +8 -0
- package/dist/serialization/receive.d.ts.map +1 -0
- package/dist/serialization/send.d.ts +7 -0
- package/dist/serialization/send.d.ts.map +1 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/messages.d.ts +3762 -0
- package/dist/types/messages.d.ts.map +1 -0
- package/dist/types/transport.d.ts +62 -0
- package/dist/types/transport.d.ts.map +1 -0
- package/dist/utils/highlevel-checks.d.ts +10 -0
- package/dist/utils/highlevel-checks.d.ts.map +1 -0
- package/dist/utils/logBlockCommand.d.ts +2 -0
- package/dist/utils/logBlockCommand.d.ts.map +1 -0
- package/dist/utils/protobuf.d.ts +2 -0
- package/dist/utils/protobuf.d.ts.map +1 -0
- package/jest.config.js +7 -0
- package/package.json +31 -0
- package/protocol.md +21 -0
- package/scripts/protobuf-build.sh +58 -0
- package/scripts/protobuf-patches/TxAck.js +44 -0
- package/scripts/protobuf-patches/TxInputType.js +49 -0
- package/scripts/protobuf-patches/TxOutputType.js +50 -0
- package/scripts/protobuf-patches/index.js +274 -0
- package/scripts/protobuf-types.js +283 -0
- package/src/constants.ts +8 -0
- package/src/index.ts +41 -0
- package/src/serialization/index.ts +8 -0
- package/src/serialization/protobuf/decode.ts +95 -0
- package/src/serialization/protobuf/encode.ts +79 -0
- package/src/serialization/protobuf/index.ts +3 -0
- package/src/serialization/protobuf/messages.ts +37 -0
- package/src/serialization/protocol/decode.ts +48 -0
- package/src/serialization/protocol/encode.ts +59 -0
- package/src/serialization/protocol/index.ts +2 -0
- package/src/serialization/receive.ts +18 -0
- package/src/serialization/send.ts +56 -0
- package/src/types/index.ts +2 -0
- package/src/types/messages.ts +4864 -0
- package/src/types/transport.ts +71 -0
- package/src/utils/highlevel-checks.ts +88 -0
- package/src/utils/logBlockCommand.ts +1 -0
- package/src/utils/protobuf.ts +24 -0
- package/tsconfig.json +11 -0
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
const UINT_TYPE = 'UintType';
|
|
5
|
+
|
|
6
|
+
// type rule fixes, ideally it should not be here
|
|
7
|
+
const RULE_PATCH = {
|
|
8
|
+
'MultisigRedeemScriptType.nodes': 'optional', // its valid to be undefined according to implementation/tests
|
|
9
|
+
'MultisigRedeemScriptType.address_n': 'optional', // its valid to be undefined according to implementation/tests
|
|
10
|
+
'TxRequestDetailsType.request_index': 'required',
|
|
11
|
+
'TxRequest.request_type': 'required',
|
|
12
|
+
'TxRequest.details': 'required',
|
|
13
|
+
'TxAckPaymentRequest.memos': 'optional', // protobuf repeated bytes are always optional (fallback to [])
|
|
14
|
+
'CardanoPoolOwnerType.staking_key_path': 'optional',
|
|
15
|
+
'CardanoPoolOwner.staking_key_path': 'optional',
|
|
16
|
+
'CardanoTxCertificateType.path': 'optional',
|
|
17
|
+
'CardanoTxCertificate.path': 'optional',
|
|
18
|
+
'CardanoTxInputType.address_n': 'optional',
|
|
19
|
+
'CardanoTxWithdrawal.path': 'optional',
|
|
20
|
+
'CardanoNativeScript.scripts': 'optional',
|
|
21
|
+
'CardanoNativeScript.key_path': 'optional',
|
|
22
|
+
'CardanoTxRequiredSigner.key_path': 'optional',
|
|
23
|
+
'Success.message': 'required', // didn't find use case where it's not sent
|
|
24
|
+
'SignedIdentity.address': 'required',
|
|
25
|
+
'EosAuthorizationKey.key': 'required', // its valid to be undefined according to implementation/tests
|
|
26
|
+
'EosAuthorizationKey.type': 'optional', // its valid to be undefined according to implementation/tests
|
|
27
|
+
'EosAuthorizationKey.address_n': 'optional', // its valid to be undefined according to implementation/tests
|
|
28
|
+
'EthereumAddress.address': 'required', // address is transformed from legacy type _old_address
|
|
29
|
+
// TODO: Features should be union: bootloader|normal
|
|
30
|
+
// fields below are marked as required because of backward compatibility (suite implementation)
|
|
31
|
+
'Features.vendor': 'required',
|
|
32
|
+
'Features.bootloader_mode': 'required',
|
|
33
|
+
'Features.device_id': 'required',
|
|
34
|
+
'Features.major_version': 'required',
|
|
35
|
+
'Features.minor_version': 'required',
|
|
36
|
+
'Features.patch_version': 'required',
|
|
37
|
+
'Features.pin_protection': 'required',
|
|
38
|
+
'Features.passphrase_protection': 'required',
|
|
39
|
+
'Features.language': 'required',
|
|
40
|
+
'Features.label': 'required',
|
|
41
|
+
'Features.initialized': 'required',
|
|
42
|
+
'Features.revision': 'required',
|
|
43
|
+
'Features.bootloader_hash': 'required',
|
|
44
|
+
'Features.imported': 'required',
|
|
45
|
+
'Features.unlocked': 'required',
|
|
46
|
+
'Features.firmware_present': 'required',
|
|
47
|
+
'Features.needs_backup': 'required',
|
|
48
|
+
'Features.flags': 'required',
|
|
49
|
+
'Features.fw_major': 'required',
|
|
50
|
+
'Features.fw_minor': 'required',
|
|
51
|
+
'Features.fw_patch': 'required',
|
|
52
|
+
'Features.fw_vendor': 'required',
|
|
53
|
+
'Features.model': 'required',
|
|
54
|
+
'Features.unfinished_backup': 'required',
|
|
55
|
+
'Features.no_backup': 'required',
|
|
56
|
+
'Features.recovery_mode': 'required',
|
|
57
|
+
'Features.backup_type': 'required',
|
|
58
|
+
'Features.sd_card_present': 'required',
|
|
59
|
+
'Features.sd_protection': 'required',
|
|
60
|
+
'Features.wipe_code_protection': 'required',
|
|
61
|
+
'Features.session_id': 'required',
|
|
62
|
+
'Features.passphrase_always_on_device': 'required',
|
|
63
|
+
'Features.safety_checks': 'required',
|
|
64
|
+
'Features.auto_lock_delay_ms': 'required',
|
|
65
|
+
'Features.display_rotation': 'required',
|
|
66
|
+
'Features.experimental_features': 'required',
|
|
67
|
+
'GetOwnershipProof.ownership_ids': 'optional', // protobuf repeated bytes are always optional (fallback to [])
|
|
68
|
+
'NEMTransactionCommon.address_n': 'optional', // no address_n in multisig
|
|
69
|
+
'NEMTransfer.mosaics': 'optional', // its valid to be undefined according to implementation/tests
|
|
70
|
+
'NEMMosaicDefinition.networks': 'optional', // never used according to implementation/tests
|
|
71
|
+
'NEMAggregateModification.modifications': 'optional', // its valid to be undefined according to implementation/tests
|
|
72
|
+
'StellarAssetType.code': 'required',
|
|
73
|
+
'StellarPathPaymentStrictReceiveOp.paths': 'optional', // its valid to be undefined according to implementation/tests
|
|
74
|
+
'StellarPathPaymentStrictSendOp.paths': 'optional', // its valid to be undefined according to implementation/tests
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
// custom types IN to trezor
|
|
78
|
+
// protobuf lib will handle the translation to required type
|
|
79
|
+
// connect or other 3rd party libs are using compatible types (string as number etc...)
|
|
80
|
+
const TYPE_PATCH = {
|
|
81
|
+
'Features.bootloader_mode': 'boolean | null',
|
|
82
|
+
'Features.device_id': 'string | null',
|
|
83
|
+
'Features.pin_protection': 'boolean | null',
|
|
84
|
+
'Features.passphrase_protection': 'boolean | null',
|
|
85
|
+
'Features.language': 'string | null',
|
|
86
|
+
'Features.label': 'string | null',
|
|
87
|
+
'Features.initialized': 'boolean | null',
|
|
88
|
+
'Features.revision': 'string | null',
|
|
89
|
+
'Features.bootloader_hash': 'string | null',
|
|
90
|
+
'Features.imported': 'boolean | null',
|
|
91
|
+
'Features.unlocked': 'boolean | null',
|
|
92
|
+
'Features.firmware_present': 'boolean | null',
|
|
93
|
+
'Features.needs_backup': 'boolean | null',
|
|
94
|
+
'Features.flags': 'number | null',
|
|
95
|
+
'Features.fw_major': 'number | null',
|
|
96
|
+
'Features.fw_minor': 'number | null',
|
|
97
|
+
'Features.fw_patch': 'number | null',
|
|
98
|
+
'Features.fw_vendor': 'string | null',
|
|
99
|
+
'Features.unfinished_backup': 'boolean | null',
|
|
100
|
+
'Features.no_backup': 'boolean | null',
|
|
101
|
+
'Features.recovery_mode': 'boolean | null',
|
|
102
|
+
'Features.backup_type': 'BackupType | null',
|
|
103
|
+
'Features.sd_card_present': 'boolean | null',
|
|
104
|
+
'Features.sd_protection': 'boolean | null',
|
|
105
|
+
'Features.wipe_code_protection': 'boolean | null',
|
|
106
|
+
'Features.session_id': 'string | null',
|
|
107
|
+
'Features.passphrase_always_on_device': 'boolean | null',
|
|
108
|
+
'Features.safety_checks': 'SafetyCheckLevel | null',
|
|
109
|
+
'Features.auto_lock_delay_ms': 'number | null',
|
|
110
|
+
'Features.display_rotation': 'number | null',
|
|
111
|
+
'Features.experimental_features': 'boolean | null',
|
|
112
|
+
'Features.ukey_device_type': 'string | null',
|
|
113
|
+
'Features.ukey_se_type': 'string | null',
|
|
114
|
+
'Features.ukey_se01_state': 'string | null',
|
|
115
|
+
'Features.ukey_se02_state': 'string | null',
|
|
116
|
+
'Features.ukey_se03_state': 'string | null',
|
|
117
|
+
'Features.ukey_se04_state': 'string | null',
|
|
118
|
+
'HDNodePathType.node': 'HDNodeType | string',
|
|
119
|
+
'FirmwareUpload.payload': 'Buffer | ArrayBuffer',
|
|
120
|
+
'EthereumGetAddress.encoded_network': 'ArrayBuffer',
|
|
121
|
+
'EthereumDefinitions.encoded_network': 'ArrayBuffer',
|
|
122
|
+
'EthereumDefinitions.encoded_token': 'ArrayBuffer',
|
|
123
|
+
'EthereumSignMessage.encoded_network': 'ArrayBuffer',
|
|
124
|
+
'EthereumSignTypedHash.encoded_network': 'ArrayBuffer',
|
|
125
|
+
'CardanoCatalystRegistrationParametersType.nonce': UINT_TYPE,
|
|
126
|
+
'CardanoPoolParametersType.pledge': UINT_TYPE,
|
|
127
|
+
'CardanoPoolParametersType.cost': UINT_TYPE,
|
|
128
|
+
'CardanoPoolParametersType.margin_numerator': UINT_TYPE,
|
|
129
|
+
'CardanoPoolParametersType.margin_denominator': UINT_TYPE,
|
|
130
|
+
'CardanoTxCertificate.deposit': UINT_TYPE,
|
|
131
|
+
'CardanoSignTxInit.ttl': UINT_TYPE,
|
|
132
|
+
'CardanoSignTxInit.validity_interval_start': UINT_TYPE,
|
|
133
|
+
'CardanoSignTxInit.total_collateral': UINT_TYPE,
|
|
134
|
+
'CardanoToken.mint_amount': UINT_TYPE,
|
|
135
|
+
'CardanoNativeScript.invalid_before': UINT_TYPE,
|
|
136
|
+
'CardanoNativeScript.invalid_hereafter': UINT_TYPE,
|
|
137
|
+
'EosAsset.symbol': 'string',
|
|
138
|
+
'EosPermissionLevel.actor': 'string',
|
|
139
|
+
'EosPermissionLevel.permission': 'string',
|
|
140
|
+
'EosAuthorizationKey.key': 'string',
|
|
141
|
+
'EosActionCommon.account': 'string',
|
|
142
|
+
'EosActionCommon.name': 'string',
|
|
143
|
+
'EosActionTransfer.sender': 'string',
|
|
144
|
+
'EosActionTransfer.receiver': 'string',
|
|
145
|
+
'EosActionDelegate.sender': 'string',
|
|
146
|
+
'EosActionDelegate.receiver': 'string',
|
|
147
|
+
'EosActionUndelegate.sender': 'string',
|
|
148
|
+
'EosActionUndelegate.receiver': 'string',
|
|
149
|
+
'EosActionRefund.owner': 'string',
|
|
150
|
+
'EosActionBuyRam.payer': 'string',
|
|
151
|
+
'EosActionBuyRam.receiver': 'string',
|
|
152
|
+
'EosActionBuyRamBytes.payer': 'string',
|
|
153
|
+
'EosActionBuyRamBytes.receiver': 'string',
|
|
154
|
+
'EosActionSellRam.account': 'string',
|
|
155
|
+
'EosActionVoteProducer.voter': 'string',
|
|
156
|
+
'EosActionVoteProducer.proxy': 'string',
|
|
157
|
+
'EosActionVoteProducer.producers': 'string',
|
|
158
|
+
'EosActionUpdateAuth.account': 'string',
|
|
159
|
+
'EosActionUpdateAuth.permission': 'string',
|
|
160
|
+
'EosActionUpdateAuth.parent': 'string',
|
|
161
|
+
'EosActionDeleteAuth.account': 'string',
|
|
162
|
+
'EosActionDeleteAuth.permission': 'string',
|
|
163
|
+
'EosActionLinkAuth.account': 'string',
|
|
164
|
+
'EosActionLinkAuth.code': 'string',
|
|
165
|
+
'EosActionLinkAuth.type': 'string',
|
|
166
|
+
'EosActionLinkAuth.requirement': 'string',
|
|
167
|
+
'EosActionUnlinkAuth.account': 'string',
|
|
168
|
+
'EosActionUnlinkAuth.code': 'string',
|
|
169
|
+
'EosActionUnlinkAuth.type': 'string',
|
|
170
|
+
'EosActionNewAccount.creator': 'string',
|
|
171
|
+
'EosActionNewAccount.name': 'string',
|
|
172
|
+
'ResetDevice.backup_type': 'string | number', // BackupType is a enum. in Features displayed as string, in resetDevice method param accepted as number
|
|
173
|
+
'StellarAssetType.type': '0 | 1 | 2',
|
|
174
|
+
'StellarSignTx.sequence_number': UINT_TYPE,
|
|
175
|
+
'StellarSignTx.memo_id': 'string',
|
|
176
|
+
'StellarSignTx.memo_hash': 'Buffer | string',
|
|
177
|
+
'StellarCreateAccountOp.starting_balance': UINT_TYPE,
|
|
178
|
+
'StellarPathPaymentStrictReceiveOp.send_max': UINT_TYPE,
|
|
179
|
+
'StellarPathPaymentStrictReceiveOp.destination_amount': UINT_TYPE,
|
|
180
|
+
'StellarPathPaymentStrictSendOp.send_amount': UINT_TYPE,
|
|
181
|
+
'StellarPathPaymentStrictSendOp.destination_min': UINT_TYPE,
|
|
182
|
+
'StellarManageSellOfferOp.offer_id': UINT_TYPE,
|
|
183
|
+
'StellarManageBuyOfferOp.offer_id': UINT_TYPE,
|
|
184
|
+
'StellarSetOptionsOp.master_weight': UINT_TYPE,
|
|
185
|
+
'StellarSetOptionsOp.low_threshold': UINT_TYPE,
|
|
186
|
+
'StellarSetOptionsOp.medium_threshold': UINT_TYPE,
|
|
187
|
+
'StellarSetOptionsOp.high_threshold': UINT_TYPE,
|
|
188
|
+
'StellarSetOptionsOp.signer_key': 'Buffer | string',
|
|
189
|
+
'StellarChangeTrustOp.limit': UINT_TYPE,
|
|
190
|
+
'StellarManageDataOp.value': 'Buffer | string',
|
|
191
|
+
'StellarBumpSequenceOp.bump_to': UINT_TYPE,
|
|
192
|
+
'TezosContractID.tag': 'number',
|
|
193
|
+
'TezosContractID.hash': 'Uint8Array',
|
|
194
|
+
'TezosRevealOp.source': 'Uint8Array',
|
|
195
|
+
'TezosRevealOp.public_key': 'Uint8Array',
|
|
196
|
+
'TezosParametersManager.set_delegate': 'Uint8Array',
|
|
197
|
+
'TezosTransactionOp.source': 'Uint8Array',
|
|
198
|
+
'TezosTransactionOp.parameters': 'number[]',
|
|
199
|
+
'TezosOriginationOp.source': 'Uint8Array',
|
|
200
|
+
'TezosOriginationOp.delegate': 'Uint8Array',
|
|
201
|
+
'TezosOriginationOp.script': 'string | number[]',
|
|
202
|
+
'TezosDelegationOp.source': 'Uint8Array',
|
|
203
|
+
'TezosDelegationOp.delegate': 'Uint8Array',
|
|
204
|
+
'TezosSignTx.branch': 'Uint8Array',
|
|
205
|
+
'TonSignMessage.ton_amount': UINT_TYPE,
|
|
206
|
+
'TonSignMessage.jetton_amount': UINT_TYPE,
|
|
207
|
+
'TonSignMessage.fwd_fee': UINT_TYPE,
|
|
208
|
+
'TonSignMessage.expire_at': UINT_TYPE,
|
|
209
|
+
'TonSignMessage.ext_ton_amount': UINT_TYPE,
|
|
210
|
+
'TonSignProof.expire_at': UINT_TYPE,
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
const DEFINITION_PATCH = {
|
|
214
|
+
TxInputType: fs.readFileSync(path.join(__dirname, './TxInputType.js'), 'utf8'),
|
|
215
|
+
TxOutputType: fs.readFileSync(path.join(__dirname, './TxOutputType.js'), 'utf8'),
|
|
216
|
+
TxAck: fs.readFileSync(path.join(__dirname, './TxAck.js'), 'utf8'),
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
// skip unnecessary types
|
|
220
|
+
const SKIP = [
|
|
221
|
+
'MessageType', // connect uses custom definition
|
|
222
|
+
'TransactionType', // connect uses custom definition
|
|
223
|
+
'TxInput', // declared in TxInputType patch
|
|
224
|
+
'TxOutput', // declared in TxOutputType patch
|
|
225
|
+
// not implemented
|
|
226
|
+
'CosiCommit',
|
|
227
|
+
'CosiCommitment',
|
|
228
|
+
'CosiSign',
|
|
229
|
+
'CosiSignature',
|
|
230
|
+
'DebugSwipeDirection',
|
|
231
|
+
'DebugLinkDecision',
|
|
232
|
+
'DebugLinkLayout',
|
|
233
|
+
'DebugLinkReseedRandom',
|
|
234
|
+
'DebugLinkRecordScreen',
|
|
235
|
+
'DebugLinkGetState',
|
|
236
|
+
'DebugLinkState',
|
|
237
|
+
'DebugLinkStop',
|
|
238
|
+
'DebugLinkLog',
|
|
239
|
+
'DebugLinkMemoryRead',
|
|
240
|
+
'DebugLinkMemory',
|
|
241
|
+
'DebugLinkMemoryWrite',
|
|
242
|
+
'DebugLinkFlashErase',
|
|
243
|
+
'DebugLinkEraseSdCard',
|
|
244
|
+
'DebugLinkWatchLayout',
|
|
245
|
+
'LoadDevice',
|
|
246
|
+
'DebugMoneroDiagRequest',
|
|
247
|
+
'DebugMoneroDiagAck',
|
|
248
|
+
'WebAuthnListResidentCredentials',
|
|
249
|
+
'WebAuthnAddResidentCredential',
|
|
250
|
+
'WebAuthnRemoveResidentCredential',
|
|
251
|
+
'WebAuthnCredential',
|
|
252
|
+
'WebAuthnCredentials',
|
|
253
|
+
'wire_in',
|
|
254
|
+
'wire_out',
|
|
255
|
+
'wire_debug_in',
|
|
256
|
+
'wire_debug_out',
|
|
257
|
+
'wire_tiny',
|
|
258
|
+
'wire_bootloader',
|
|
259
|
+
'wire_no_fsm',
|
|
260
|
+
'bitcoin_only',
|
|
261
|
+
'has_bitcoin_only_values',
|
|
262
|
+
'unstable',
|
|
263
|
+
'wire_type',
|
|
264
|
+
'experimental',
|
|
265
|
+
'include_in_bitcoin_only',
|
|
266
|
+
];
|
|
267
|
+
|
|
268
|
+
module.exports = {
|
|
269
|
+
RULE_PATCH,
|
|
270
|
+
TYPE_PATCH,
|
|
271
|
+
DEFINITION_PATCH,
|
|
272
|
+
SKIP,
|
|
273
|
+
UINT_TYPE,
|
|
274
|
+
};
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
/* eslint-disable react-hooks/rules-of-hooks */
|
|
2
|
+
/* eslint-disable import/no-unresolved */
|
|
3
|
+
// flowtype only
|
|
4
|
+
// flowtype doesn't have `enum` declarations like typescript
|
|
5
|
+
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
|
|
9
|
+
const json = require('../messages.json');
|
|
10
|
+
const { RULE_PATCH, TYPE_PATCH, DEFINITION_PATCH, SKIP, UINT_TYPE } = require('./protobuf-patches');
|
|
11
|
+
|
|
12
|
+
const args = process.argv.slice(2);
|
|
13
|
+
|
|
14
|
+
const isTypescript = args.includes('typescript');
|
|
15
|
+
|
|
16
|
+
// proto types to javascript types
|
|
17
|
+
const FIELD_TYPES = {
|
|
18
|
+
uint32: 'number',
|
|
19
|
+
uint64: 'number',
|
|
20
|
+
sint32: 'number',
|
|
21
|
+
sint64: 'number',
|
|
22
|
+
bool: 'boolean',
|
|
23
|
+
bytes: 'string',
|
|
24
|
+
// 'bytes': 'Uint8Array | number[] | Buffer | string', // protobuf will handle conversion
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const types = []; // { type: 'enum | message', name: string, value: string[], exact?: boolean };
|
|
28
|
+
|
|
29
|
+
// enums used as keys (string), used as values (number) by default
|
|
30
|
+
const ENUM_KEYS = [
|
|
31
|
+
'InputScriptType',
|
|
32
|
+
'OutputScriptType',
|
|
33
|
+
'RequestType',
|
|
34
|
+
'BackupType',
|
|
35
|
+
'Capability',
|
|
36
|
+
'SafetyCheckLevel',
|
|
37
|
+
'ButtonRequestType',
|
|
38
|
+
'PinMatrixRequestType',
|
|
39
|
+
'WordRequestType',
|
|
40
|
+
];
|
|
41
|
+
|
|
42
|
+
const parseEnumTypescript = (itemName, item) => {
|
|
43
|
+
const value = [];
|
|
44
|
+
const IS_KEY = ENUM_KEYS.includes(itemName);
|
|
45
|
+
// declare enum
|
|
46
|
+
if (IS_KEY) {
|
|
47
|
+
value.push(`export enum Enum_${itemName} {`);
|
|
48
|
+
} else {
|
|
49
|
+
value.push(`export enum ${itemName} {`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// declare fields
|
|
53
|
+
Object.entries(item.values).forEach(([name, id]) => {
|
|
54
|
+
value.push(` ${name} = ${id},`);
|
|
55
|
+
});
|
|
56
|
+
// close enum declaration
|
|
57
|
+
value.push('}');
|
|
58
|
+
|
|
59
|
+
if (IS_KEY) {
|
|
60
|
+
value.push(`export type ${itemName} = keyof typeof Enum_${itemName};`);
|
|
61
|
+
}
|
|
62
|
+
// empty line
|
|
63
|
+
value.push('');
|
|
64
|
+
|
|
65
|
+
types.push({
|
|
66
|
+
type: 'enum',
|
|
67
|
+
name: itemName,
|
|
68
|
+
value: value.join('\n'),
|
|
69
|
+
});
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const parseEnum = (itemName, item) => {
|
|
73
|
+
if (isTypescript) return parseEnumTypescript(itemName, item);
|
|
74
|
+
const value = [];
|
|
75
|
+
// declare enum
|
|
76
|
+
value.push(`export const Enum_${itemName} = Object.freeze({`);
|
|
77
|
+
// declare fields
|
|
78
|
+
Object.entries(item.values).forEach(([name, id]) => {
|
|
79
|
+
value.push(` ${name}: ${id},`);
|
|
80
|
+
});
|
|
81
|
+
// close enum declaration
|
|
82
|
+
value.push('});');
|
|
83
|
+
// declare enum type using Keys or Values
|
|
84
|
+
const KEY = ENUM_KEYS.includes(itemName) ? 'Keys' : 'Values';
|
|
85
|
+
value.push(`export type ${itemName} = $${KEY}<typeof Enum_${itemName}>;`);
|
|
86
|
+
// empty line
|
|
87
|
+
value.push('');
|
|
88
|
+
|
|
89
|
+
types.push({
|
|
90
|
+
type: 'enum',
|
|
91
|
+
name: itemName,
|
|
92
|
+
value: value.join('\n'),
|
|
93
|
+
});
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const useDefinition = def => {
|
|
97
|
+
// remove flow overhead
|
|
98
|
+
const clean = def.replace(/\/\/ @flow/, '').replace(/\/\/ @overhead-start(.*)@overhead-end/s, '');
|
|
99
|
+
|
|
100
|
+
if (isTypescript) {
|
|
101
|
+
// use typescript variant
|
|
102
|
+
// replace flowtype $Exact declaration: {| foo: 1 |} => { foo: 1 }
|
|
103
|
+
// replace flowtype spread with typescript union: { ...T, foo: 1 } => T & { foo: 1 }, see TxInputType patch
|
|
104
|
+
return clean
|
|
105
|
+
.replace(/\/\/ @typescript-variant:/, '')
|
|
106
|
+
.replace(/\/\/ @flowtype-variant(.*)/, '')
|
|
107
|
+
.replace(/{\|/gi, '{')
|
|
108
|
+
.replace(/\|}/gi, '}')
|
|
109
|
+
.replace(/\{\n.*.\.{3}(.*?),/g, '$1 & {');
|
|
110
|
+
}
|
|
111
|
+
return clean.replace(/\/\/ @typescript-variant(.*)/, '').replace(/\/\/ @flowtype-variant:/, '');
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const parseMessage = (messageName, message, depth = 0) => {
|
|
115
|
+
if (messageName === 'google') return;
|
|
116
|
+
const value = [];
|
|
117
|
+
// add comment line
|
|
118
|
+
if (!depth) value.push(`// ${messageName}`);
|
|
119
|
+
// declare nested enums
|
|
120
|
+
|
|
121
|
+
// declare nested values
|
|
122
|
+
if (message.nested) {
|
|
123
|
+
Object.keys(message.nested).map(item => parseMessage(item, message.nested[item], depth + 1));
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (message.values) {
|
|
127
|
+
return parseEnum(messageName, message);
|
|
128
|
+
}
|
|
129
|
+
if (!message.fields || !Object.keys(message.fields).length) {
|
|
130
|
+
// few types are just empty objects, make it one line
|
|
131
|
+
value.push(`export type ${messageName} = {};`);
|
|
132
|
+
value.push('');
|
|
133
|
+
} else {
|
|
134
|
+
// find patch
|
|
135
|
+
const definition = DEFINITION_PATCH[messageName];
|
|
136
|
+
if (definition) {
|
|
137
|
+
// replace whole declaration
|
|
138
|
+
value.push(useDefinition(definition));
|
|
139
|
+
} else {
|
|
140
|
+
// declare type
|
|
141
|
+
value.push(`export type ${messageName} = {`);
|
|
142
|
+
Object.keys(message.fields).forEach(fieldName => {
|
|
143
|
+
const field = message.fields[fieldName];
|
|
144
|
+
const fieldKey = `${messageName}.${fieldName}`;
|
|
145
|
+
// find patch for "rule"
|
|
146
|
+
const fieldRule = RULE_PATCH[fieldKey] || field.rule;
|
|
147
|
+
const rule = fieldRule === 'required' || fieldRule === 'repeated' ? ': ' : '?: ';
|
|
148
|
+
// find patch for "type"
|
|
149
|
+
let type = TYPE_PATCH[fieldKey] || FIELD_TYPES[field.type] || field.type;
|
|
150
|
+
// automatically convert all amount and fee fields to UINT_TYPE
|
|
151
|
+
if (['amount', 'fee'].includes(fieldName)) {
|
|
152
|
+
type = UINT_TYPE;
|
|
153
|
+
}
|
|
154
|
+
// array
|
|
155
|
+
if (field.rule === 'repeated') {
|
|
156
|
+
type = type.split('|').length > 1 ? `Array<${type}>` : `${type}[]`;
|
|
157
|
+
}
|
|
158
|
+
value.push(` ${fieldName}${rule}${type};`);
|
|
159
|
+
});
|
|
160
|
+
// close type declaration
|
|
161
|
+
value.push('};');
|
|
162
|
+
// empty line
|
|
163
|
+
value.push('');
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
// type doest have to be e
|
|
167
|
+
const exact = message.fields && Object.values(message.fields).find(f => f.rule === 'required');
|
|
168
|
+
types.push({
|
|
169
|
+
type: 'message',
|
|
170
|
+
name: messageName,
|
|
171
|
+
value: value.join('\n'),
|
|
172
|
+
exact,
|
|
173
|
+
});
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
// top level messages and nested messages
|
|
177
|
+
Object.keys(json.nested).map(e => parseMessage(e, json.nested[e]));
|
|
178
|
+
|
|
179
|
+
// types needs reordering (used before defined)
|
|
180
|
+
const ORDER = {
|
|
181
|
+
BinanceCoin: 'BinanceInputOutput',
|
|
182
|
+
HDNodeType: 'HDNodePathType',
|
|
183
|
+
CardanoAssetGroupType: 'CardanoTxOutputType',
|
|
184
|
+
CardanoTokenType: 'CardanoAssetGroupType',
|
|
185
|
+
TxAck: 'TxAckInputWrapper',
|
|
186
|
+
EthereumFieldType: 'EthereumStructMember',
|
|
187
|
+
EthereumDataType: 'EthereumFieldType',
|
|
188
|
+
PaymentRequestMemo: 'TxAckPaymentRequest',
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
Object.keys(ORDER).forEach(key => {
|
|
192
|
+
// find indexes
|
|
193
|
+
const indexA = types.findIndex(t => t && t.name === key);
|
|
194
|
+
const indexB = types.findIndex(t => t && t.name === ORDER[key]);
|
|
195
|
+
const prevA = types[indexA];
|
|
196
|
+
// replace values
|
|
197
|
+
delete types[indexA];
|
|
198
|
+
types.splice(indexB, 0, prevA);
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
// skip not needed types
|
|
202
|
+
SKIP.forEach(key => {
|
|
203
|
+
const index = types.findIndex(t => t && t.name === key);
|
|
204
|
+
delete types[index];
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
// create content from types
|
|
208
|
+
const content = types.flatMap(t => (t ? [t.value] : [])).join('\n');
|
|
209
|
+
|
|
210
|
+
const lines = []; // string[]
|
|
211
|
+
if (!isTypescript) lines.push('// @flow');
|
|
212
|
+
lines.push('// This file is auto generated from data/messages/message.json');
|
|
213
|
+
lines.push('');
|
|
214
|
+
lines.push('// custom type uint32/64 may be represented as string');
|
|
215
|
+
lines.push(`export type ${UINT_TYPE} = string | number;`);
|
|
216
|
+
lines.push('');
|
|
217
|
+
lines.push(content);
|
|
218
|
+
|
|
219
|
+
// create custom definition
|
|
220
|
+
if (!isTypescript) {
|
|
221
|
+
lines.push('// custom connect definitions');
|
|
222
|
+
lines.push('export type MessageType = {');
|
|
223
|
+
types
|
|
224
|
+
.flatMap(t => (t && t.type === 'message' ? [t] : []))
|
|
225
|
+
.forEach(t => {
|
|
226
|
+
if (t.exact) {
|
|
227
|
+
lines.push(` ${t.name}: $Exact<${t.name}>;`);
|
|
228
|
+
} else {
|
|
229
|
+
lines.push(` ${t.name}: ${t.name};`);
|
|
230
|
+
}
|
|
231
|
+
// lines.push(' ' + t.name + ': $Exact<' + t.name + '>;');
|
|
232
|
+
});
|
|
233
|
+
lines.push('};');
|
|
234
|
+
|
|
235
|
+
// additional types utilities
|
|
236
|
+
lines.push(`
|
|
237
|
+
export type MessageKey = $Keys<MessageType>;
|
|
238
|
+
|
|
239
|
+
export type MessageResponse<T: MessageKey> = {
|
|
240
|
+
type: T;
|
|
241
|
+
message: $ElementType<MessageType, T>;
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
export type TypedCall = <T: MessageKey, R: MessageKey>(
|
|
245
|
+
type: T,
|
|
246
|
+
resType: R,
|
|
247
|
+
message?: $ElementType<MessageType, T>
|
|
248
|
+
) => Promise<MessageResponse<R>>;
|
|
249
|
+
`);
|
|
250
|
+
} else {
|
|
251
|
+
lines.push('// custom connect definitions');
|
|
252
|
+
lines.push('export type MessageType = {');
|
|
253
|
+
types
|
|
254
|
+
.flatMap(t => (t && t.type === 'message' ? [t] : []))
|
|
255
|
+
.forEach(t => {
|
|
256
|
+
lines.push(` ${t.name}: ${t.name};`);
|
|
257
|
+
});
|
|
258
|
+
lines.push('};');
|
|
259
|
+
|
|
260
|
+
// additional types utilities
|
|
261
|
+
lines.push(`
|
|
262
|
+
export type MessageKey = keyof MessageType;
|
|
263
|
+
|
|
264
|
+
export type MessageResponse<T extends MessageKey> = {
|
|
265
|
+
type: T;
|
|
266
|
+
message: MessageType[T];
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
export type TypedCall = <T extends MessageKey, R extends MessageKey>(
|
|
270
|
+
type: T,
|
|
271
|
+
resType: R,
|
|
272
|
+
message?: MessageType[T],
|
|
273
|
+
) => Promise<MessageResponse<R>>;
|
|
274
|
+
`);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// save to file
|
|
278
|
+
const filePath = isTypescript
|
|
279
|
+
? path.join(__dirname, '../src/types/messages.ts')
|
|
280
|
+
: path.join(__dirname, '../protobuf.js');
|
|
281
|
+
fs.writeFile(filePath, lines.join('\n'), err => {
|
|
282
|
+
if (err) return console.log(err);
|
|
283
|
+
});
|
package/src/constants.ts
ADDED
package/src/index.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import * as protobuf from 'protobufjs/light';
|
|
2
|
+
import * as Long from 'long';
|
|
3
|
+
import {
|
|
4
|
+
buildBuffers,
|
|
5
|
+
buildEncodeBuffers,
|
|
6
|
+
buildOne,
|
|
7
|
+
decodeProtocol,
|
|
8
|
+
parseConfigure,
|
|
9
|
+
receiveOne,
|
|
10
|
+
} from './serialization';
|
|
11
|
+
import * as check from './utils/highlevel-checks';
|
|
12
|
+
|
|
13
|
+
protobuf.util.Long = Long;
|
|
14
|
+
protobuf.configure();
|
|
15
|
+
|
|
16
|
+
export type {
|
|
17
|
+
Transport,
|
|
18
|
+
AcquireInput,
|
|
19
|
+
UKeyDeviceInfo,
|
|
20
|
+
UKeyMobileDeviceInfo,
|
|
21
|
+
UKeyDeviceInfoWithSession,
|
|
22
|
+
MessageFromUKey,
|
|
23
|
+
LowlevelTransportSharedPlugin,
|
|
24
|
+
LowLevelDevice,
|
|
25
|
+
} from './types';
|
|
26
|
+
|
|
27
|
+
export { Messages } from './types';
|
|
28
|
+
export * from './types/messages';
|
|
29
|
+
export * from './utils/logBlockCommand';
|
|
30
|
+
|
|
31
|
+
export * from './constants';
|
|
32
|
+
|
|
33
|
+
export default {
|
|
34
|
+
check,
|
|
35
|
+
buildOne,
|
|
36
|
+
buildBuffers,
|
|
37
|
+
buildEncodeBuffers,
|
|
38
|
+
receiveOne,
|
|
39
|
+
parseConfigure,
|
|
40
|
+
decodeProtocol,
|
|
41
|
+
};
|