Skip to content

Commit ed57710

Browse files
committed
feat: cip30 signTx should send CBOR in sign transactionWitnesserReq
Instead of the only the transaction body. The witnesser request was missing the auxiliaryData and witness fields. Plus, it's more reliable to use the CBOR instead of reconstructing it.
1 parent 3879bf1 commit ed57710

File tree

4 files changed

+30
-19
lines changed

4 files changed

+30
-19
lines changed

packages/core/src/Cardano/types/Transaction.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { PlutusData } from './PlutusData';
1111
import { ProposalProcedure, VotingProcedures } from './Governance';
1212
import { RewardAccount } from '../Address';
1313
import { Script } from './Script';
14+
import { Serialization } from '../..';
1415

1516
/** transaction hash as hex string */
1617
export type TransactionId = OpaqueString<'TransactionId'>;
@@ -164,3 +165,6 @@ export type TxBodyWithHash = {
164165
hash: TransactionId;
165166
body: TxBody;
166167
};
168+
169+
export const isTxBodyWithHash = (tx: Serialization.TxCBOR | TxBodyWithHash): tx is TxBodyWithHash =>
170+
typeof tx === 'object' && 'hash' in tx && 'body' in tx;

packages/wallet/src/Wallets/BaseWallet.ts

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -619,26 +619,29 @@ export class BaseWallet implements ObservableWallet {
619619
}: FinalizeTxProps): Promise<Cardano.Tx> {
620620
const knownAddresses = await firstValueFrom(this.addresses$);
621621
const dRepPublicKey = await this.governance.getPubDRepKey();
622+
const emptyWitness = { signatures: new Map() };
623+
624+
let transaction: Serialization.Transaction;
625+
if (Cardano.isTxBodyWithHash(tx)) {
626+
// Reconstruct transaction from parts
627+
transaction = new Serialization.Transaction(
628+
bodyCbor ? Serialization.TransactionBody.fromCbor(bodyCbor) : Serialization.TransactionBody.fromCore(tx.body),
629+
Serialization.TransactionWitnessSet.fromCore({ ...emptyWitness, ...witness }),
630+
auxiliaryData ? Serialization.AuxiliaryData.fromCore(auxiliaryData) : undefined
631+
);
632+
if (isValid !== undefined) transaction.setIsValid(isValid);
633+
} else {
634+
// Transaction CBOR is available. Use as is.
635+
transaction = Serialization.Transaction.fromCbor(tx);
636+
}
622637

623638
const context = {
624639
...signingContext,
625640
dRepPublicKey,
626641
knownAddresses,
627-
txInKeyPathMap: await util.createTxInKeyPathMap(tx.body, knownAddresses, this.util)
642+
txInKeyPathMap: await util.createTxInKeyPathMap(transaction.body().toCore(), knownAddresses, this.util)
628643
};
629644

630-
const emptyWitness = { signatures: new Map() };
631-
632-
// The Witnesser takes a serializable transaction. We cant build that from the hash alone, if
633-
// the bodyCbor is available, use that instead of the coreTx type to build the transaction.
634-
const transaction = new Serialization.Transaction(
635-
bodyCbor ? Serialization.TransactionBody.fromCbor(bodyCbor) : Serialization.TransactionBody.fromCore(tx.body),
636-
Serialization.TransactionWitnessSet.fromCore({ ...emptyWitness, ...witness }),
637-
auxiliaryData ? Serialization.AuxiliaryData.fromCore(auxiliaryData) : undefined
638-
);
639-
640-
if (isValid !== undefined) transaction.setIsValid(isValid);
641-
642645
const result = await this.witnesser.witness(transaction, context, signingOptions);
643646

644647
this.#newTransactions.signed$.next(result);

packages/wallet/src/cip30.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -465,10 +465,10 @@ const baseCip30WalletApi = (
465465
},
466466
signTx: async ({ sender }: SenderContext, tx: Cbor, partialSign?: Boolean): Promise<Cbor> => {
467467
const scope = new ManagedFreeableScope();
468-
logger.debug('signTx');
469-
const txDecoded = Serialization.Transaction.fromCbor(Serialization.TxCBOR(tx));
468+
logger.debug('signTx', tx);
469+
const txCbor = Serialization.TxCBOR(tx);
470+
const txDecoded = Serialization.Transaction.fromCbor(txCbor);
470471
const wallet = await firstValueFrom(wallet$);
471-
const hash = txDecoded.getId();
472472
const coreTx = txDecoded.toCore();
473473

474474
const needsForeignSignature = await requiresForeignSignatures(coreTx, wallet);
@@ -493,9 +493,8 @@ const baseCip30WalletApi = (
493493
witness: { signatures }
494494
} = await signOrCancel(
495495
wallet.finalizeTx({
496-
bodyCbor: txDecoded.body().toCbor(),
497496
signingContext: { sender },
498-
tx: { ...coreTx, hash }
497+
tx: txCbor
499498
}),
500499
confirmationResult,
501500
() => new TxSignError(TxSignErrorCode.UserDeclined, 'user declined signing tx')

packages/wallet/src/types.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,13 @@ export interface SyncStatus extends Shutdown {
4949
isSettled$: Observable<boolean>;
5050
}
5151

52+
/**
53+
* If tx is the transaction CBOR, the auxiliary data, witness and isValid properties are ignored.
54+
* If tx is `Cardano.TxBodyWithHash`, the transaction is reconstructed from along with the other
55+
* provided properties.
56+
*/
5257
export type FinalizeTxProps = Omit<TxContext, 'signingContext'> & {
53-
tx: Cardano.TxBodyWithHash;
58+
tx: Cardano.TxBodyWithHash | Serialization.TxCBOR;
5459
bodyCbor?: HexBlob;
5560
signingContext?: Partial<SignTransactionContext>;
5661
};

0 commit comments

Comments
 (0)