@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.
- package/dist/api/BaseMethod.d.ts.map +1 -1
- package/dist/api/cardano/CardanoGetAddress.d.ts +8 -0
- package/dist/api/cardano/CardanoGetAddress.d.ts.map +1 -0
- package/dist/api/cardano/CardanoGetPublicKey.d.ts +8 -0
- package/dist/api/cardano/CardanoGetPublicKey.d.ts.map +1 -0
- package/dist/api/cardano/CardanoSignTransaction.d.ts +9 -0
- package/dist/api/cardano/CardanoSignTransaction.d.ts.map +1 -0
- package/dist/api/cardano/helper/addressParameters.d.ts +7 -0
- package/dist/api/cardano/helper/addressParameters.d.ts.map +1 -0
- package/dist/api/cardano/helper/auxiliaryData.d.ts +5 -0
- package/dist/api/cardano/helper/auxiliaryData.d.ts.map +1 -0
- package/dist/api/cardano/helper/cardanoInputs.d.ts +14 -0
- package/dist/api/cardano/helper/cardanoInputs.d.ts.map +1 -0
- package/dist/api/cardano/helper/cardanoOutputs.d.ts +11 -0
- package/dist/api/cardano/helper/cardanoOutputs.d.ts.map +1 -0
- package/dist/api/cardano/helper/certificate.d.ts +9 -0
- package/dist/api/cardano/helper/certificate.d.ts.map +1 -0
- package/dist/api/cardano/helper/token.d.ts +3 -0
- package/dist/api/cardano/helper/token.d.ts.map +1 -0
- package/dist/api/cardano/helper/utils.d.ts +3 -0
- package/dist/api/cardano/helper/utils.d.ts.map +1 -0
- package/dist/api/cardano/helper/witnesses.d.ts +5 -0
- package/dist/api/cardano/helper/witnesses.d.ts.map +1 -0
- package/dist/api/firmware/uploadFirmware.d.ts.map +1 -1
- package/dist/api/helpers/paramsValidator.d.ts +2 -1
- package/dist/api/helpers/paramsValidator.d.ts.map +1 -1
- package/dist/api/index.d.ts +6 -0
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/sui/SuiGetAddress.d.ts +18 -0
- package/dist/api/sui/SuiGetAddress.d.ts.map +1 -0
- package/dist/api/sui/SuiGetPublicKey.d.ts +21 -0
- package/dist/api/sui/SuiGetPublicKey.d.ts.map +1 -0
- package/dist/api/sui/SuiSignTransaction.d.ts +15 -0
- package/dist/api/sui/SuiSignTransaction.d.ts.map +1 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/device/Device.d.ts +1 -0
- package/dist/device/Device.d.ts.map +1 -1
- package/dist/index.d.ts +233 -3
- package/dist/index.js +1203 -97
- package/dist/inject.d.ts.map +1 -1
- package/dist/types/api/cardano.d.ts +158 -0
- package/dist/types/api/cardano.d.ts.map +1 -0
- package/dist/types/api/cardanoGetAddress.d.ts +33 -0
- package/dist/types/api/cardanoGetAddress.d.ts.map +1 -0
- package/dist/types/api/cardanoGetPublicKey.d.ts +23 -0
- package/dist/types/api/cardanoGetPublicKey.d.ts.map +1 -0
- package/dist/types/api/cardanoSignTransaction.d.ts +4 -0
- package/dist/types/api/cardanoSignTransaction.d.ts.map +1 -0
- package/dist/types/api/export.d.ts +3 -0
- package/dist/types/api/export.d.ts.map +1 -1
- package/dist/types/api/index.d.ts +12 -0
- package/dist/types/api/index.d.ts.map +1 -1
- package/dist/types/api/suiGetAddress.d.ts +15 -0
- package/dist/types/api/suiGetAddress.d.ts.map +1 -0
- package/dist/types/api/suiGetPublicKey.d.ts +14 -0
- package/dist/types/api/suiGetPublicKey.d.ts.map +1 -0
- package/dist/types/api/suiSignTransaction.d.ts +11 -0
- package/dist/types/api/suiSignTransaction.d.ts.map +1 -0
- package/dist/utils/patch.d.ts +1 -1
- package/dist/utils/patch.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/api/BaseMethod.ts +7 -1
- package/src/api/btc/helpers/signtxLegacy.ts +1 -1
- package/src/api/cardano/CardanoGetAddress.ts +87 -0
- package/src/api/cardano/CardanoGetPublicKey.ts +55 -0
- package/src/api/cardano/CardanoSignTransaction.ts +309 -0
- package/src/api/cardano/helper/addressParameters.ts +118 -0
- package/src/api/cardano/helper/auxiliaryData.ts +74 -0
- package/src/api/cardano/helper/cardanoInputs.ts +56 -0
- package/src/api/cardano/helper/cardanoOutputs.ts +89 -0
- package/src/api/cardano/helper/certificate.ts +199 -0
- package/src/api/cardano/helper/token.ts +43 -0
- package/src/api/cardano/helper/utils.ts +17 -0
- package/src/api/cardano/helper/witnesses.ts +63 -0
- package/src/api/firmware/uploadFirmware.ts +1 -3
- package/src/api/helpers/paramsValidator.ts +19 -1
- package/src/api/index.ts +8 -0
- package/src/api/sui/SuiGetAddress.ts +97 -0
- package/src/api/sui/SuiGetPublicKey.ts +63 -0
- package/src/api/sui/SuiSignTransaction.ts +48 -0
- package/src/core/index.ts +1 -0
- package/src/data/messages/messages.json +217 -69
- package/src/device/Device.ts +5 -0
- package/src/inject.ts +14 -0
- package/src/types/api/cardano.ts +186 -0
- package/src/types/api/cardanoGetAddress.ts +47 -0
- package/src/types/api/cardanoGetPublicKey.ts +33 -0
- package/src/types/api/cardanoSignTransaction.ts +8 -0
- package/src/types/api/export.ts +4 -0
- package/src/types/api/index.ts +22 -0
- package/src/types/api/suiGetAddress.ts +24 -0
- package/src/types/api/suiGetPublicKey.ts +23 -0
- 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
|
|
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
|
+
}
|