Skip to content

Commit 7a08c8f

Browse files
AngelCastilloBmkazlauskas
authored andcommitted
test: add a unit test to create and sign a transaction that transfer 300 assets
1 parent 5c6568c commit 7a08c8f

File tree

5 files changed

+148
-3
lines changed

5 files changed

+148
-3
lines changed

Diff for: packages/util-dev/src/dataGeneration.ts

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/**
2+
* Generates a random byte array in hexadecimal value.
3+
*
4+
* @param size The size of the hex string in bytes.
5+
*/
6+
export const generateRandomHexString = (size: number) =>
7+
[...Array.from({ length: size })]
8+
.map(() => Math.floor(Math.random() * 16).toString(16))
9+
.join('')
10+
.toLowerCase();
11+
12+
/**
13+
* Generates a random BigInt number between two values.
14+
*
15+
* @param min The minimum value.
16+
* @param max The maximum value.
17+
*/
18+
export const generateRandomBigInt = (min: number, max: number): bigint =>
19+
BigInt(Math.floor(Math.random() * (max + 1 - min) + min));

Diff for: packages/util-dev/src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ export * from './stubLogger';
88
export * from './testScheduler';
99
export * from './createStubUtxoProvider';
1010
export * from './createGenericMockServer';
11+
export * from './dataGeneration';

Diff for: packages/util-dev/test/dataGeneration.test.ts

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { generateRandomBigInt, generateRandomHexString } from '../src';
2+
3+
describe('dataGeneration', () => {
4+
describe('generateRandomHexString', () => {
5+
it('generates a valid hex string', () => {
6+
const hex = generateRandomHexString(10);
7+
expect(!Number.isNaN(Number(`0x${hex}`))).toBeTruthy();
8+
});
9+
it('generates hex string of the correct size', () => {
10+
const hex = generateRandomHexString(10);
11+
expect(hex.length).toEqual(10);
12+
});
13+
});
14+
describe('generateRandomBigInt', () => {
15+
it('generates a bigint between the given range', () => {
16+
const bigInt = generateRandomBigInt(10_000, 20_000);
17+
expect(bigInt).toBeLessThanOrEqual(20_000);
18+
expect(bigInt).toBeGreaterThanOrEqual(10_000);
19+
});
20+
});
21+
});

Diff for: packages/wallet/test/SingleAddressWallet/load.test.ts

+103-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,13 @@
22
/* eslint-disable @typescript-eslint/no-explicit-any */
33
import * as mocks from '../mocks';
44
import { AddressType, GroupedAddress } from '@cardano-sdk/key-management';
5-
import { AssetId, createStubStakePoolProvider, somePartialStakePools } from '@cardano-sdk/util-dev';
5+
import {
6+
AssetId,
7+
createStubStakePoolProvider,
8+
generateRandomBigInt,
9+
generateRandomHexString,
10+
somePartialStakePools
11+
} from '@cardano-sdk/util-dev';
612
import {
713
Cardano,
814
ChainHistoryProvider,
@@ -165,6 +171,62 @@ const assertWalletProperties2 = async (wallet: ObservableWallet) => {
165171
expect(rewardAccounts[0].rewardBalance).toBe(mocks.rewardAccountBalance2);
166172
};
167173

174+
/**
175+
* Generates a set of UTXOs matching the given parameters.
176+
*
177+
* @param utxoCount The number of UTXOs to be generated.
178+
* @param assetsPerUtxo The number of Assets per UTXO.
179+
*/
180+
const generateUtxos = (utxoCount: number, assetsPerUtxo: number): Cardano.Utxo[] => {
181+
const utxos: Cardano.Utxo[] = [];
182+
183+
for (let utxoIndex = 0; utxoIndex < utxoCount; ++utxoIndex) {
184+
const utxo: Cardano.Utxo = [
185+
{
186+
address,
187+
index: 0,
188+
txId: Cardano.TransactionId(generateRandomHexString(64))
189+
},
190+
{
191+
address,
192+
value: {
193+
assets: new Map(),
194+
coins: generateRandomBigInt(1_000_000, 9_999_999_000_000) // from 1 tADA to 9.999.999 tADA
195+
}
196+
}
197+
];
198+
for (let assetIndex = 0; assetIndex < assetsPerUtxo; ++assetIndex) {
199+
utxo[1].value!.assets!.set(Cardano.AssetId(generateRandomHexString(72)), generateRandomBigInt(1, 1000));
200+
}
201+
202+
utxos.push(utxo);
203+
}
204+
205+
return utxos;
206+
};
207+
208+
/**
209+
* Gets the asset list and the total amount of lovelace on a utxo set.
210+
*
211+
* @param utxos The utxos.
212+
* @returns The total lovelace and the aggregated asset set.
213+
*/
214+
const getAssetsFromUtxos = (utxos: Cardano.Utxo[]) => {
215+
const values = utxos.map((utxo) => utxo[1].value);
216+
let totalLovelace = 0n;
217+
const totalTokens = new Map();
218+
219+
for (const value of values) {
220+
totalLovelace += value.coins;
221+
222+
for (const [key, val] of value.assets!.entries()) {
223+
totalTokens.set(key, val);
224+
}
225+
}
226+
227+
return { totalLovelace, totalTokens };
228+
};
229+
168230
describe('SingleAddressWallet load', () => {
169231
it('loads all properties from provider, stores them and restores on subsequent load, fetches new data', async () => {
170232
const stores = createInMemoryWalletStores();
@@ -288,3 +350,43 @@ describe('SingleAddressWallet load', () => {
288350
wallet.shutdown();
289351
});
290352
});
353+
354+
describe('SingleAddressWallet creates big UTXO', () => {
355+
it('creates an UTXO with 300 hundred mixed assets coming from several inputs', async () => {
356+
const stores = createInMemoryWalletStores();
357+
const utxoSet = generateUtxos(30, 10);
358+
const totalAssets = getAssetsFromUtxos(utxoSet);
359+
360+
const wallet = await createWallet(stores, {
361+
chainHistoryProvider: mocks.mockChainHistoryProvider(),
362+
networkInfoProvider: mocks.mockNetworkInfoProvider(),
363+
rewardsProvider: mocks.mockRewardsProvider(),
364+
utxoProvider: mocks.mockUtxoProvider(utxoSet)
365+
});
366+
367+
const txProps = {
368+
outputs: new Set([
369+
{
370+
address,
371+
value: {
372+
assets: totalAssets.totalTokens,
373+
coins: totalAssets.totalLovelace - 10_000_000n // Leave some tADA available for fees
374+
}
375+
}
376+
])
377+
};
378+
379+
const unsignedTx = await wallet.initializeTx(txProps);
380+
381+
const finalizeProps = {
382+
tx: unsignedTx
383+
};
384+
385+
const signedTx = await wallet.finalizeTx(finalizeProps);
386+
387+
const nonChangeOutput = signedTx.body.outputs.find((out) => out.value!.assets!.size > 0);
388+
expect(nonChangeOutput!.value.assets).toBe(totalAssets.totalTokens);
389+
390+
wallet.shutdown();
391+
});
392+
});

Diff for: packages/wallet/test/mocks/mockUtxoProvider.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,13 @@ export const utxo2 = utxo.slice(1);
6666
/**
6767
* Provider stub for testing
6868
*
69+
* @param utxoSet The set of UTXOs to be included in the wallet state.
70+
*
6971
* returns UtxoProvider-compatible object
7072
*/
71-
export const mockUtxoProvider = (): UtxoProvider => ({
73+
export const mockUtxoProvider = (utxoSet?: Cardano.Utxo[]): UtxoProvider => ({
7274
healthCheck: jest.fn().mockResolvedValue({ ok: true }),
73-
utxoByAddresses: jest.fn().mockResolvedValue(utxo)
75+
utxoByAddresses: jest.fn().mockResolvedValue(utxoSet ? utxoSet : utxo)
7476
});
7577

7678
export const mockUtxoProvider2 = (delayMs: number): UtxoProvider => {

0 commit comments

Comments
 (0)