From 0998bc993702649323875a25410fce6ed3e8211a Mon Sep 17 00:00:00 2001 From: Angel Castillo Date: Mon, 22 Jul 2024 08:48:25 +0800 Subject: [PATCH] fix(input-selection): round robin random improve now produces valid change outputs when wallet has too many assets --- .../src/RoundRobinRandomImprove/change.ts | 74 +++++++++- .../InputSelectionPropertyTesting.test.ts | 3 +- .../test/RoundRobinRandomImprove.test.ts | 36 +++++ packages/input-selection/test/tsconfig.json | 2 +- packages/input-selection/test/vectors.ts | 133 ++++++++++++++++++ 5 files changed, 245 insertions(+), 3 deletions(-) create mode 100644 packages/input-selection/test/vectors.ts diff --git a/packages/input-selection/src/RoundRobinRandomImprove/change.ts b/packages/input-selection/src/RoundRobinRandomImprove/change.ts index 400505d0abd..42b78358b4b 100644 --- a/packages/input-selection/src/RoundRobinRandomImprove/change.ts +++ b/packages/input-selection/src/RoundRobinRandomImprove/change.ts @@ -270,12 +270,71 @@ export const coalesceChangeBundlesForMinCoinRequirement = ( return sortedBundles.filter((bundle) => bundle.coins > 0n || (bundle.assets?.size || 0) > 0); }; +/** + * Splits change bundles if the token bundle size exceeds the specified limit. Each bundle is checked, + * and if it exceeds the limit, it's split into smaller bundles such that each conforms to the limit. + * It also ensures that each bundle has a minimum coin quantity. + * + * @param changeBundles - The array of change bundles, each containing assets and their quantities. + * @param computeMinimumCoinQuantity - A function to compute the minimum coin quantity required for a transaction output. + * @param tokenBundleSizeExceedsLimit - A function to determine if the token bundle size of a set of assets exceeds a predefined limit. + * @returns The array of adjusted change bundles, conforming to the token bundle size limits and each having the necessary minimum coin quantity. + * @throws Throws an error if the total coin amount is fully depleted and cannot cover the minimum required coin quantity. + */ +const splitChangeIfTokenBundlesSizeExceedsLimit = ( + changeBundles: Cardano.Value[], + computeMinimumCoinQuantity: ComputeMinimumCoinQuantity, + tokenBundleSizeExceedsLimit: TokenBundleSizeExceedsLimit +): Cardano.Value[] => { + const result: Cardano.Value[] = []; + + for (const bundle of changeBundles) { + const { assets, coins } = bundle; + if (!assets || assets.size === 0 || !tokenBundleSizeExceedsLimit(assets)) { + result.push({ assets, coins }); + continue; + } + + const newValues = []; + let newValue = { assets: new Map(), coins: 0n }; + + for (const [assetId, quantity] of assets.entries()) { + newValue.assets.set(assetId, quantity); + + if (tokenBundleSizeExceedsLimit(newValue.assets) && newValue.assets.size > 1) { + newValue.assets.delete(assetId); + newValues.push(newValue); + newValue = { assets: new Map([[assetId, quantity]]), coins: 0n }; + } + } + + newValues.push(newValue); + + let totalMinCoin = 0n; + for (const value of newValues) { + const minCoin = computeMinimumCoinQuantity({ address: stubMaxSizeAddress, value }); + value.coins = minCoin; + totalMinCoin += minCoin; + } + + if (coins < totalMinCoin) { + throw new InputSelectionError(InputSelectionFailure.UtxoFullyDepleted); + } + + newValues[0].coins += coins - totalMinCoin; + result.push(...newValues); + } + + return result; +}; + const computeChangeBundles = ({ utxoSelection, outputValues, uniqueTxAssetIDs, implicitValue, computeMinimumCoinQuantity, + tokenBundleSizeExceedsLimit, fee = 0n }: { utxoSelection: UtxoSelection; @@ -283,6 +342,7 @@ const computeChangeBundles = ({ uniqueTxAssetIDs: Cardano.AssetId[]; implicitValue: RequiredImplicitValue; computeMinimumCoinQuantity: ComputeMinimumCoinQuantity; + tokenBundleSizeExceedsLimit: TokenBundleSizeExceedsLimit; fee?: bigint; }): (UtxoSelection & { changeBundles: Cardano.Value[] }) | false => { const requestedAssetChangeBundles = computeRequestedAssetChangeBundles( @@ -304,7 +364,17 @@ const computeChangeBundles = ({ if (!changeBundles) { return false; } - return { changeBundles, ...utxoSelection }; + + // Make sure the change outputs do not exceed token bundle size limit, this can happen if the UTXO set + // has too many assets and the selection strategy selects enough of them to violates this constraint for the resulting + // change output set. + const adjustedChange = splitChangeIfTokenBundlesSizeExceedsLimit( + changeBundles, + computeMinimumCoinQuantity, + tokenBundleSizeExceedsLimit + ); + + return { changeBundles: adjustedChange, ...utxoSelection }; }; const validateChangeBundles = ( @@ -365,6 +435,7 @@ export const computeChangeAndAdjustForFee = async ({ computeMinimumCoinQuantity, implicitValue, outputValues, + tokenBundleSizeExceedsLimit, uniqueTxAssetIDs, utxoSelection }); @@ -395,6 +466,7 @@ export const computeChangeAndAdjustForFee = async ({ fee: estimatedCosts.fee, implicitValue, outputValues, + tokenBundleSizeExceedsLimit, uniqueTxAssetIDs, utxoSelection: pick(selectionWithChangeAndFee, ['utxoRemaining', 'utxoSelected']) }); diff --git a/packages/input-selection/test/InputSelectionPropertyTesting.test.ts b/packages/input-selection/test/InputSelectionPropertyTesting.test.ts index 31cfdb8461c..a6622dc9752 100644 --- a/packages/input-selection/test/InputSelectionPropertyTesting.test.ts +++ b/packages/input-selection/test/InputSelectionPropertyTesting.test.ts @@ -298,7 +298,8 @@ const testInputSelection = (name: string, getAlgorithm: () => InputSelector) => getAlgorithm, mockConstraints: { ...SelectionConstraints.MOCK_NO_CONSTRAINTS, - maxTokenBundleSize: 1 + maxTokenBundleSize: 1, + minimumCoinQuantity: 1_000_000n } }); }); diff --git a/packages/input-selection/test/RoundRobinRandomImprove.test.ts b/packages/input-selection/test/RoundRobinRandomImprove.test.ts index e8640ec863e..8fdceced019 100644 --- a/packages/input-selection/test/RoundRobinRandomImprove.test.ts +++ b/packages/input-selection/test/RoundRobinRandomImprove.test.ts @@ -1,6 +1,14 @@ import { Cardano } from '@cardano-sdk/core'; import { MockChangeAddressResolver, SelectionConstraints } from './util'; import { TxTestUtil } from '@cardano-sdk/util-dev'; +import { + babbageSelectionParameters, + cborUtxoSetWithManyAssets, + getCoreUtxosFromCbor, + txBuilder, + txEvaluator +} from './vectors'; +import { defaultSelectionConstraints } from '../../tx-construction/src/input-selection/selectionConstraints'; import { roundRobinRandomImprove } from '../src/RoundRobinRandomImprove'; describe('RoundRobinRandomImprove', () => { @@ -78,4 +86,32 @@ describe('RoundRobinRandomImprove', () => { ) ).toBeTruthy(); }); + + it('splits change outputs if they violate the tokenBundleSizeExceedsLimit constraint', async () => { + const utxoSet = getCoreUtxosFromCbor(cborUtxoSetWithManyAssets); + const maxSpendableAmount = 87_458_893n; + const assetsInUtxoSet = 511; + + const constraints = defaultSelectionConstraints({ + buildTx: txBuilder, + protocolParameters: babbageSelectionParameters, + redeemersByType: {}, + txEvaluator: txEvaluator as never + }); + + const results = await roundRobinRandomImprove({ + changeAddressResolver: new MockChangeAddressResolver() + }).select({ + constraints, + outputs: new Set([TxTestUtil.createOutput({ coins: maxSpendableAmount })]), + preSelectedUtxo: new Set(), + utxo: utxoSet + }); + + expect(results.selection.inputs.size).toBe(utxoSet.size); + expect(results.selection.change.length).toBe(2); + expect(results.selection.change[0].value.assets!.size + results.selection.change[1].value.assets!.size).toBe( + assetsInUtxoSet + ); + }); }); diff --git a/packages/input-selection/test/tsconfig.json b/packages/input-selection/test/tsconfig.json index b7eebbc140d..14ac9bf0dde 100644 --- a/packages/input-selection/test/tsconfig.json +++ b/packages/input-selection/test/tsconfig.json @@ -3,7 +3,7 @@ "compilerOptions": { "baseUrl": "." }, - "include": ["./**/*.ts"], + "include": ["./**/*.ts", "../../tx-construction/src/input-selection/selectionConstraints"], "references": [ { "path": "../src" diff --git a/packages/input-selection/test/vectors.ts b/packages/input-selection/test/vectors.ts new file mode 100644 index 00000000000..ece602c9b1a --- /dev/null +++ b/packages/input-selection/test/vectors.ts @@ -0,0 +1,133 @@ +import { Cardano, Serialization } from '@cardano-sdk/core'; +import { HexBlob } from '@cardano-sdk/util'; +import { ProtocolParametersForInputSelection } from '../src'; +import { SelectionSkeleton } from '../dist/cjs'; +import { TxTestUtil } from '@cardano-sdk/util-dev'; + +export const mockTx: Cardano.Tx = { + body: { + fee: 10n, + inputs: [TxTestUtil.createTxInput()], + outputs: [TxTestUtil.createOutput({ coins: 1_000_000n })] + }, + id: Cardano.TransactionId('8d2feeab1087e0aa4ad06e878c5269eaa2edcef5264bcc97542a28c189b2cbc5'), + witness: { + signatures: new Map([ + [ + 'd75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a', + 'e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b' + ] + ]) as Cardano.Signatures + } +}; + +export const babbageSelectionParameters = { + coinsPerUtxoByte: 4310, + maxTxSize: 16_384, + maxValueSize: 5000, + minFeeCoefficient: 44, + minFeeConstant: 155_381, + prices: { memory: 0.0577, steps: 0.000_007_21 } +} as ProtocolParametersForInputSelection; + +export const cborUtxoSetWithManyAssets = [ + HexBlob( + '8282582065375f2301b0fe4bed847138821af6401c36732cd5dbcf16f993d75c675e6dff00825839019ec46b264f72a1905c89cfc348c0b3530dbbcbe75dfc0f0473df753bb9416169cea3eb4cfc7f331b6e5f81b069495cf96c1730b7b0cfedb5821a0014e9d4a2581c80c7314177f9f0089d16f412c20f2ada0934c179ad6dc04e27722cf4a1474c4951474f4c441903e8581ca09278c524f157eec21b6c590e57022e8acf1980035c94018817490ea15041726d6f724d756c7469706c6578563102' + ), + HexBlob( + '8282582065375f2301b0fe4bed847138821af6401c36732cd5dbcf16f993d75c675e6dff01825839019ec46b264f72a1905c89cfc348c0b3530dbbcbe75dfc0f0473df753bb9416169cea3eb4cfc7f331b6e5f81b069495cf96c1730b7b0cfedb5821a00280d16a6581c03bb190eb9ed60d4a52e2b314e89b6a1dbbf07ed5717942d90131a58a14847656e746f31393701581c0728fb6e98a52c7fed8d95df0d509deab81b8460384b9541eaa893f7a24f507572706c65446561746830333030014f507572706c6544656174683039373801581c075689c3bbac454f053a120099068a4b5e66c9a425952a5a271b1e57a34d5061796261636b414f57303031014d5061796261636b414f57303032014d5061796261636b414f5730313901581c08745cbfeed4d42985b9fb6accd955514e21d9425e6746268c46360ca14f54555246394333564643323443393201581c0ad7f7a3281ba7c832344eb267594899147709b708176bc1084979f1a7473130343435323401473130353231343901473130363037333301473130373335333401473130383232373401473130393032313401473130393831313301581c101f1c1116505176b2fb3eb43dd698a91e7f713bde7886d7ddfd6d4ea158184e5943656c6562726174696f6e323032334443433030383901' + ), + HexBlob( + '8282582065375f2301b0fe4bed847138821af6401c36732cd5dbcf16f993d75c675e6dff02825839019ec46b264f72a1905c89cfc348c0b3530dbbcbe75dfc0f0473df753bb9416169cea3eb4cfc7f331b6e5f81b069495cf96c1730b7b0cfedb5821a00348beaaa581c11ff0e0d9ad037d18e3ed575cd35a0513b8473f83008124db89f1d8fa1504861707079486f70706572303937343001581c139be85c1c04afa7ae6563f60e96a5b35ea2ef34e15258f50488e6f8a350507572706c65446561746833443033360150507572706c6544656174683344303735015243686962694172744f66576f6d616e30313501581c14a95b2a4a863c8074d6a78a6a445150223e867999a90295dc1d0cf6a35050726f6a65637456656e757330303031015050726f6a65637456656e757330303237015050726f6a65637456656e75733034343901581c15863308ea198618a40426bb3989b2849e263c85aa757281b22476e5a14b5044506879736963616c3101581c17e953e5995a2f54c38b4ae4fa5a110b36be36ff892a66c36a511598a24d464841313030424c5545323536014d464841313030424c554532383401581c1d4dff885ca2381ef1fa79ea0ca6d2baf47bc72afd920b644e84ad88a15246616861646f756b656e31304b763332303801581c220d4993a171f82cab14f6597457e33bd0ad407b6e3da8199d0ef434a15041444150756e6b566f78656c3137363101581c25203856802bc901de04a1d2c780b732b22cddf111613858995c492aa153576869736b656573207820414f57202330313301581c4247d5091db82330100904963ab8d0850976c80d3f1b927e052e07bda146546f6b68756e01581c4d7fadadc1d6b6abd470f66a9778e155a9354b62738b0a9a0737d96fa1564461696c79446f736553706163654275647a3636343901' + ), + HexBlob( + '8282582065375f2301b0fe4bed847138821af6401c36732cd5dbcf16f993d75c675e6dff07825839019ec46b264f72a1905c89cfc348c0b3530dbbcbe75dfc0f0473df753bb9416169cea3eb4cfc7f331b6e5f81b069495cf96c1730b7b0cfedb5821a002b9a3aa6581c76ebe108d0d58ba2ffe6024cf25cf5f6a890f4c61d77ee7911362b14a64a41444150756e6b363034014b41444150756e6b31373631014b41444150756e6b35363739014b41444150756e6b36303632014b41444150756e6b38303531014b41444150756e6b3937363301581c9cf64dc7e71b4d952632ddec21440a99111765a3fa1c3d9a42c15c0ea351496e66696e697465566f696423303332340151496e66696e697465566f696423303338370151496e66696e697465566f6964233038373501581ca09278c524f157eec21b6c590e57022e8acf1980035c94018817490ea34d4d61736b4e6f78696f75735632014e44726f696452616469616e7456320151476c6173736573497465726e616c73563101581ca3a893673545e647b53c05af7765857d706c29371cdbfb365a3a0daca158184461696c79446f7365484e544d6178696d616c697374303501581ca5bb0e5bb275a573d744a021f9b3bff73595468e002755b447e01559a156484f534b59436173684772616230303031313236323701581ca616aab3b18eb855b4292246bd58f9e131d7c8c25d1d1d7c88b666c4a14d50454e44554c554d303133313401' + ), + HexBlob( + '8282582065375f2301b0fe4bed847138821af6401c36732cd5dbcf16f993d75c675e6dff0a825839019ec46b264f72a1905c89cfc348c0b3530dbbcbe75dfc0f0473df753bb9416169cea3eb4cfc7f331b6e5f81b069495cf96c1730b7b0cfedb5821a002aae86a1581c90465e141ecb7b72ed0cdbcbd848673177cd52be5af5518e95d0de1db81e4b33444547454e5330343136014b33444547454e5330343138014b33444547454e5330343538014b33444547454e5330343738014b33444547454e5330343839014b33444547454e5330353032014b33444547454e5330353131014b33444547454e5330353730014b33444547454e5330353833014b33444547454e5330353933014b33444547454e5330363137014b33444547454e5330363432014b33444547454e5330363436014b33444547454e5330363930014b33444547454e5330373039014b33444547454e5330373235014b33444547454e5330373534014b33444547454e5330373636014b33444547454e5330373937014b33444547454e5330373939014b33444547454e5330383333014b33444547454e5330383437014b33444547454e5330383533014b33444547454e5330383739014b33444547454e5330383835014b33444547454e5330383932014b33444547454e5330393033014b33444547454e5330393136014b33444547454e5330393231014b33444547454e533039323601' + ), + HexBlob( + '8282582065375f2301b0fe4bed847138821af6401c36732cd5dbcf16f993d75c675e6dff0b825839019ec46b264f72a1905c89cfc348c0b3530dbbcbe75dfc0f0473df753bb9416169cea3eb4cfc7f331b6e5f81b069495cf96c1730b7b0cfedb5821a002aae86a1581c90465e141ecb7b72ed0cdbcbd848673177cd52be5af5518e95d0de1db81e4b33444547454e5330393535014b33444547454e5330393538014b33444547454e5330393837014b33444547454e5330393933014b33444547454e5331303030014b33444547454e5331303130014b33444547454e5331303237014b33444547454e5331303434014b33444547454e5331303534014b33444547454e5331303632014b33444547454e5331303834014b33444547454e5331303930014b33444547454e5331303934014b33444547454e5331313134014b33444547454e5331313638014b33444547454e5331313935014b33444547454e5331323132014b33444547454e5331323632014b33444547454e5331323733014b33444547454e5331333135014b33444547454e5331333432014b33444547454e5331333633014b33444547454e5331333637014b33444547454e5331333933014b33444547454e5331333934014b33444547454e5331343033014b33444547454e5331343636014b33444547454e5331343731014b33444547454e5331343738014b33444547454e533135303001' + ), + HexBlob( + '8282582065375f2301b0fe4bed847138821af6401c36732cd5dbcf16f993d75c675e6dff0d825839019ec46b264f72a1905c89cfc348c0b3530dbbcbe75dfc0f0473df753bb9416169cea3eb4cfc7f331b6e5f81b069495cf96c1730b7b0cfedb5821a002aae86a1581c90465e141ecb7b72ed0cdbcbd848673177cd52be5af5518e95d0de1db81e4b33444547454e5331393434014b33444547454e5331393630014b33444547454e5331393636014b33444547454e5331393838014b33444547454e5332303035014b33444547454e5332303233014b33444547454e5332303235014b33444547454e5332303435014b33444547454e5332303438014b33444547454e5332303736014b33444547454e5332303934014b33444547454e5332313038014b33444547454e5332313134014b33444547454e5332313231014b33444547454e5332313233014b33444547454e5332313239014b33444547454e5332313437014b33444547454e5332313438014b33444547454e5332313532014b33444547454e5332313536014b33444547454e5332313538014b33444547454e5332323332014b33444547454e5332323939014b33444547454e5332333231014b33444547454e5332333334014b33444547454e5332333631014b33444547454e5332333637014b33444547454e5332333733014b33444547454e5332333833014b33444547454e533233393301' + ), + HexBlob( + '8282582065375f2301b0fe4bed847138821af6401c36732cd5dbcf16f993d75c675e6dff0f825839019ec46b264f72a1905c89cfc348c0b3530dbbcbe75dfc0f0473df753bb9416169cea3eb4cfc7f331b6e5f81b069495cf96c1730b7b0cfedb5821a002aae86a1581c90465e141ecb7b72ed0cdbcbd848673177cd52be5af5518e95d0de1db81e4b33444547454e5332383231014b33444547454e5332383233014b33444547454e5332383431014b33444547454e5332383432014b33444547454e5332383534014b33444547454e5332383535014b33444547454e5332383536014b33444547454e5332383538014b33444547454e5332383635014b33444547454e5332383636014b33444547454e5332393230014b33444547454e5332393232014b33444547454e5332393233014b33444547454e5332393331014b33444547454e5332393332014b33444547454e5332393336014b33444547454e5332393530014b33444547454e5332393634014b33444547454e5332393833014b33444547454e5333303037014b33444547454e5333303132014b33444547454e5333303133014b33444547454e5333303135014b33444547454e5333303330014b33444547454e5333303331014b33444547454e5333303434014b33444547454e5333303537014b33444547454e5333303837014b33444547454e5333313338014b33444547454e533331373301' + ), + HexBlob( + '8282582065375f2301b0fe4bed847138821af6401c36732cd5dbcf16f993d75c675e6dff10825839019ec46b264f72a1905c89cfc348c0b3530dbbcbe75dfc0f0473df753bb9416169cea3eb4cfc7f331b6e5f81b069495cf96c1730b7b0cfedb5821a002aae86a1581c90465e141ecb7b72ed0cdbcbd848673177cd52be5af5518e95d0de1db81e4b33444547454e5333313932014b33444547454e5333323032014b33444547454e5333323131014b33444547454e5333323139014b33444547454e5333323233014b33444547454e5333323332014b33444547454e5333323334014b33444547454e5333323633014b33444547454e5333323735014b33444547454e5333323834014b33444547454e5333333035014b33444547454e5333333430014b33444547454e5333333437014b33444547454e5333333630014b33444547454e5333333731014b33444547454e5333333738014b33444547454e5333343037014b33444547454e5333343130014b33444547454e5333343237014b33444547454e5333343837014b33444547454e5333343839014b33444547454e5333353035014b33444547454e5333353136014b33444547454e5333353330014b33444547454e5333353333014b33444547454e5333353735014b33444547454e5333353737014b33444547454e5333353833014b33444547454e5333363135014b33444547454e533336323001' + ), + HexBlob( + '8282582065375f2301b0fe4bed847138821af6401c36732cd5dbcf16f993d75c675e6dff11825839019ec46b264f72a1905c89cfc348c0b3530dbbcbe75dfc0f0473df753bb9416169cea3eb4cfc7f331b6e5f81b069495cf96c1730b7b0cfedb5821a002aae86a1581c90465e141ecb7b72ed0cdbcbd848673177cd52be5af5518e95d0de1db81e4b33444547454e5333363237014b33444547454e5333363337014b33444547454e5333363433014b33444547454e5333363737014b33444547454e5333363934014b33444547454e5333373039014b33444547454e5333373135014b33444547454e5333373231014b33444547454e5333373432014b33444547454e5333373839014b33444547454e5333373938014b33444547454e5333383131014b33444547454e5333383138014b33444547454e5333383233014b33444547454e5333383236014b33444547454e5333383331014b33444547454e5333383338014b33444547454e5333383431014b33444547454e5333383436014b33444547454e5333383631014b33444547454e5333383638014b33444547454e5333383735014b33444547454e5333383739014b33444547454e5333393337014b33444547454e5333393431014b33444547454e5333393539014b33444547454e5333393737014b33444547454e5333393933014b33444547454e5334303335014b33444547454e533430343201' + ), + HexBlob( + '8282582065375f2301b0fe4bed847138821af6401c36732cd5dbcf16f993d75c675e6dff12825839019ec46b264f72a1905c89cfc348c0b3530dbbcbe75dfc0f0473df753bb9416169cea3eb4cfc7f331b6e5f81b069495cf96c1730b7b0cfedb5821a002aae86a1581c90465e141ecb7b72ed0cdbcbd848673177cd52be5af5518e95d0de1db81e4b33444547454e5334303436014b33444547454e5334303536014b33444547454e5334313137014b33444547454e5334313330014b33444547454e5334313331014b33444547454e5334313435014b33444547454e5334313438014b33444547454e5334313938014b33444547454e5334323233014b33444547454e5334323737014b33444547454e5334323932014b33444547454e5334333135014b33444547454e5334333139014b33444547454e5334333232014b33444547454e5334333336014b33444547454e5334333431014b33444547454e5334333434014b33444547454e5334333631014b33444547454e5334333730014b33444547454e5334333838014b33444547454e5334333937014b33444547454e5334343032014b33444547454e5334343135014b33444547454e5334343238014b33444547454e5334343531014b33444547454e5334343535014b33444547454e5334343634014b33444547454e5334343636014b33444547454e5334343735014b33444547454e533435303301' + ), + HexBlob( + '8282582065375f2301b0fe4bed847138821af6401c36732cd5dbcf16f993d75c675e6dff13825839019ec46b264f72a1905c89cfc348c0b3530dbbcbe75dfc0f0473df753bb9416169cea3eb4cfc7f331b6e5f81b069495cf96c1730b7b0cfedb5821a002aae86a1581c90465e141ecb7b72ed0cdbcbd848673177cd52be5af5518e95d0de1db81e4b33444547454e5334353037014b33444547454e5334353130014b33444547454e5334353239014b33444547454e5334353434014b33444547454e5334353436014b33444547454e5334353437014b33444547454e5334353530014b33444547454e5334353636014b33444547454e5334353735014b33444547454e5334353736014b33444547454e5334353739014b33444547454e5334363233014b33444547454e5334363339014b33444547454e5334363534014b33444547454e5334363734014b33444547454e5334363930014b33444547454e5334363935014b33444547454e5334373036014b33444547454e5334373133014b33444547454e5334373534014b33444547454e5334373538014b33444547454e5334373938014b33444547454e5334383238014b33444547454e5334383339014b33444547454e5334383439014b33444547454e5334383636014b33444547454e5334383734014b33444547454e5334383930014b33444547454e5334383939014b33444547454e533439313801' + ), + HexBlob( + '8282582065375f2301b0fe4bed847138821af6401c36732cd5dbcf16f993d75c675e6dff15825839019ec46b264f72a1905c89cfc348c0b3530dbbcbe75dfc0f0473df753bb9416169cea3eb4cfc7f331b6e5f81b069495cf96c1730b7b0cfedb5821a002bee68a4581cba7adcbe329cb7eac17efdd6ec986ed6b6127281307ae7b15701d710a75443617264616e6f4c65747465727333373456564d015543617264616e6f4c65747465727332343833574c47015543617264616e6f4c65747465727337343130514459015543617264616e6f4c65747465727338313139524c58015543617264616e6f4c657474657273383938334e4f43015543617264616e6f4c65747465727339373232475650015643617264616e6f4c657474657273313438343053474b01581cbbfdef65fb7f28d64640b40f6b5fc95720daf1b776824a79e922d688a15046616861646f756b656e31304b34323101581cc2cd32fa237916eff6b74e8cc28aaa2ece9cf1ae53d9c113c36fc0f8a6514265727279426972746864617930303036015142657272794269727468646179303031390151426572727942697274686461793030383901514265727279426972746864617930313139015142657272794269727468646179303133320151426572727942697274686461793132313301581ccbbf660fab2d8846e34f4659de9024908cbcca36d80a62fc81f996f7a1564461696c79446f736553686974636f696e303030333301' + ), + HexBlob( + '8282582065375f2301b0fe4bed847138821af6401c36732cd5dbcf16f993d75c675e6dff16825839019ec46b264f72a1905c89cfc348c0b3530dbbcbe75dfc0f0473df753bb9416169cea3eb4cfc7f331b6e5f81b069495cf96c1730b7b0cfedb5821a002fbee4a8581cca58b06fb195890e84eceecbde4dde67384312128009639cacf8837da355467573696f6e48616c6f30323336367830303032390155467573696f6e48616c6f30363534377830373338380155467573696f6e48616c6f303833333778303538363501581cce298c6897535729964d729a465a159ce953dd05baadd27d10c8e033a34a4f646441726d79313935014a4f646441726d79343138014a4f646441726d7934323401581cd2063c54b55cd83ecd0d23d880b7d3ae628a230206c131e6e4748b88a24e44495954726f6f70657230313536014e44495954726f6f7065723032383901581cd436d9f6b754582f798fe33f4bed12133d47493f78b944b9cc55fd18a34f53756d6d69744c6f64676533393533014f53756d6d69744c6f64676533393637014f53756d6d69744c6f6467653430323201581cd5ac02157f1c4249f4671f397a3cd8424178054dca84c0ac8c2f4044a14b53454e42415a555255363301581cd8437545753daf7b607171d3f0eeacae6b011b29923493055bde5c78a14d4e46546974746965733034373901581cdee118864d89ffcd9d5cad9247c3a2d30e198543a410fd322d50f926a15447454e544f5048494c455370656369616c73313101581ce7a154cb78d62edd9e7683584c04de94248289a40aa5e8a8681fb7aca14b414f57584d41535330323401' + ), + HexBlob( + '8282582065375f2301b0fe4bed847138821af6401c36732cd5dbcf16f993d75c675e6dff1818825839019ec46b264f72a1905c89cfc348c0b3530dbbcbe75dfc0f0473df753bb9416169cea3eb4cfc7f331b6e5f81b069495cf96c1730b7b0cfedb5821a0029d3a8a1581cf0df8200b79d57d56afa0a7b9f232b4510d9948f972ce19075735acab253444547454e45545445534541534f4e303030350153444547454e45545445534541534f4e303232390153444547454e45545445534541534f4e303333370153444547454e45545445534541534f4e303430390153444547454e45545445534541534f4e303432360153444547454e45545445534541534f4e303437300153444547454e45545445534541534f4e303439360153444547454e45545445534541534f4e303536360153444547454e45545445534541534f4e303731370153444547454e45545445534541534f4e303838340153444547454e45545445534541534f4e303838390153444547454e45545445534541534f4e303930330153444547454e45545445534541534f4e303939390153444547454e45545445534541534f4e313034300153444547454e45545445534541534f4e313131310153444547454e45545445534541534f4e313135360153444547454e45545445534541534f4e313137300153444547454e45545445534541534f4e3131393301' + ), + HexBlob( + '8282582065375f2301b0fe4bed847138821af6401c36732cd5dbcf16f993d75c675e6dff1819825839019ec46b264f72a1905c89cfc348c0b3530dbbcbe75dfc0f0473df753bb9416169cea3eb4cfc7f331b6e5f81b069495cf96c1730b7b0cfedb5821a00242bc4a3581cf0ff48bbb7bbe9d59a40f1ce90e9e9d0ff5002ec48f232b49ca0fb9aa248756e69617374726f014d6469726563747061792e61646101581cf58e7f37c0bc5a9b0bc7fb7c5dfc11a5430a345981d4fd5d667ad47daa4d47454e544f5048494c45343533014e47454e544f5048494c4531313436014e47454e544f5048494c4531313533014e47454e544f5048494c4531383635014e47454e544f5048494c4532303933014e47454e544f5048494c4533353532014e47454e544f5048494c4533363932014e47454e544f5048494c4533383030014e47454e544f5048494c4533383433014e47454e544f5048494c453338393501581cf70c8350222f9707cc1ffcaf428bfd657f29e7b1de27374a9566cff8a255507572706c654465617468536b65746368303233330155507572706c654465617468536b657463683032393101' + ), + HexBlob( + '8282582065375f2301b0fe4bed847138821af6401c36732cd5dbcf16f993d75c675e6dff181a825839019ec46b264f72a1905c89cfc348c0b3530dbbcbe75dfc0f0473df753bb9416169cea3eb4cfc7f331b6e5f81b069495cf96c1730b7b0cfedb5821a00144178a1581cf97bb2ae7b056a17a63847fbe5032148353d30c980f5467f51f19637a34e41444150756e6b7a4d5650373937014f41444150756e6b7a4d565032333732014f41444150756e6b7a4d56503338393501' + ), + HexBlob( + '8282582065375f2301b0fe4bed847138821af6401c36732cd5dbcf16f993d75c675e6dff181c825839019ec46b264f72a1905c89cfc348c0b3530dbbcbe75dfc0f0473df753bb9416169cea3eb4cfc7f331b6e5f81b069495cf96c1730b7b0cfedb51a014e9965' + ), + HexBlob( + '8282582065375f2301b0fe4bed847138821af6401c36732cd5dbcf16f993d75c675e6dff181d825839019ec46b264f72a1905c89cfc348c0b3530dbbcbe75dfc0f0473df753bb9416169cea3eb4cfc7f331b6e5f81b069495cf96c1730b7b0cfedb51a00df10ee' + ), + HexBlob( + '8282582065375f2301b0fe4bed847138821af6401c36732cd5dbcf16f993d75c675e6dff181f825839019ec46b264f72a1905c89cfc348c0b3530dbbcbe75dfc0f0473df753bb9416169cea3eb4cfc7f331b6e5f81b069495cf96c1730b7b0cfedb51a006f8878' + ), + HexBlob( + '8282582065375f2301b0fe4bed847138821af6401c36732cd5dbcf16f993d75c675e6dff1820825839019ec46b264f72a1905c89cfc348c0b3530dbbcbe75dfc0f0473df753bb9416169cea3eb4cfc7f331b6e5f81b069495cf96c1730b7b0cfedb51a006f8877' + ), + HexBlob( + '8282582065375f2301b0fe4bed847138821af6401c36732cd5dbcf16f993d75c675e6dff1821825839019ec46b264f72a1905c89cfc348c0b3530dbbcbe75dfc0f0473df753bb9416169cea3eb4cfc7f331b6e5f81b069495cf96c1730b7b0cfedb51a006f8877' + ), + HexBlob( + '82825820adc2d9b0fbd9ca39081df9d0fcf92185c918761382b9881d27309afa8c3d897c01825839019ec46b264f72a1905c89cfc348c0b3530dbbcbe75dfc0f0473df753bb9416169cea3eb4cfc7f331b6e5f81b069495cf96c1730b7b0cfedb5821a00163a8ca1581c406cd2082f4ca575fdec9995202821ea101f3b9be03c19829b1cace3a54e53706c6974576f726c6433363933014e53706c6974576f726c6434353938014e53706c6974576f726c6436343933014e53706c6974576f726c6436373932014e53706c6974576f726c643638343901' + ), + HexBlob( + '828258209abd0c9d9de35a1e21d891f5b83c757a0cd20f427dfea273ac70cd3b07af6b6e01825839019ec46b264f72a1905c89cfc348c0b3530dbbcbe75dfc0f0473df753bb9416169cea3eb4cfc7f331b6e5f81b069495cf96c1730b7b0cfedb5821a00d2c72eb3581c684272bb723070545b52a9fc732f138c3bcb23cd06103d812527912ca458184e617574696c757352656453656154726f6f7065723030380158184e617574696c757352656453656154726f6f70657230393901581c4f6e6559656172416e6e697665727361727954726f6f70657230333201581d536c617368656453707261795061696e7454726f6f706572202330373401581c6cf682cf03c622a9b0de832ecfc5c026e8c092fe4f1057066bc7f50fa1494c6164796d6963653301581c6f3a7634e62c5daae02bcb6b5be34d30e72cf469a13ed2a2458c2154a350546564647954726f6f706572313337350150546564647954726f6f706572313836350150546564647954726f6f7065723436313701581c768659f8bc03c42d7db29841c58a966cffdf1b421b1fa23ad475d40ea14f414f5747594c3259414f573030313701581c76dbbc78587bf972c710f22a0807a6905a8a5e713418515fc9abeed1a14e434b53545544494f53303939363701581c854d968ac3052cb88ce711543deee668aa495ad19aae97a80a003fb5a1494d616e676f4275736801581c8ee78e40b4110fa2d44968b45cd2ade13b4af1057e59a9058d41f54fb451444547454e534541534f4e414c303038310151444547454e534541534f4e414c303038350151444547454e534541534f4e414c303133350151444547454e534541534f4e414c303134360151444547454e534541534f4e414c303137350151444547454e534541534f4e414c303231320151444547454e534541534f4e414c303233370151444547454e534541534f4e414c303235310151444547454e534541534f4e414c303435360151444547454e534541534f4e414c303531360151444547454e534541534f4e414c303631390151444547454e534541534f4e414c303638370151444547454e534541534f4e414c303639370151444547454e534541534f4e414c303739300151444547454e534541534f4e414c303838380151444547454e534541534f4e414c303935350151444547454e534541534f4e414c303936300151444547454e534541534f4e414c313039390151444547454e534541534f4e414c313137340151444547454e534541534f4e414c3132313201581c90465e141ecb7b72ed0cdbcbd848673177cd52be5af5518e95d0de1db85d4b33444547454e5330303032014b33444547454e5330303232014b33444547454e5330303236014b33444547454e5330303335014b33444547454e5330303432014b33444547454e5330303435014b33444547454e5330303732014b33444547454e5330303830014b33444547454e5330313230014b33444547454e5330313237014b33444547454e5330313630014b33444547454e5330313931014b33444547454e5330323035014b33444547454e5330323135014b33444547454e5330323139014b33444547454e5330323234014b33444547454e5330323238014b33444547454e5330323334014b33444547454e5330323433014b33444547454e5330323739014b33444547454e5330323939014b33444547454e5330333035014b33444547454e5330333037014b33444547454e5330333330014b33444547454e5330333432014b33444547454e5330333633014b33444547454e5330333737014b33444547454e5330333831014b33444547454e5330333839014b33444547454e5330343030014b33444547454e5331353037014b33444547454e5331353332014b33444547454e5331353334014b33444547454e5331353431014b33444547454e5331353432014b33444547454e5331353532014b33444547454e5331353635014b33444547454e5331353736014b33444547454e5331363035014b33444547454e5331363130014b33444547454e5331363131014b33444547454e5331363139014b33444547454e5331363331014b33444547454e5331363838014b33444547454e5331373233014b33444547454e5331373539014b33444547454e5331373638014b33444547454e5331373938014b33444547454e5331383130014b33444547454e5331383230014b33444547454e5331383232014b33444547454e5331383432014b33444547454e5331383436014b33444547454e5331383533014b33444547454e5331383737014b33444547454e5331383739014b33444547454e5331393030014b33444547454e5331393031014b33444547454e5331393139014b33444547454e5331393430014b33444547454e5332343035014b33444547454e5332343235014b33444547454e5332343239014b33444547454e5332343335014b33444547454e5332343736014b33444547454e5332343932014b33444547454e5332353032014b33444547454e5332353037014b33444547454e5332353237014b33444547454e5332353334014b33444547454e5332353530014b33444547454e5332353734014b33444547454e5332353831014b33444547454e5332353834014b33444547454e5332353930014b33444547454e5332353933014b33444547454e5332363030014b33444547454e5332363435014b33444547454e5332363535014b33444547454e5332363838014b33444547454e5332363935014b33444547454e5332363938014b33444547454e5332373032014b33444547454e5332373238014b33444547454e5332373539014b33444547454e5332373738014b33444547454e5332373830014b33444547454e5332373937014b33444547454e5332383135014b33444547454e5332383138014b33444547454e5334393239014b33444547454e5334393533014b33444547454e533439363201581c94ff68c23008fe6403c4f57f8796004141af5c37f788e3d5a2951b5ba154415a555253756e6461655377617042726f6e7a6501581c98b6216ceb2b8cce6d4c0f90d7f6dbd9a5e96fd349246ab4d2cc6808a15750726f6f666f66504453746174756545646974696f6e3101581c9def2b8de3736fdbd611109878e3ac44f46c352ae51961ea34f0d296a15246616861646f756b656e31304b763234343501581ca134724e20a26031a75ca1bc8effc60d3beb667c449c95d91587b137a157486f736b696e736f6e323032325768697465626f61726401581cab12b275ce3a39a0a03576f8903d7c770b39ccb2a00d10d088a877e6a44948616c6f3031323139014948616c6f3032333331014948616c6f3032333636014948616c6f303237323001581cad36b288d7192c8258210f437bc17f4da306122eedb619a26f2e3b00a1534461696c79446f73654144414a616d7330303701581cafa25c8d9a5725e33dbe28f57923a0e77989532c50bbfdf942862be3a4524461696c79446f7365484e5452617265303501544461696c79446f7365484e54436f6d6d6f6e313501564461696c79446f7365484e54556e636f6d6d6f6e303401574461696c79446f7365434f5449556e636f6d6d6f6e303601581cb0b9708323e0350cd31fba93214709407b024799f290c0acfac2ef9fa15243617264616e6f4368616d656c656f6e333201581cb9625c53d517ca5106e66322079ab5aea0551a7a22caacca36abd713a14a446567656e426f79444401581cdd589bbcfa48c9a133a22e205da33a5d07ef79dac1f8d5d8067b1004a9517768657265734f7262697457616c646f3501537768657265735765726e697357616c646f3332015577686572657357616c646f54726f6f70657233323301577768657265734164616e6175747357616c646f313834310157776865726573426c6f636b4f776c7357616c646f373832015777686572657346617374536f636965747957616c646f32015777686572657357696c6454616e677a57616c646f3339350158187768657265734579654f665468654b696e6757616c646f3601581c77686572657343617264616e6f50726f7869657357616c646f31373401581ce018c111d34ba8ab1ffc5e9dced251c261f7eb2cbbcde887a8d16086a64a44434358434b30333231014a44434358434b30343536014a44434358434b30353537014a44434358434b31313731014a44434358434b31313738014a44434358434b3133363601' + ), + HexBlob( + '828258209abd0c9d9de35a1e21d891f5b83c757a0cd20f427dfea273ac70cd3b07af6b6e02825839019ec46b264f72a1905c89cfc348c0b3530dbbcbe75dfc0f0473df753bb9416169cea3eb4cfc7f331b6e5f81b069495cf96c1730b7b0cfedb51a01611a4d' + ) +]; + +export const getCoreUtxosFromCbor = (serializedUtxos: Array) => { + const utxos = new Set(); + + for (const entry of serializedUtxos) { + const utxo = Serialization.TransactionUnspentOutput.fromCbor(entry); + utxos.add(utxo.toCore() as unknown as Cardano.Utxo); + } + + return utxos; +}; + +export const txEvaluator = { + evaluate: async (_: Cardano.Tx, __: Array) => [] +}; + +export const txBuilder = async (selection: SelectionSkeleton) => { + const newTx = { ...mockTx }; + newTx.body.inputs = [...selection.inputs].map((utxo) => utxo[0]); + newTx.body.outputs = [...selection.outputs, ...selection.change]; + newTx.body.fee = selection.fee; + + return newTx; +};