Skip to content

Commit

Permalink
input-adding differentiation for regular, native, or plutus inputs
Browse files Browse the repository at this point in the history
  • Loading branch information
vsubhuman committed May 23, 2022
1 parent 271864e commit 8ef19a5
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 25 deletions.
20 changes: 9 additions & 11 deletions packages/yoroi-extension/app/api/ada/index.js
Expand Up @@ -106,7 +106,11 @@ import LocalizableError from '../../i18n/LocalizableError';
import { scanBip44Account, } from '../common/lib/restoration/bip44';
import { v2genAddressBatchFunc, } from './restoration/byron/scan';
import { scanShelleyCip1852Account } from './restoration/shelley/scan';
import type { CardanoAddressedUtxo, V4UnsignedTxAddressedUtxoResponse, } from './transactions/types';
import type {
CardanoAddressedUtxo,
CardanoUtxoScriptWitness,
V4UnsignedTxAddressedUtxoResponse,
} from './transactions/types';
import { HaskellShelleyTxSignRequest, } from './transactions/shelley/HaskellShelleyTxSignRequest';
import type { SignTransactionRequest } from '@cardano-foundation/ledgerjs-hw-app-cardano';
import { WrongPassphraseError } from './lib/cardanoCrypto/cryptoErrors';
Expand Down Expand Up @@ -327,16 +331,10 @@ export type CardanoTxRequestMint = {|
metadata?: CardanoTxRequestMintMetadata,
|};
type CardanoTxRequestInput =
string | // UTxO IDs
{|
id: string, // UTxO ID
nativeScript: string,
|} |
string | // UTxO ID
{|
id: string, // UTxO ID
plutusScript: string,
datum: string,
redeemer: string,
witness: CardanoUtxoScriptWitness,
|};
export type CardanoTxRequest = {|
includeInputs?: Array<CardanoTxRequestInput>,
Expand Down Expand Up @@ -1189,12 +1187,12 @@ export default class AdaApi {
return acc;
}, {})

const mustIncludeUtxos = [];
const mustIncludeUtxos: Array<[CardanoAddressedUtxo, ?CardanoUtxoScriptWitness]> = [];
const coinSelectUtxos = [];
for (const utxo of utxos) {
const includeInputEntry = includeInputMap[utxo.utxo_id];
if (includeInputEntry != null) {
mustIncludeUtxos.push(utxo);
mustIncludeUtxos.push([utxo, includeInputEntry.witness]);
} else {
coinSelectUtxos.push(utxo);
}
Expand Down
Expand Up @@ -3,7 +3,12 @@
// Handles interfacing w/ cardano-serialization-lib to create transaction

import BigNumber from 'bignumber.js';
import type { CardanoAddressedUtxo, V4UnsignedTxAddressedUtxoResponse, V4UnsignedTxUtxoResponse, } from '../types';
import type {
CardanoAddressedUtxo,
CardanoUtxoScriptWitness,
V4UnsignedTxAddressedUtxoResponse,
V4UnsignedTxUtxoResponse,
} from '../types';
import type { RemoteUnspentOutput, } from '../../lib/state-fetch/types';
import {
AssetOverflowError,
Expand All @@ -21,7 +26,7 @@ import { getCardanoSpendingKeyHash, normalizeToAddress, } from '../../lib/storag
import { MultiToken, } from '../../../common/lib/MultiToken';
import { PRIMARY_ASSET_CONSTANTS } from '../../lib/storage/database/primitives/enums';
import { cardanoValueFromMultiToken, cardanoValueFromRemoteFormat, multiTokenFromCardanoValue, } from '../utils';
import { hexToBytes } from '../../../../coreUtils';
import { hexToBytes, logErr } from '../../../../coreUtils';
import { coinSelectionForValues } from './coinSelection';

/**
Expand Down Expand Up @@ -122,6 +127,7 @@ function addUtxoInput(
protocolParams: {|
networkId: number,
|},
witness?: ?CardanoUtxoScriptWitness,
): $Values<typeof AddInputResult> {
const wasmAddr = normalizeToAddress(input.receiver);
if (wasmAddr == null) {
Expand Down Expand Up @@ -204,11 +210,56 @@ function addUtxoInput(
return skipResult;
}

txBuilder.add_input(
wasmAddr,
txInput,
wasmAmount
);
if (witness == null) {
logErr(
() => {
txBuilder.add_input(
wasmAddr,
txInput,
wasmAmount
);
},
'Failed to add a regular input',
);
} else if (witness.nativeScript != null) {
const nativeScript = logErr(
() => RustModule.WalletV4.NativeScript.from_bytes(hexToBytes(witness.nativeScript)),
`Failed to parse witness.nativeScript: ${JSON.stringify(witness)}`,
);
logErr(
() => {
txBuilder.add_native_script_input(
nativeScript,
txInput,
wasmAmount,
);
},
'Failed to add a native script input',
);
} else if (witness.plutusScript != null) {
const plutusScript = logErr(
() => RustModule.WalletV4.PlutusScript.from_bytes(hexToBytes(witness.plutusScript)),
`Failed to parse witness.plutusScript: ${JSON.stringify(witness)}`,
);
const datum = logErr(
() => RustModule.WalletV4.PlutusData.from_bytes(hexToBytes(witness.datum)),
`Failed to parse witness.datum: ${JSON.stringify(witness)}`,
);
const redeemer = logErr(
() => RustModule.WalletV4.Redeemer.from_bytes(hexToBytes(witness.redeemer)),
`Failed to parse witness.redeemer: ${JSON.stringify(witness)}`,
);
logErr(
() => {
txBuilder.add_plutus_script_input(
RustModule.WalletV4.PlutusWitness.new(plutusScript, datum, redeemer),
txInput,
wasmAmount,
);
},
'Failed to add a plutus script input',
);
}
return AddInputResult.VALID;
}

Expand Down Expand Up @@ -381,7 +432,7 @@ export function newAdaUnsignedTxForConnector(
mint: Array<TxMint>,
auxiliaryData: TxAuxiliaryData,
changeAdaAddr: void | {| ...Address, ...Addressing |},
mustIncludeUtxos: Array<CardanoAddressedUtxo>,
mustIncludeUtxos: Array<[CardanoAddressedUtxo, ?CardanoUtxoScriptWitness]>,
coinSelectUtxos: Array<CardanoAddressedUtxo>,
absSlotNumber: BigNumber,
validityStart: ?number,
Expand All @@ -402,10 +453,13 @@ export function newAdaUnsignedTxForConnector(
utxo_id: utxo.utxo_id,
assets: utxo.assets,
});
const mustIncludeRemoteOutputs: Array<[RemoteUnspentOutput, ?CardanoUtxoScriptWitness]> = [];
const addressingMapForMustIncludeUtxos = new Map<RemoteUnspentOutput, CardanoAddressedUtxo>();
const addressingMapForCoinSelectUtxos = new Map<RemoteUnspentOutput, CardanoAddressedUtxo>();
for (const utxo of mustIncludeUtxos) {
addressingMapForMustIncludeUtxos.set(toRemoteUnspentOutput(utxo), utxo);
for (const [utxo, witness] of mustIncludeUtxos) {
const remoteUnspentOutput = toRemoteUnspentOutput(utxo);
mustIncludeRemoteOutputs.push([remoteUnspentOutput, witness]);
addressingMapForMustIncludeUtxos.set(remoteUnspentOutput, utxo);
}
for (const utxo of coinSelectUtxos) {
addressingMapForCoinSelectUtxos.set(toRemoteUnspentOutput(utxo), utxo);
Expand All @@ -415,7 +469,7 @@ export function newAdaUnsignedTxForConnector(
mint,
auxiliaryData,
changeAdaAddr,
Array.from(addressingMapForMustIncludeUtxos.keys()),
mustIncludeRemoteOutputs,
Array.from(addressingMapForCoinSelectUtxos.keys()),
absSlotNumber,
validityStart,
Expand Down Expand Up @@ -660,7 +714,7 @@ function newAdaUnsignedTxFromUtxoForConnector(
mint: Array<TxMint>,
auxiliaryData: TxAuxiliaryData,
changeAdaAddr: void | {| ...Address, ...Addressing |},
mustIncludeUtxos: Array<RemoteUnspentOutput>,
mustIncludeUtxos: Array<[RemoteUnspentOutput, ?CardanoUtxoScriptWitness]>,
coinSelectUtxos: Array<RemoteUnspentOutput>,
absSlotNumber: BigNumber,
validityStart: ?number,
Expand Down Expand Up @@ -772,13 +826,14 @@ function newAdaUnsignedTxFromUtxoForConnector(
/**
* REQUIRED INPUTS
*/
for (const utxo of mustIncludeUtxos) {
for (const [utxo, witness] of mustIncludeUtxos) {
const added = addUtxoInput(
txBuilder,
undefined,
utxo,
true,
{ networkId: protocolParams.networkId },
witness,
);
if (added !== AddInputResult.VALID) {
throw new Error('could not add designated UTXO');
Expand Down
8 changes: 8 additions & 0 deletions packages/yoroi-extension/app/api/ada/transactions/types.js
Expand Up @@ -28,6 +28,14 @@ export type UserAnnotation = {|
+fee: MultiToken,
|};

export type CardanoUtxoScriptWitness = {
nativeScript: string,
} | {
plutusScript: string,
datum: string,
redeemer: string,
}

export type CardanoAddressedUtxo = {|
...RemoteUnspentOutput,
...Addressing,
Expand Down
11 changes: 10 additions & 1 deletion packages/yoroi-extension/app/coreUtils.js
Expand Up @@ -10,4 +10,13 @@ export function hexToBytes(hex: string): Buffer {

export function hexToUtf(hex: string): string {
return hexToBytes(hex).toString('utf-8');
}
}

export function logErr<T>(f: () => T, msg: (string | (Error) => string)) {
try {
return f();
} catch (e) {
console.error(typeof msg === 'string' ? msg : msg(e), e);
throw e;
}
}

0 comments on commit 8ef19a5

Please sign in to comment.