@onekeyfe/hd-core 0.2.7 → 0.2.9

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 (93) hide show
  1. package/dist/api/BaseMethod.d.ts.map +1 -1
  2. package/dist/api/cardano/CardanoGetAddress.d.ts +8 -0
  3. package/dist/api/cardano/CardanoGetAddress.d.ts.map +1 -0
  4. package/dist/api/cardano/CardanoGetPublicKey.d.ts +8 -0
  5. package/dist/api/cardano/CardanoGetPublicKey.d.ts.map +1 -0
  6. package/dist/api/cardano/CardanoSignTransaction.d.ts +9 -0
  7. package/dist/api/cardano/CardanoSignTransaction.d.ts.map +1 -0
  8. package/dist/api/cardano/helper/addressParameters.d.ts +7 -0
  9. package/dist/api/cardano/helper/addressParameters.d.ts.map +1 -0
  10. package/dist/api/cardano/helper/auxiliaryData.d.ts +5 -0
  11. package/dist/api/cardano/helper/auxiliaryData.d.ts.map +1 -0
  12. package/dist/api/cardano/helper/cardanoInputs.d.ts +14 -0
  13. package/dist/api/cardano/helper/cardanoInputs.d.ts.map +1 -0
  14. package/dist/api/cardano/helper/cardanoOutputs.d.ts +11 -0
  15. package/dist/api/cardano/helper/cardanoOutputs.d.ts.map +1 -0
  16. package/dist/api/cardano/helper/certificate.d.ts +9 -0
  17. package/dist/api/cardano/helper/certificate.d.ts.map +1 -0
  18. package/dist/api/cardano/helper/token.d.ts +3 -0
  19. package/dist/api/cardano/helper/token.d.ts.map +1 -0
  20. package/dist/api/cardano/helper/utils.d.ts +3 -0
  21. package/dist/api/cardano/helper/utils.d.ts.map +1 -0
  22. package/dist/api/cardano/helper/witnesses.d.ts +5 -0
  23. package/dist/api/cardano/helper/witnesses.d.ts.map +1 -0
  24. package/dist/api/firmware/uploadFirmware.d.ts.map +1 -1
  25. package/dist/api/helpers/paramsValidator.d.ts +2 -1
  26. package/dist/api/helpers/paramsValidator.d.ts.map +1 -1
  27. package/dist/api/index.d.ts +6 -0
  28. package/dist/api/index.d.ts.map +1 -1
  29. package/dist/api/sui/SuiGetAddress.d.ts +18 -0
  30. package/dist/api/sui/SuiGetAddress.d.ts.map +1 -0
  31. package/dist/api/sui/SuiGetPublicKey.d.ts +21 -0
  32. package/dist/api/sui/SuiGetPublicKey.d.ts.map +1 -0
  33. package/dist/api/sui/SuiSignTransaction.d.ts +15 -0
  34. package/dist/api/sui/SuiSignTransaction.d.ts.map +1 -0
  35. package/dist/core/index.d.ts.map +1 -1
  36. package/dist/device/Device.d.ts +1 -0
  37. package/dist/device/Device.d.ts.map +1 -1
  38. package/dist/index.d.ts +233 -3
  39. package/dist/index.js +1203 -97
  40. package/dist/inject.d.ts.map +1 -1
  41. package/dist/types/api/cardano.d.ts +158 -0
  42. package/dist/types/api/cardano.d.ts.map +1 -0
  43. package/dist/types/api/cardanoGetAddress.d.ts +33 -0
  44. package/dist/types/api/cardanoGetAddress.d.ts.map +1 -0
  45. package/dist/types/api/cardanoGetPublicKey.d.ts +23 -0
  46. package/dist/types/api/cardanoGetPublicKey.d.ts.map +1 -0
  47. package/dist/types/api/cardanoSignTransaction.d.ts +4 -0
  48. package/dist/types/api/cardanoSignTransaction.d.ts.map +1 -0
  49. package/dist/types/api/export.d.ts +3 -0
  50. package/dist/types/api/export.d.ts.map +1 -1
  51. package/dist/types/api/index.d.ts +12 -0
  52. package/dist/types/api/index.d.ts.map +1 -1
  53. package/dist/types/api/suiGetAddress.d.ts +15 -0
  54. package/dist/types/api/suiGetAddress.d.ts.map +1 -0
  55. package/dist/types/api/suiGetPublicKey.d.ts +14 -0
  56. package/dist/types/api/suiGetPublicKey.d.ts.map +1 -0
  57. package/dist/types/api/suiSignTransaction.d.ts +11 -0
  58. package/dist/types/api/suiSignTransaction.d.ts.map +1 -0
  59. package/dist/utils/patch.d.ts +1 -1
  60. package/dist/utils/patch.d.ts.map +1 -1
  61. package/package.json +4 -4
  62. package/src/api/BaseMethod.ts +7 -1
  63. package/src/api/btc/helpers/signtxLegacy.ts +1 -1
  64. package/src/api/cardano/CardanoGetAddress.ts +87 -0
  65. package/src/api/cardano/CardanoGetPublicKey.ts +55 -0
  66. package/src/api/cardano/CardanoSignTransaction.ts +309 -0
  67. package/src/api/cardano/helper/addressParameters.ts +118 -0
  68. package/src/api/cardano/helper/auxiliaryData.ts +74 -0
  69. package/src/api/cardano/helper/cardanoInputs.ts +56 -0
  70. package/src/api/cardano/helper/cardanoOutputs.ts +89 -0
  71. package/src/api/cardano/helper/certificate.ts +199 -0
  72. package/src/api/cardano/helper/token.ts +43 -0
  73. package/src/api/cardano/helper/utils.ts +17 -0
  74. package/src/api/cardano/helper/witnesses.ts +63 -0
  75. package/src/api/firmware/uploadFirmware.ts +1 -3
  76. package/src/api/helpers/paramsValidator.ts +19 -1
  77. package/src/api/index.ts +8 -0
  78. package/src/api/sui/SuiGetAddress.ts +97 -0
  79. package/src/api/sui/SuiGetPublicKey.ts +63 -0
  80. package/src/api/sui/SuiSignTransaction.ts +48 -0
  81. package/src/core/index.ts +1 -0
  82. package/src/data/messages/messages.json +217 -69
  83. package/src/device/Device.ts +5 -0
  84. package/src/inject.ts +14 -0
  85. package/src/types/api/cardano.ts +186 -0
  86. package/src/types/api/cardanoGetAddress.ts +47 -0
  87. package/src/types/api/cardanoGetPublicKey.ts +33 -0
  88. package/src/types/api/cardanoSignTransaction.ts +8 -0
  89. package/src/types/api/export.ts +4 -0
  90. package/src/types/api/index.ts +22 -0
  91. package/src/types/api/suiGetAddress.ts +24 -0
  92. package/src/types/api/suiGetPublicKey.ts +23 -0
  93. package/src/types/api/suiSignTransaction.ts +17 -0
@@ -0,0 +1,56 @@
1
+ import { validateParams } from '../../helpers/paramsValidator';
2
+ import { validatePath } from '../../helpers/pathUtils';
3
+ import type { PROTO } from '../../../constants';
4
+
5
+ export type Path = number[];
6
+
7
+ export type InputWithPath = {
8
+ input: PROTO.CardanoTxInput;
9
+ path?: Path;
10
+ };
11
+
12
+ export type CollateralInputWithPath = {
13
+ // @ts-expect-error
14
+ collateralInput: PROTO.CardanoTxCollateralInput;
15
+ path?: Path;
16
+ };
17
+
18
+ export const transformInput = (input: any): InputWithPath => {
19
+ validateParams(input, [
20
+ { name: 'prev_hash', type: 'string', required: true },
21
+ { name: 'prev_index', type: 'number', required: true },
22
+ ]);
23
+ return {
24
+ input: {
25
+ prev_hash: input.prev_hash,
26
+ prev_index: input.prev_index,
27
+ },
28
+ path: input.path ? validatePath(input.path, 5) : undefined,
29
+ };
30
+ };
31
+
32
+ export const transformCollateralInput = (collateralInput: any): CollateralInputWithPath => {
33
+ validateParams(collateralInput, [
34
+ { name: 'prev_hash', type: 'string', required: true },
35
+ { name: 'prev_index', type: 'number', required: true },
36
+ ]);
37
+ return {
38
+ collateralInput: {
39
+ prev_hash: collateralInput.prev_hash,
40
+ prev_index: collateralInput.prev_index,
41
+ },
42
+ path: collateralInput.path ? validatePath(collateralInput.path, 5) : undefined,
43
+ };
44
+ };
45
+
46
+ // @ts-expect-error
47
+ export const transformReferenceInput = (referenceInput: any): PROTO.CardanoTxReferenceInput => {
48
+ validateParams(referenceInput, [
49
+ { name: 'prev_hash', type: 'string', required: true },
50
+ { name: 'prev_index', type: 'number', required: true },
51
+ ]);
52
+ return {
53
+ prev_hash: referenceInput.prev_hash,
54
+ prev_index: referenceInput.prev_index,
55
+ };
56
+ };
@@ -0,0 +1,89 @@
1
+ import { validateParams } from '../../helpers/paramsValidator';
2
+ import { tokenBundleToProto } from './token';
3
+ import { addressParametersToProto, validateAddressParameters } from './addressParameters';
4
+ import { hexStringByteLength, sendChunkedHexString } from './utils';
5
+ import type { PROTO } from '../../../constants';
6
+ import type { AssetGroupWithTokens } from '../../../types/api/cardano';
7
+
8
+ export type OutputWithData = {
9
+ output: PROTO.CardanoTxOutput;
10
+ tokenBundle?: AssetGroupWithTokens[];
11
+ inlineDatum?: string;
12
+ referenceScript?: string;
13
+ };
14
+
15
+ export const transformOutput = (output: any): OutputWithData => {
16
+ validateParams(output, [
17
+ { name: 'address', type: 'string' },
18
+ { name: 'amount', type: 'uint', required: true },
19
+ { name: 'tokenBundle', type: 'array', allowEmpty: true },
20
+ { name: 'datumHash', type: 'string' },
21
+ { name: 'format', type: 'number' },
22
+ { name: 'inlineDatum', type: 'string' },
23
+ { name: 'referenceScript', type: 'string' },
24
+ ]);
25
+
26
+ const result: OutputWithData = {
27
+ output: {
28
+ amount: output.amount,
29
+ asset_groups_count: 0,
30
+ // @ts-expect-error
31
+ datum_hash: output.datumHash,
32
+ format: output.format,
33
+ inline_datum_size: output.inlineDatum ? hexStringByteLength(output.inlineDatum) : undefined,
34
+ reference_script_size: output.referenceScript
35
+ ? hexStringByteLength(output.referenceScript)
36
+ : undefined,
37
+ },
38
+ inlineDatum: output.inlineDatum,
39
+ referenceScript: output.referenceScript,
40
+ };
41
+
42
+ if (output.addressParameters) {
43
+ validateAddressParameters(output.addressParameters);
44
+ result.output.address_parameters = addressParametersToProto(output.addressParameters);
45
+ } else {
46
+ result.output.address = output.address;
47
+ }
48
+
49
+ if (output.tokenBundle) {
50
+ result.tokenBundle = tokenBundleToProto(output.tokenBundle);
51
+ result.output.asset_groups_count = result.tokenBundle.length;
52
+ } else {
53
+ result.output.asset_groups_count = 0;
54
+ }
55
+
56
+ return result;
57
+ };
58
+
59
+ export const sendOutput = async (typedCall: any, outputWithData: OutputWithData) => {
60
+ const MAX_CHUNK_SIZE = 1024 * 2; // 1024 hex-encoded bytes
61
+
62
+ const { output, tokenBundle, inlineDatum, referenceScript } = outputWithData;
63
+
64
+ await typedCall('CardanoTxOutput', 'CardanoTxItemAck', output);
65
+ if (tokenBundle) {
66
+ for (const assetGroup of tokenBundle) {
67
+ await typedCall('CardanoAssetGroup', 'CardanoTxItemAck', {
68
+ policy_id: assetGroup.policyId,
69
+ tokens_count: assetGroup.tokens.length,
70
+ });
71
+ for (const token of assetGroup.tokens) {
72
+ await typedCall('CardanoToken', 'CardanoTxItemAck', token);
73
+ }
74
+ }
75
+ }
76
+
77
+ if (inlineDatum) {
78
+ await sendChunkedHexString(typedCall, inlineDatum, MAX_CHUNK_SIZE, 'CardanoTxInlineDatumChunk');
79
+ }
80
+
81
+ if (referenceScript) {
82
+ await sendChunkedHexString(
83
+ typedCall,
84
+ referenceScript,
85
+ MAX_CHUNK_SIZE,
86
+ 'CardanoTxReferenceScriptChunk'
87
+ );
88
+ }
89
+ };
@@ -0,0 +1,199 @@
1
+ import { ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
2
+ import { validateParams } from '../../helpers/paramsValidator';
3
+ import { validatePath } from '../../helpers/pathUtils';
4
+ import type {
5
+ CardanoCertificate,
6
+ CardanoPoolParameters,
7
+ CertificateWithPoolOwnersAndRelays,
8
+ CardanoPoolMargin,
9
+ CardanoPoolMetadata,
10
+ CardanoPoolRelay,
11
+ CardanoPoolOwner,
12
+ } from '../../../types/api/cardano';
13
+ import { PROTO } from '../../../constants';
14
+
15
+ export type PoolParametersWithOwnersAndRelays = {
16
+ poolParameters?: PROTO.CardanoPoolParametersType;
17
+ poolOwners: PROTO.CardanoPoolOwner[];
18
+ poolRelays: PROTO.CardanoPoolRelayParameters[];
19
+ };
20
+
21
+ const ipv4AddressToHex = (ipv4Address: string) =>
22
+ Buffer.from(ipv4Address.split('.').map(ipPart => parseInt(ipPart, 10))).toString('hex');
23
+
24
+ const ipv6AddressToHex = (ipv6Address: string) => ipv6Address.split(':').join('');
25
+
26
+ const validatePoolMargin = (margin: CardanoPoolMargin) => {
27
+ validateParams(margin, [
28
+ { name: 'numerator', type: 'string', required: true },
29
+ { name: 'denominator', type: 'string', required: true },
30
+ ]);
31
+ };
32
+
33
+ const validatePoolMetadata = (metadata: CardanoPoolMetadata) => {
34
+ validateParams(metadata, [
35
+ { name: 'url', type: 'string', required: true },
36
+ { name: 'hash', type: 'string', required: true },
37
+ ]);
38
+ };
39
+
40
+ const validatePoolRelay = (relay: CardanoPoolRelay) => {
41
+ validateParams(relay, [{ name: 'type', type: 'number', required: true }]);
42
+
43
+ if (relay.type === PROTO.CardanoPoolRelayType.SINGLE_HOST_IP) {
44
+ const paramsToValidate: Parameters<typeof validateParams>[1] = [
45
+ { name: 'port', type: 'number', required: true },
46
+ ];
47
+ if (relay.ipv4Address) {
48
+ paramsToValidate.push({ name: 'ipv4Address', type: 'string', required: false });
49
+ }
50
+ if (relay.ipv6Address) {
51
+ paramsToValidate.push({ name: 'ipv6Address', type: 'string', required: false });
52
+ }
53
+
54
+ validateParams(relay, paramsToValidate);
55
+
56
+ if (!relay.ipv4Address && !relay.ipv6Address) {
57
+ throw ERRORS.TypedError(
58
+ HardwareErrorCode.CallMethodInvalidParameter,
59
+ 'Either ipv4Address or ipv6Address must be supplied'
60
+ );
61
+ }
62
+ } else if (relay.type === PROTO.CardanoPoolRelayType.SINGLE_HOST_NAME) {
63
+ validateParams(relay, [
64
+ { name: 'hostName', type: 'string', required: true },
65
+ { name: 'port', type: 'number', required: true },
66
+ ]);
67
+ } else if (relay.type === PROTO.CardanoPoolRelayType.MULTIPLE_HOST_NAME) {
68
+ validateParams(relay, [{ name: 'hostName', type: 'string', required: true }]);
69
+ }
70
+ };
71
+
72
+ const validatePoolOwners = (owners: CardanoPoolOwner[]) => {
73
+ owners.forEach(owner => {
74
+ if (owner.stakingKeyHash) {
75
+ validateParams(owner, [
76
+ { name: 'stakingKeyHash', type: 'string', required: !owner.stakingKeyPath },
77
+ ]);
78
+ }
79
+
80
+ if (owner.stakingKeyPath) {
81
+ validatePath(owner.stakingKeyPath, 5);
82
+ }
83
+
84
+ if (!owner.stakingKeyHash && !owner.stakingKeyPath) {
85
+ throw ERRORS.TypedError(
86
+ HardwareErrorCode.CallMethodInvalidParameter,
87
+ 'Either stakingKeyHash or stakingKeyPath must be supplied'
88
+ );
89
+ }
90
+ });
91
+
92
+ const ownersAsPathCount = owners.filter(owner => !!owner.stakingKeyPath).length;
93
+ if (ownersAsPathCount !== 1) {
94
+ throw ERRORS.TypedError(
95
+ HardwareErrorCode.CallMethodInvalidParameter,
96
+ 'Exactly one pool owner must be given as a path'
97
+ );
98
+ }
99
+ };
100
+
101
+ const validatePoolParameters = (poolParameters: CardanoPoolParameters) => {
102
+ validateParams(poolParameters, [
103
+ { name: 'poolId', type: 'string', required: true },
104
+ { name: 'vrfKeyHash', type: 'string', required: true },
105
+ { name: 'pledge', type: 'string', required: true },
106
+ { name: 'cost', type: 'string', required: true },
107
+ { name: 'margin', type: 'object', required: true },
108
+ { name: 'rewardAccount', type: 'string', required: true },
109
+ { name: 'owners', type: 'array', required: true },
110
+ { name: 'relays', type: 'array', required: true, allowEmpty: true },
111
+ { name: 'metadata', type: 'object' },
112
+ ]);
113
+
114
+ validatePoolMargin(poolParameters.margin);
115
+ validatePoolOwners(poolParameters.owners);
116
+ poolParameters.relays.forEach(validatePoolRelay);
117
+
118
+ if (poolParameters.metadata) {
119
+ validatePoolMetadata(poolParameters.metadata);
120
+ }
121
+ };
122
+
123
+ const transformPoolParameters = (
124
+ poolParameters?: CardanoPoolParameters
125
+ ): PoolParametersWithOwnersAndRelays => {
126
+ if (!poolParameters) {
127
+ return { poolParameters: undefined, poolOwners: [], poolRelays: [] };
128
+ }
129
+
130
+ validatePoolParameters(poolParameters);
131
+
132
+ return {
133
+ // @ts-expect-error
134
+ poolParameters: {
135
+ pool_id: poolParameters.poolId,
136
+ vrf_key_hash: poolParameters.vrfKeyHash,
137
+ pledge: poolParameters.pledge,
138
+ cost: poolParameters.cost,
139
+ margin_numerator: poolParameters.margin.numerator,
140
+ margin_denominator: poolParameters.margin.denominator,
141
+ reward_account: poolParameters.rewardAccount,
142
+ metadata: poolParameters.metadata,
143
+ owners_count: poolParameters.owners.length,
144
+ relays_count: poolParameters.relays.length,
145
+ },
146
+ poolOwners: poolParameters.owners.map(owner => ({
147
+ staking_key_hash: owner.stakingKeyHash,
148
+ staking_key_path: owner.stakingKeyPath ? validatePath(owner.stakingKeyPath, 5) : undefined,
149
+ })),
150
+ poolRelays: poolParameters.relays.map(relay => ({
151
+ type: relay.type,
152
+ ipv4_address: relay.ipv4Address ? ipv4AddressToHex(relay.ipv4Address) : undefined,
153
+ ipv6_address: relay.ipv6Address ? ipv6AddressToHex(relay.ipv6Address) : undefined,
154
+ host_name: relay.hostName,
155
+ port: relay.port,
156
+ })),
157
+ };
158
+ };
159
+
160
+ export const transformCertificate = (
161
+ certificate: CardanoCertificate
162
+ ): CertificateWithPoolOwnersAndRelays => {
163
+ const paramsToValidate: Parameters<typeof validateParams>[1] = [
164
+ { name: 'type', type: 'number', required: true },
165
+ ];
166
+
167
+ if (certificate.type !== PROTO.CardanoCertificateType.STAKE_POOL_REGISTRATION) {
168
+ paramsToValidate.push({ name: 'scriptHash', type: 'string' });
169
+ paramsToValidate.push({ name: 'keyHash', type: 'string' });
170
+ }
171
+
172
+ if (certificate.type === PROTO.CardanoCertificateType.STAKE_DELEGATION) {
173
+ paramsToValidate.push({ name: 'pool', type: 'string', required: true });
174
+ }
175
+
176
+ if (certificate.type === PROTO.CardanoCertificateType.STAKE_POOL_REGISTRATION) {
177
+ paramsToValidate.push({ name: 'poolParameters', type: 'object', required: true });
178
+ }
179
+
180
+ validateParams(certificate, paramsToValidate);
181
+
182
+ const { poolParameters, poolOwners, poolRelays } = transformPoolParameters(
183
+ certificate.poolParameters
184
+ );
185
+
186
+ return {
187
+ certificate: {
188
+ type: certificate.type,
189
+ path: certificate.path ? validatePath(certificate.path, 5) : undefined,
190
+ script_hash: certificate.scriptHash,
191
+ // @ts-expect-error
192
+ key_hash: certificate.keyHash,
193
+ pool: certificate.pool,
194
+ pool_parameters: poolParameters,
195
+ },
196
+ poolOwners,
197
+ poolRelays,
198
+ };
199
+ };
@@ -0,0 +1,43 @@
1
+ import { validateParams } from '../../helpers/paramsValidator';
2
+ import type {
3
+ CardanoAssetGroup,
4
+ AssetGroupWithTokens,
5
+ CardanoToken,
6
+ } from '../../../types/api/cardano';
7
+ import type { PROTO } from '../../../constants';
8
+
9
+ const validateTokens = (tokenAmounts: CardanoToken[]) => {
10
+ tokenAmounts.forEach(tokenAmount => {
11
+ validateParams(tokenAmount, [
12
+ { name: 'assetNameBytes', type: 'string', required: true },
13
+ { name: 'amount', type: 'uint' },
14
+ { name: 'mintAmount', type: 'uint', allowNegative: true },
15
+ ]);
16
+ });
17
+ };
18
+
19
+ const validateTokenBundle = (tokenBundle: CardanoAssetGroup[]) => {
20
+ tokenBundle.forEach(tokenGroup => {
21
+ validateParams(tokenGroup, [
22
+ { name: 'policyId', type: 'string', required: true },
23
+ { name: 'tokenAmounts', type: 'array', required: true },
24
+ ]);
25
+
26
+ validateTokens(tokenGroup.tokenAmounts);
27
+ });
28
+ };
29
+
30
+ export const tokenBundleToProto = (tokenBundle: CardanoAssetGroup[]): AssetGroupWithTokens[] => {
31
+ validateTokenBundle(tokenBundle);
32
+ return tokenBundle.map(tokenGroup => ({
33
+ policyId: tokenGroup.policyId,
34
+ tokens: tokenAmountsToProto(tokenGroup.tokenAmounts),
35
+ }));
36
+ };
37
+
38
+ const tokenAmountsToProto = (tokenAmounts: CardanoToken[]): PROTO.CardanoToken[] =>
39
+ tokenAmounts.map(tokenAmount => ({
40
+ asset_name_bytes: tokenAmount.assetNameBytes,
41
+ amount: tokenAmount.amount,
42
+ mint_amount: tokenAmount.mintAmount,
43
+ }));
@@ -0,0 +1,17 @@
1
+ export const hexStringByteLength = (s: string) => s.length / 2;
2
+
3
+ export const sendChunkedHexString = async (
4
+ typedCall: any,
5
+ data: string,
6
+ chunkSize: number,
7
+ messageType: string
8
+ ) => {
9
+ let processedSize = 0;
10
+ while (processedSize < data.length) {
11
+ const chunk = data.slice(processedSize, processedSize + chunkSize);
12
+ await typedCall(messageType, 'CardanoTxItemAck', {
13
+ data: chunk,
14
+ });
15
+ processedSize += chunkSize;
16
+ }
17
+ };
@@ -0,0 +1,63 @@
1
+ import type { CertificateWithPoolOwnersAndRelays } from '../../../types/api/cardano';
2
+ import { CollateralInputWithPath, InputWithPath, Path } from './cardanoInputs';
3
+ import { PROTO } from '../../../constants';
4
+
5
+ export const gatherWitnessPaths = (
6
+ inputsWithPath: InputWithPath[],
7
+ certificatesWithPoolOwnersAndRelays: CertificateWithPoolOwnersAndRelays[],
8
+ withdrawals: PROTO.CardanoTxWithdrawal[],
9
+ collateralInputsWithPath: CollateralInputWithPath[],
10
+ // @ts-expect-error
11
+ requiredSigners: PROTO.CardanoTxRequiredSigner[],
12
+ additionalWitnessRequests: Path[],
13
+ signingMode: PROTO.CardanoTxSigningMode
14
+ ): Path[] => {
15
+ const witnessPaths = new Map<string, Path>();
16
+ function _insert(path: Path) {
17
+ const pathKey = JSON.stringify(path);
18
+ witnessPaths.set(pathKey, path);
19
+ }
20
+
21
+ // don't gather paths from tx elements in MULTISIG_TRANSACTION signing mode
22
+ if (signingMode !== PROTO.CardanoTxSigningMode.MULTISIG_TRANSACTION) {
23
+ inputsWithPath.forEach(({ path }) => {
24
+ if (path) _insert(path);
25
+ });
26
+
27
+ certificatesWithPoolOwnersAndRelays.forEach(({ certificate, poolOwners }) => {
28
+ if (
29
+ certificate.path &&
30
+ (certificate.type === PROTO.CardanoCertificateType.STAKE_DELEGATION ||
31
+ certificate.type === PROTO.CardanoCertificateType.STAKE_DEREGISTRATION)
32
+ ) {
33
+ _insert(certificate.path);
34
+ }
35
+ poolOwners.forEach(poolOwner => {
36
+ if (poolOwner.staking_key_path) _insert(poolOwner.staking_key_path);
37
+ });
38
+ });
39
+
40
+ withdrawals.forEach(({ path }) => {
41
+ if (path) _insert(path);
42
+ });
43
+ }
44
+
45
+ // gather Plutus-related paths
46
+ // @ts-expect-error
47
+ if (signingMode === PROTO.CardanoTxSigningMode.PLUTUS_TRANSACTION) {
48
+ collateralInputsWithPath.forEach(({ path }) => {
49
+ if (path) _insert(path);
50
+ });
51
+ }
52
+
53
+ requiredSigners.forEach(({ key_path }) => {
54
+ if (key_path) _insert(key_path);
55
+ });
56
+
57
+ // add additional witness requests in all cases (because of minting)
58
+ additionalWitnessRequests.forEach(path => {
59
+ _insert(path);
60
+ });
61
+
62
+ return Array.from(witnessPaths.values());
63
+ };
@@ -2,7 +2,7 @@ import { blake2s } from '@noble/hashes/blake2s';
2
2
  import JSZip from 'jszip';
3
3
  import { ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
4
4
  import { Success } from '@onekeyfe/hd-transport';
5
- import { wait, getLogger, LoggerNames } from '../../utils/index';
5
+ import { wait } from '../../utils/index';
6
6
  import { DEVICE, CoreMessage, createUiMessage, UI_REQUEST } from '../../events';
7
7
  import { PROTO } from '../../constants';
8
8
  import type { Device } from '../../device/Device';
@@ -10,8 +10,6 @@ import type { TypedCall, TypedResponseMessage } from '../../device/DeviceCommand
10
10
  import { KnownDevice } from '../../types';
11
11
  import { bytesToHex } from '../helpers/hexUtils';
12
12
 
13
- const Log = getLogger(LoggerNames.Device);
14
-
15
13
  const postConfirmationMessage = (device: Device) => {
16
14
  // only if firmware is already installed. fresh device does not require button confirmation
17
15
  if (device.features?.firmware_present) {
@@ -10,12 +10,14 @@ export type SchemaParam = {
10
10
  | 'number'
11
11
  | 'boolean'
12
12
  | 'bigNumber'
13
+ | 'uint'
13
14
  | 'buffer'
14
15
  | 'object'
15
16
  | 'array'
16
17
  | 'hexString';
17
18
  required?: boolean;
18
19
  allowEmpty?: boolean;
20
+ allowNegative?: boolean;
19
21
  };
20
22
 
21
23
  const invalidParameter = (message: string) =>
@@ -42,7 +44,23 @@ export const validateParams = (values: any, fields: Array<SchemaParam>): void =>
42
44
  throw invalidParameter(`Parameter "${field.name}" is empty.`);
43
45
  }
44
46
  break;
45
-
47
+ case 'uint':
48
+ if (typeof value !== 'string' && typeof value !== 'number') {
49
+ throw invalidParameter(
50
+ `Parameter [${field.name}] has invalid type. "string|number" expected.`
51
+ );
52
+ }
53
+ if (
54
+ (typeof value === 'number' && !Number.isSafeInteger(value)) ||
55
+ !/^(?:[1-9]\d*|\d)$/.test(
56
+ value.toString().replace(/^-/, field.allowNegative ? '' : '-')
57
+ )
58
+ ) {
59
+ throw invalidParameter(
60
+ `Parameter [${field.name}] has invalid value "${value}". Integer representation expected.`
61
+ );
62
+ }
63
+ break;
46
64
  case 'bigNumber':
47
65
  if (typeof value !== 'string') {
48
66
  throw invalidParameter(
package/src/api/index.ts CHANGED
@@ -81,3 +81,11 @@ export { default as cosmosSignTransaction } from './cosmos/CosmosSignTransaction
81
81
 
82
82
  export { default as xrpGetAddress } from './xrp/XrpGetAddress';
83
83
  export { default as xrpSignTransaction } from './xrp/XrpSignTransaction';
84
+
85
+ export { default as suiGetAddress } from './sui/SuiGetAddress';
86
+ export { default as suiGetPublicKey } from './sui/SuiGetPublicKey';
87
+ export { default as suiSignTransaction } from './sui/SuiSignTransaction';
88
+
89
+ export { default as cardanoGetAddress } from './cardano/CardanoGetAddress';
90
+ export { default as cardanoGetPublicKey } from './cardano/CardanoGetPublicKey';
91
+ export { default as cardanoSignTransaction } from './cardano/CardanoSignTransaction';
@@ -0,0 +1,97 @@
1
+ import { SuiGetAddress as HardwareSuiGetAddress } from '@onekeyfe/hd-transport';
2
+
3
+ import { sha3_256 } from '@noble/hashes/sha3';
4
+ import { bytesToHex } from '@noble/hashes/utils';
5
+ import { UI_REQUEST } from '../../constants/ui-request';
6
+ import { serializedPath, validatePath } from '../helpers/pathUtils';
7
+ import { BaseMethod } from '../BaseMethod';
8
+ import { validateParams } from '../helpers/paramsValidator';
9
+ import { SuiAddress, SuiGetAddressParams } from '../../types';
10
+ import { supportBatchPublicKey } from '../../utils/deviceFeaturesUtils';
11
+ import { hexToBytes } from '../helpers/hexUtils';
12
+
13
+ export default class SuiGetAddress extends BaseMethod<HardwareSuiGetAddress[]> {
14
+ hasBundle = false;
15
+
16
+ init() {
17
+ this.checkDeviceId = true;
18
+ this.allowDeviceMode = [...this.allowDeviceMode, UI_REQUEST.INITIALIZE];
19
+
20
+ this.hasBundle = !!this.payload?.bundle;
21
+ const payload = this.hasBundle ? this.payload : { bundle: [this.payload] };
22
+
23
+ // check payload
24
+ validateParams(payload, [{ name: 'bundle', type: 'array' }]);
25
+
26
+ // init params
27
+ this.params = [];
28
+ payload.bundle.forEach((batch: SuiGetAddressParams) => {
29
+ const addressN = validatePath(batch.path, 3);
30
+
31
+ validateParams(batch, [
32
+ { name: 'path', required: true },
33
+ { name: 'showOnOneKey', type: 'boolean' },
34
+ ]);
35
+
36
+ const showOnOneKey = batch.showOnOneKey ?? true;
37
+
38
+ this.params.push({
39
+ address_n: addressN,
40
+ show_display: showOnOneKey,
41
+ });
42
+ });
43
+ }
44
+
45
+ publicKeyToAddress(publicKey: string) {
46
+ const hash = sha3_256.create();
47
+ // Ed25519
48
+ hash.update('\x00');
49
+ // hash.update('\x01'); Secp256k1
50
+ hash.update(hexToBytes(publicKey));
51
+ return `0x${bytesToHex(hash.digest().slice(0, 20))}`;
52
+ }
53
+
54
+ getVersionRange() {
55
+ return {
56
+ model_mini: {
57
+ min: '2.9.0',
58
+ },
59
+ model_touch: {
60
+ min: '3.5.0',
61
+ },
62
+ };
63
+ }
64
+
65
+ async run() {
66
+ if (this.hasBundle && supportBatchPublicKey(this.device?.features)) {
67
+ const res = await this.device.commands.typedCall('BatchGetPublickeys', 'EcdsaPublicKeys', {
68
+ paths: this.params,
69
+ ecdsa_curve_name: 'ed25519',
70
+ });
71
+ const result = res.message.public_keys.map((publicKey: string, index: number) => ({
72
+ path: serializedPath((this.params as unknown as any[])[index].address_n),
73
+ publicKey,
74
+ address: this.publicKeyToAddress(publicKey),
75
+ }));
76
+ return Promise.resolve(result);
77
+ }
78
+
79
+ const responses: SuiAddress[] = [];
80
+ for (let i = 0; i < this.params.length; i++) {
81
+ const param = this.params[i];
82
+
83
+ const res = await this.device.commands.typedCall('SuiGetAddress', 'SuiAddress', {
84
+ ...param,
85
+ });
86
+
87
+ const { address } = res.message;
88
+
89
+ responses.push({
90
+ path: serializedPath(param.address_n),
91
+ address: address?.toLowerCase(),
92
+ });
93
+ }
94
+
95
+ return Promise.resolve(this.hasBundle ? responses : responses[0]);
96
+ }
97
+ }