Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

not asserting withdrawals to be strictly local + tagged cbor sets #3781

Merged
merged 7 commits into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions packages/yoroi-extension/app/api/ada/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -717,7 +717,7 @@ export default class AdaApi {
);

return {
txHash: Scope.WalletV4.hash_transaction(signedTx.body()).to_hex(),
txHash: Scope.WalletV4.FixedTransaction.from_hex(signedTx.to_hex()).transaction_hash().to_hex(),
encodedTx: signedTx.to_bytes(),
}
})
Expand Down Expand Up @@ -1579,13 +1579,13 @@ export default class AdaApi {
);

{
const body = unsignedTxResponse.txBuilder.build();
const tx = unsignedTxResponse.txBuilder.build_tx();
for (const withdrawal of request.withdrawals) {
if (withdrawal.privateKey != null) {
const { privateKey } = withdrawal;
neededKeys.wits.add(
RustModule.WalletV4.make_vkey_witness(
RustModule.WalletV4.hash_transaction(body),
RustModule.WalletV4.FixedTransaction.from_hex(tx.to_hex()).transaction_hash(),
privateKey
).to_hex()
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -546,10 +546,11 @@ export function toRemoteByronTx(
request: SignedRequestInternal,
): RemoteTransaction {
const tx = Array.isArray(request.signedTx) ? forceNonNull(last(request.signedTx)) : request.signedTx;
const signedTx = RustModule.WalletV4.Transaction.from_bytes(Buffer.from(tx, 'base64'));
const txBytes = Buffer.from(tx, 'base64');
const signedTx = RustModule.WalletV4.Transaction.from_bytes(txBytes);

const body = signedTx.body();
const hash = RustModule.WalletV4.hash_transaction(body).to_hex();
const hash = RustModule.WalletV4.FixedTransaction.from_bytes(txBytes).transaction_hash().to_hex();

const outputs = iterateLenGet(body.outputs()).map(output => ({
address: toHexOrBase58(output.address()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ export async function buildYoroiTransferTx(payload: {|
return {
recoveredBalance: totalBalance,
fee,
id: RustModule.WalletV4.hash_transaction(signedTx.body()).to_hex(),
id: RustModule.WalletV4.FixedTransaction.from_hex(signedTx.to_hex()).transaction_hash().to_hex(),
encodedTx: signedTx.to_bytes(),
// only display unique addresses
senders: Array.from(new Set(senderUtxos.map(utxo => utxo.receiver))),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,9 @@ implements ISignRequest<RustModule.WalletV4.TransactionBuilder> {
}

txId(): string {
return RustModule.WalletV4.hash_transaction(this.unsignedTx.build()).to_hex();
return RustModule.WalletV4.FixedTransaction.from_hex(
this.unsignedTx.build_tx().to_hex()
).transaction_hash().to_hex();
}

size(): {| full: number, outputs: number[] |} {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,15 @@ import { toHexOrBase58 } from '../../lib/storage/bridge/utils';
import { Bip44DerivationLevels, } from '../../lib/storage/database/walletTypes/bip44/api/utils';
import { ChainDerivations, } from '../../../../config/numbersConfig';
import { derivePublicByAddressing } from '../../lib/cardanoCrypto/deriveByAddressing';
import { bytesToHex, fail, forceNonNull, iterateLenGet, iterateLenGetMap, maybe } from '../../../../coreUtils';
import {
bytesToHex,
fail,
forceNonNull,
hexToBytes,
iterateLenGet,
iterateLenGetMap,
maybe
} from '../../../../coreUtils';
import { mergeWitnessSets } from '../utils';

// ==================== LEDGER ==================== //
Expand All @@ -48,7 +56,18 @@ export function createLedgerSignTxPayload(request: {|
addressingMap: string => (void | $PropertyType<Addressing, 'addressing'>),
cip36: boolean,
|}): SignTransactionRequest {
const txBody = request.signRequest.unsignedTx.build();

const tx = request.signRequest.unsignedTx.build_tx();
const txBody = tx.body();

const tagsState = RustModule.WasmScope(Module =>
Module.WalletV4.has_transaction_set_tag(tx.to_bytes()));

if (tagsState === RustModule.WalletV4.TransactionSetsState.MixedSets) {
throw new Error('Transaction with mixed sets cannot be signed by Ledger');
}

const txHasSetTags = tagsState === RustModule.WalletV4.TransactionSetsState.AllSetsHaveTag;

// Inputs
const ledgerInputs = _transformToLedgerInputs(
Expand Down Expand Up @@ -166,7 +185,7 @@ export function createLedgerSignTxPayload(request: {|
},
additionalWitnessPaths: [],
options: {
tagCborSets: false,
tagCborSets: txHasSetTags,
}
};
}
Expand Down Expand Up @@ -304,17 +323,37 @@ function formatLedgerWithdrawals(
for (const [rewardAddress, withdrawalAmount] of iterateLenGetMap(withdrawals).nonNullValue()) {
const rewardAddressPayload = rewardAddress.to_address().to_hex();
const addressing = addressingMap(rewardAddressPayload);
if (addressing == null) {
throw new Error(`${nameof(formatLedgerWithdrawals)} Ledger can only withdraw from own address ${rewardAddressPayload}`);
let stakeCredential;
if (addressing != null) {
stakeCredential = {
type: CredentialParamsType.KEY_PATH,
keyPath: addressing.path,
};
} else {
const cred = rewardAddress.payment_cred();
const maybeKeyHash = cred.to_keyhash();
const maybeScriptHash = cred.to_scripthash();
if (maybeKeyHash) {
stakeCredential = {
type: CredentialParamsType.KEY_HASH,
keyHashHex: maybeKeyHash.to_hex(),
};
} else if (maybeScriptHash) {
stakeCredential = {
type: CredentialParamsType.SCRIPT_HASH,
scriptHashHex: maybeScriptHash.to_hex(),
};
}
}
if (stakeCredential == null) {
throw new Error('Failed to resolve credential type for reward address: ' + rewardAddressPayload);
}
result.push({
amount: withdrawalAmount.to_str(),
stakeCredential: {
type: CredentialParamsType.KEY_PATH,
keyPath: addressing.path,
},
stakeCredential,
});
}
// $FlowIgnore[incompatible-return]
return result;
}

Expand Down Expand Up @@ -772,6 +811,16 @@ export function toLedgerSignRequest(
additionalRequiredSigners: Array<string> = [],
): SignTransactionRequest {

const tagsState = RustModule.WasmScope(Module => Module.WalletV4.has_transaction_set_tag(
Module.WalletV4.FixedTransaction.new_from_body_bytes(hexToBytes(txBodyHex)).to_bytes()
));

if (tagsState === RustModule.WalletV4.TransactionSetsState.MixedSets) {
throw new Error('Transaction with mixed sets cannot be signed by Ledger');
}

const txHasSetTags = tagsState === RustModule.WalletV4.TransactionSetsState.AllSetsHaveTag;

const txBody = RustModule.WalletV4.TransactionBody.from_hex(txBodyHex);

function formatInputs(inputs: RustModule.WalletV4.TransactionInputs): Array<TxInput> {
Expand Down Expand Up @@ -1076,6 +1125,9 @@ export function toLedgerSignRequest(
referenceInputs: formattedReferenceInputs,
},
additionalWitnessPaths,
options: {
tagCborSets: txHasSetTags,
}
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1086,15 +1086,15 @@ export function signTransaction(
if (unsignedTx instanceof RustModule.WalletV4.Transaction) {
txBody = unsignedTx.body();
txWitSet = unsignedTx.witness_set();
txHash = RustModule.WalletV4.hash_transaction(txBody);
txHash = RustModule.WalletV4.FixedTransaction.from_hex(unsignedTx.to_hex()).transaction_hash();
} else if (unsignedTx instanceof RustModule.WalletV4.TransactionBuilder) {
const tx = unsignedTx.build_tx();
txBody = tx.body();
txWitSet = tx.witness_set();
txHash = RustModule.WalletV4.hash_transaction(txBody);
txHash = RustModule.WalletV4.FixedTransaction.from_hex(tx.to_hex()).transaction_hash();
} else if (unsignedTx instanceof RustModule.WalletV4.TransactionBody) {
txBody = unsignedTx;
txHash = RustModule.WalletV4.hash_transaction(txBody);
txHash = RustModule.WalletV4.FixedTransaction.new_from_body_bytes(txBody.to_bytes()).transaction_hash();
} else if (unsignedTx instanceof Buffer || unsignedTx instanceof Uint8Array) {
// note: we are calculating the tx hash from the raw tx body bytes, which
// probably won't match the serialized `txBody`. But this happens only for
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -954,11 +954,9 @@ describe('Create signed transactions', () => {
accountPrivateKey,
new Set([
RustModule.WalletV4.make_vkey_witness(
RustModule.WalletV4.hash_transaction(
RustModule.WalletV4.TransactionBody.from_bytes(
unsignedTxResponse.txBuilder.build().to_bytes(),
),
),
RustModule.WalletV4.FixedTransaction.from_hex(
unsignedTxResponse.txBuilder.build_tx().to_hex(),
).transaction_hash(),
stakingKey,
).to_hex()
]),
Expand Down Expand Up @@ -1031,11 +1029,9 @@ describe('Create signed transactions', () => {
accountPrivateKey,
new Set([
RustModule.WalletV4.make_vkey_witness(
RustModule.WalletV4.hash_transaction(
RustModule.WalletV4.TransactionBody.from_bytes(
unsignedTxResponse.txBuilder.build().to_bytes(),
),
),
RustModule.WalletV4.FixedTransaction.from_hex(
unsignedTxResponse.txBuilder.build_tx().to_hex()
).transaction_hash(),
stakingKey,
).to_hex(),
]),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import { RustModule } from '../../lib/cardanoCrypto/rustLoader';
import { toHexOrBase58 } from '../../lib/storage/bridge/utils';
import blake2b from 'blake2b';
import { derivePublicByAddressing } from '../../lib/cardanoCrypto/deriveByAddressing';
import { bytesToHex, iterateLenGet, iterateLenGetMap, maybe, forceNonNull } from '../../../../coreUtils';
import { bytesToHex, iterateLenGet, iterateLenGetMap, maybe, forceNonNull, hexToBytes } from '../../../../coreUtils';
import { mergeWitnessSets } from '../utils';

// ==================== TREZOR ==================== //
Expand All @@ -58,7 +58,17 @@ export function createTrezorSignTxPayload(
return result;
})();

const txBody = signRequest.unsignedTx.build();
const tx = signRequest.unsignedTx.build_tx();
const txBody = tx.body();

const tagsState = RustModule.WasmScope(Module =>
Module.WalletV4.has_transaction_set_tag(tx.to_bytes()));

if (tagsState === RustModule.WalletV4.TransactionSetsState.MixedSets) {
throw new Error('Transaction with mixed sets cannot be signed by Ledger');
}

const txHasSetTags = tagsState === RustModule.WalletV4.TransactionSetsState.AllSetsHaveTag;

// Inputs
const trezorInputs = _transformToTrezorInputs(
Expand Down Expand Up @@ -144,6 +154,12 @@ export function createTrezorSignTxPayload(
}
};
}
if (txHasSetTags) {
request = {
...request,
tagCborSets: true,
};
}
return request;
}

Expand Down Expand Up @@ -546,6 +562,16 @@ export function toTrezorSignRequest(
senderUtxos: Array<CardanoAddressedUtxo>,
): $Exact<CardanoSignTransaction> {

const tagsState = RustModule.WasmScope(Module => Module.WalletV4.has_transaction_set_tag(
Module.WalletV4.FixedTransaction.new_from_body_bytes(hexToBytes(txBodyHex)).to_bytes()
));

if (tagsState === RustModule.WalletV4.TransactionSetsState.MixedSets) {
throw new Error('Transaction with mixed sets cannot be signed by Ledger');
}

const txHasSetTags = tagsState === RustModule.WalletV4.TransactionSetsState.AllSetsHaveTag;

const txBody = RustModule.WalletV4.TransactionBody.from_hex(txBodyHex);

function formatInputs(inputs: RustModule.WalletV4.TransactionInputs): Array<CardanoInput> {
Expand Down Expand Up @@ -860,6 +886,9 @@ export function toTrezorSignRequest(
if (additionalWitnessRequests.length > 0) {
result.additionalWitnessRequests = additionalWitnessRequests;
}
if (txHasSetTags) {
result.tagCborSets = true;
}

return result;
}
Expand Down
2 changes: 1 addition & 1 deletion packages/yoroi-extension/app/api/thunk.js
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ export async function signAndBroadcastTransaction(
): Promise<{| txId: string |}> {
const tx = request.signRequest.unsignedTx.build_tx();
const txBody = tx.body();
const txHash = RustModule.WalletV4.hash_transaction(txBody);
const txHash = RustModule.WalletV4.FixedTransaction.from_hex(tx.to_hex()).transaction_hash();

const serializableRequest: SignAndBroadcastTransactionRequestType = {
senderUtxos: request.signRequest.senderUtxos,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1064,7 +1064,8 @@ export default class ConnectorStore extends Store<StoresMap, ActionsMap> {
s => ownAddressMap[s],
addressedUtxos,
);
} catch {
} catch (e) {
console.error('toTrezorSignRequest failed: ', e);
runInAction(() => {
this.hwWalletError = unsupportedTransactionError;
this.isHwWalletErrorRecoverable = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ export default class TrezorSendStore extends Store<StoresMap, ActionsMap> {
metadata,
);

const txId = RustModule.WalletV4.hash_transaction(tx.body()).to_hex();
const txId = RustModule.WalletV4.FixedTransaction.from_hex(tx.to_hex()).transaction_hash().to_hex();

await broadcastTransaction({
publicDeriverId: request.wallet.publicDeriverId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,8 @@ const Handlers = Object.freeze({
[ string /* tx hex */ ],
string,
>(async ({ wallet, message }) => {
const txBuffer = hexToBytes(message.params[0]);
const txHex = message.params[0];
const txBuffer = hexToBytes(txHex);
await connectorSendTxCardano(
wallet,
txBuffer,
Expand All @@ -397,7 +398,7 @@ const Handlers = Object.freeze({
const tx = RustModule.WalletV4.Transaction.from_bytes(
txBuffer
);
const id = RustModule.WalletV4.hash_transaction(tx.body()).to_hex();
const id = RustModule.WalletV4.FixedTransaction.from_hex(txHex).transaction_hash().to_hex();
try {
await connectorRecordSubmittedCardanoTransaction(
wallet,
Expand Down
Loading
Loading