Skip to content

Commit ed91155

Browse files
fix(hardware-ledger): transaction outputs format are now computed independently
1 parent 1723cb0 commit ed91155

File tree

8 files changed

+73
-43
lines changed

8 files changed

+73
-43
lines changed

packages/hardware-ledger/src/LedgerKeyAgent.ts

+11-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/* eslint-disable @typescript-eslint/no-explicit-any */
22
import * as Crypto from '@cardano-sdk/crypto';
3+
import * as Ledger from '@cardano-foundation/ledgerjs-hw-app-cardano';
34
import {
45
AlgorithmId,
56
CBORValue,
@@ -720,13 +721,21 @@ export class LedgerKeyAgent extends KeyAgentBase {
720721
const dRepPublicKey = await this.derivePublicKey(util.DREP_KEY_DERIVATION_PATH);
721722
const dRepKeyHashHex = (await Crypto.Ed25519PublicKey.fromHex(dRepPublicKey).hash()).hex();
722723

724+
const outputsFormat = txBody
725+
.outputs()
726+
.map((out) => (out.isBabbageOutput() ? Ledger.TxOutputFormat.MAP_BABBAGE : Ledger.TxOutputFormat.ARRAY_LEGACY));
727+
const collateralReturnFormat = txBody.collateralReturn()?.isBabbageOutput()
728+
? Ledger.TxOutputFormat.MAP_BABBAGE
729+
: Ledger.TxOutputFormat.ARRAY_LEGACY;
730+
723731
const ledgerTxData = await toLedgerTx(body, {
724732
accountIndex: this.accountIndex,
725733
chainId: this.chainId,
734+
collateralReturnFormat,
726735
dRepKeyHashHex,
727736
knownAddresses,
728-
txInKeyPathMap,
729-
useBabbageOutputs: txBody.hasBabbageOutput()
737+
outputsFormat,
738+
txInKeyPathMap
730739
});
731740

732741
const deviceConnection = await LedgerKeyAgent.checkDeviceConnection(

packages/hardware-ledger/src/transformers/collateralOutput.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@ import { LedgerTxTransformerContext } from '../types';
33
import { toTxOut } from './txOut';
44

55
export const mapCollateralTxOut = (collateralTxOut: Cardano.TxOut | undefined, context: LedgerTxTransformerContext) =>
6-
collateralTxOut ? toTxOut(collateralTxOut, context) : null;
6+
collateralTxOut ? toTxOut({ index: 0, isCollateral: true, txOut: collateralTxOut }, context) : null;

packages/hardware-ledger/src/transformers/txOut.ts

+24-18
Original file line numberDiff line numberDiff line change
@@ -56,27 +56,33 @@ const getScriptHex = (output: Serialization.TransactionOutput): HexBlob | null =
5656
return scriptRef.toCbor();
5757
};
5858

59-
export const toTxOut: Transform<Cardano.TxOut, Ledger.TxOutput, LedgerTxTransformerContext> = (txOut, context) => {
59+
export const toTxOut: Transform<
60+
{ txOut: Cardano.TxOut; index: number; isCollateral: boolean },
61+
Ledger.TxOutput,
62+
LedgerTxTransformerContext
63+
> = (elem, context) => {
64+
const { txOut, index, isCollateral } = elem;
6065
const output = Serialization.TransactionOutput.fromCore(txOut);
6166
const scriptHex = getScriptHex(output);
67+
const format = isCollateral ? context?.collateralReturnFormat : context?.outputsFormat[index];
68+
const isBabbageFormat = format === Ledger.TxOutputFormat.MAP_BABBAGE;
6269

63-
return context?.useBabbageOutputs
64-
? {
65-
amount: txOut.value.coins,
66-
datum: txOut.datumHash ? toDatumHash(txOut.datumHash) : txOut.datum ? toInlineDatum(txOut.datum) : null,
67-
destination: toDestination(txOut, context),
68-
format: Ledger.TxOutputFormat.MAP_BABBAGE,
69-
referenceScriptHex: scriptHex,
70-
tokenBundle: mapTokenMap(txOut.value.assets)
71-
}
72-
: {
73-
amount: txOut.value.coins,
74-
datumHashHex: txOut.datumHash ? txOut.datumHash : null,
75-
destination: toDestination(txOut, context),
76-
format: Ledger.TxOutputFormat.ARRAY_LEGACY,
77-
tokenBundle: mapTokenMap(txOut.value.assets)
78-
};
70+
return {
71+
amount: txOut.value.coins,
72+
destination: toDestination(txOut, context),
73+
tokenBundle: mapTokenMap(txOut.value.assets),
74+
...(isBabbageFormat
75+
? {
76+
datum: txOut.datumHash ? toDatumHash(txOut.datumHash) : txOut.datum ? toInlineDatum(txOut.datum) : null,
77+
format: Ledger.TxOutputFormat.MAP_BABBAGE,
78+
referenceScriptHex: scriptHex
79+
}
80+
: {
81+
datumHashHex: txOut.datumHash ?? null,
82+
format: Ledger.TxOutputFormat.ARRAY_LEGACY
83+
})
84+
};
7985
};
8086

8187
export const mapTxOuts = (txOuts: Cardano.TxOut[], context: LedgerTxTransformerContext): Ledger.TxOutput[] =>
82-
txOuts.map((txOut) => toTxOut(txOut, context));
88+
txOuts.map((txOut, index) => toTxOut({ index, isCollateral: false, txOut }, context));

packages/hardware-ledger/src/types.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Cardano } from '@cardano-sdk/core';
22
import { HID } from 'node-hid';
33
import { SignTransactionContext } from '@cardano-sdk/key-management';
4+
import { TxOutputFormat } from '@cardano-foundation/ledgerjs-hw-app-cardano';
45
import TransportNodeHid from '@ledgerhq/hw-transport-node-hid-noevents';
56
import TransportWebUSB from '@ledgerhq/hw-transport-webusb';
67

@@ -21,6 +22,8 @@ export type LedgerTxTransformerContext = {
2122
chainId: Cardano.ChainId;
2223
/** Non-hardened account in cip1852 */
2324
accountIndex: number;
24-
/** Whether to use Babbage output format or not. */
25-
useBabbageOutputs: boolean;
25+
/** The outputs format in the same order as they appear in the transaction. */
26+
outputsFormat: Array<TxOutputFormat>;
27+
/** The collateral return output format. */
28+
collateralReturnFormat: TxOutputFormat | undefined;
2629
} & SignTransactionContext;

packages/hardware-ledger/test/testData.ts

+7-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as Crypto from '@cardano-sdk/crypto';
2+
import * as Ledger from '@cardano-foundation/ledgerjs-hw-app-cardano';
23
import { AddressType, KeyRole } from '@cardano-sdk/key-management';
34
import { Base64Blob, HexBlob } from '@cardano-sdk/util';
45
import { Cardano, Serialization } from '@cardano-sdk/core';
@@ -342,6 +343,7 @@ export const CONTEXT_WITH_KNOWN_ADDRESSES: LedgerTxTransformerContext = {
342343
networkId: Cardano.NetworkId.Testnet,
343344
networkMagic: 999
344345
},
346+
collateralReturnFormat: Ledger.TxOutputFormat.MAP_BABBAGE,
345347
dRepKeyHashHex: Crypto.Ed25519KeyHashHex(dRepCredential.hash),
346348
knownAddresses: [
347349
{
@@ -357,8 +359,8 @@ export const CONTEXT_WITH_KNOWN_ADDRESSES: LedgerTxTransformerContext = {
357359
type: AddressType.Internal
358360
}
359361
],
360-
txInKeyPathMap: {},
361-
useBabbageOutputs: true
362+
outputsFormat: [Ledger.TxOutputFormat.ARRAY_LEGACY, Ledger.TxOutputFormat.MAP_BABBAGE],
363+
txInKeyPathMap: {}
362364
};
363365

364366
export const CONTEXT_WITHOUT_KNOWN_ADDRESSES: LedgerTxTransformerContext = {
@@ -367,9 +369,10 @@ export const CONTEXT_WITHOUT_KNOWN_ADDRESSES: LedgerTxTransformerContext = {
367369
networkId: Cardano.NetworkId.Testnet,
368370
networkMagic: 999
369371
},
372+
collateralReturnFormat: Ledger.TxOutputFormat.ARRAY_LEGACY,
370373
knownAddresses: [],
371-
txInKeyPathMap: {},
372-
useBabbageOutputs: true
374+
outputsFormat: [Ledger.TxOutputFormat.ARRAY_LEGACY, Ledger.TxOutputFormat.MAP_BABBAGE],
375+
txInKeyPathMap: {}
373376
};
374377

375378
export const votes = [

packages/hardware-ledger/test/transformers/certificates.test.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -73,20 +73,21 @@ export const createTxInKeyPathMapMock = (knownAddresses: GroupedAddress[]): TxIn
7373
const mockContext: LedgerTxTransformerContext = {
7474
accountIndex: 0,
7575
chainId: createChainId(1, 764_824_073),
76+
collateralReturnFormat: Ledger.TxOutputFormat.ARRAY_LEGACY,
77+
7678
dRepKeyHashHex: undefined,
7779

7880
handleResolutions: [],
79-
8081
knownAddresses: [
8182
createGroupedAddress(address1, ownRewardAccount, AddressType.External, 0, stakeKeyPath),
8283
createGroupedAddress(address2, ownRewardAccount, AddressType.External, 1, stakeKeyPath)
8384
],
85+
outputsFormat: [Ledger.TxOutputFormat.ARRAY_LEGACY, Ledger.TxOutputFormat.MAP_BABBAGE],
8486
sender: undefined,
8587
txInKeyPathMap: createTxInKeyPathMapMock([
8688
createGroupedAddress(address1, ownRewardAccount, AddressType.External, 0, stakeKeyPath),
8789
createGroupedAddress(address2, ownRewardAccount, AddressType.External, 1, stakeKeyPath)
88-
]),
89-
useBabbageOutputs: true
90+
])
9091
};
9192

9293
const EXAMPLE_URL = 'https://example.com';

packages/hardware-ledger/test/transformers/tx.test.ts

+3-8
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@ describe('tx', () => {
1515
txInKeyPathMap: {
1616
[TxInId(tx.body.inputs[0])]: paymentKeyPath,
1717
[TxInId(tx.body.collaterals![0])]: paymentKeyPath
18-
},
19-
useBabbageOutputs: false
18+
}
2019
})
2120
).toEqual({
2221
auxiliaryData: {
@@ -181,6 +180,7 @@ describe('tx', () => {
181180
expect(
182181
await toLedgerTx(babbageTxWithoutScript.body, {
183182
...CONTEXT_WITH_KNOWN_ADDRESSES,
183+
outputsFormat: [Ledger.TxOutputFormat.MAP_BABBAGE],
184184
txInKeyPathMap: {
185185
[TxInId(babbageTxWithoutScript.body.inputs[0])]: paymentKeyPath
186186
}
@@ -266,12 +266,7 @@ describe('tx', () => {
266266
]
267267
};
268268

269-
expect(
270-
await toLedgerTx(txBodyWithRegistrationCert, {
271-
...CONTEXT_WITH_KNOWN_ADDRESSES,
272-
useBabbageOutputs: false
273-
})
274-
).toEqual({
269+
expect(await toLedgerTx(txBodyWithRegistrationCert, CONTEXT_WITH_KNOWN_ADDRESSES)).toEqual({
275270
auxiliaryData: {
276271
params: {
277272
hashHex: '2ceb364d93225b4a0f004a0975a13eb50c3cc6348474b4fe9121f8dc72ca0cfa'

packages/hardware-ledger/test/transformers/txOut.test.ts

+18-5
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,14 @@ describe('txOut', () => {
1818
txOutWithReferenceScriptWithInlineDatum,
1919
txOutWithReferenceScriptWithInlineDatum
2020
],
21-
CONTEXT_WITH_KNOWN_ADDRESSES
21+
{
22+
...CONTEXT_WITH_KNOWN_ADDRESSES,
23+
outputsFormat: [
24+
Ledger.TxOutputFormat.MAP_BABBAGE,
25+
Ledger.TxOutputFormat.MAP_BABBAGE,
26+
Ledger.TxOutputFormat.MAP_BABBAGE
27+
]
28+
}
2229
);
2330

2431
expect(txOuts.length).toEqual(3);
@@ -64,7 +71,7 @@ describe('txOut', () => {
6471

6572
describe('toTxOut', () => {
6673
it('can map a simple txOut to third party address', async () => {
67-
const out = toTxOut(txOut, { ...CONTEXT_WITH_KNOWN_ADDRESSES, useBabbageOutputs: false });
74+
const out = toTxOut({ index: 0, isCollateral: false, txOut }, CONTEXT_WITH_KNOWN_ADDRESSES);
6875

6976
expect(out).toEqual({
7077
amount: 10n,
@@ -114,7 +121,7 @@ describe('txOut', () => {
114121
});
115122

116123
it('can map a simple txOut to owned address', async () => {
117-
const out = toTxOut(txOutToOwnedAddress, { ...CONTEXT_WITH_KNOWN_ADDRESSES, useBabbageOutputs: false });
124+
const out = toTxOut({ index: 0, isCollateral: false, txOut: txOutToOwnedAddress }, CONTEXT_WITH_KNOWN_ADDRESSES);
118125

119126
expect(out).toEqual({
120127
amount: 10n,
@@ -179,7 +186,10 @@ describe('txOut', () => {
179186
});
180187

181188
it('can map a txOut with a reference script - datum hash', async () => {
182-
const out = toTxOut(txOutWithReferenceScript, CONTEXT_WITH_KNOWN_ADDRESSES);
189+
const out = toTxOut(
190+
{ index: 1, isCollateral: false, txOut: txOutWithReferenceScript },
191+
CONTEXT_WITH_KNOWN_ADDRESSES
192+
);
183193

184194
expect(out).toEqual({
185195
amount: 10n,
@@ -216,7 +226,10 @@ describe('txOut', () => {
216226
});
217227

218228
it('can map a txOut with a reference script - inline datum', async () => {
219-
const out = toTxOut(txOutWithReferenceScriptWithInlineDatum, CONTEXT_WITH_KNOWN_ADDRESSES);
229+
const out = toTxOut(
230+
{ index: 1, isCollateral: false, txOut: txOutWithReferenceScriptWithInlineDatum },
231+
CONTEXT_WITH_KNOWN_ADDRESSES
232+
);
220233

221234
expect(out).toEqual({
222235
amount: 10n,

0 commit comments

Comments
 (0)