From ea7c3ca3009ec6aaf161505165af8c9a2481bbb2 Mon Sep 17 00:00:00 2001 From: Vanessa Date: Tue, 30 May 2023 14:29:22 +0100 Subject: [PATCH] fix: types and test from koralabshandleprovider --- .../src/tx-builder/OutputBuilder.ts | 25 ++++++++++--- .../tx-construction/src/tx-builder/types.ts | 9 ++++- .../test/tx-builder/TxBuilder.test.ts | 36 +++++++++++++------ 3 files changed, 53 insertions(+), 17 deletions(-) diff --git a/packages/tx-construction/src/tx-builder/OutputBuilder.ts b/packages/tx-construction/src/tx-builder/OutputBuilder.ts index f0e893746af..273e79dda4e 100644 --- a/packages/tx-construction/src/tx-builder/OutputBuilder.ts +++ b/packages/tx-construction/src/tx-builder/OutputBuilder.ts @@ -3,11 +3,13 @@ import { Hash32ByteBase16 } from '@cardano-sdk/crypto'; import { Logger } from 'ts-log'; import { + InvalidConfigurationError, OutputBuilder, OutputBuilderTxOut, OutputValidationMinimumCoinError, OutputValidationMissingRequiredError, OutputValidationTokenBundleSizeError, + TxOutputFailure, PartialTxOut } from './types'; import { OutputValidation, OutputValidator } from '../output-validation'; @@ -23,11 +25,12 @@ export interface OutputBuilderProps { /** Logger */ logger: Logger; /** Handle Provider for resolving addresses */ - handleProvider: HandleProvider; + handleProvider?: HandleProvider; } /** Determines if the `PartialTxOut` arg has at least an address and coins. */ -const isViableTxOut = (txOut: PartialTxOut): txOut is Cardano.TxOut => !!(txOut?.address && txOut?.value?.coins); +const isViableTxOut = (txOut: PartialTxOut): txOut is Cardano.TxOut => + !!((txOut?.address || txOut?.handle) && txOut?.value?.coins); /** * Transforms from `OutputValidation` type emitted by `OutputValidator`, to @@ -56,13 +59,16 @@ export class TxOutputBuilder implements OutputBuilder { #partialOutput: PartialTxOut; #outputValidator: OutputBuilderValidator; #logger: Logger; - #handleProvider: HandleProvider; + #handleProvider: HandleProvider | null = null; constructor({ outputValidator, txOut, logger, handleProvider }: OutputBuilderProps) { this.#partialOutput = { ...txOut }; this.#outputValidator = outputValidator; this.#logger = logger; - this.#handleProvider = handleProvider; + + if (handleProvider) { + this.#handleProvider = handleProvider; + } } /** @@ -122,6 +128,10 @@ export class TxOutputBuilder implements OutputBuilder { } handle(handle: Handle): OutputBuilder { + if (!this.#handleProvider) { + throw new InvalidConfigurationError(TxOutputFailure.MissingHandleProviderError); + } + this.#partialOutput = { ...this.#partialOutput, handle }; return this; } @@ -134,11 +144,16 @@ export class TxOutputBuilder implements OutputBuilder { throw outputValidation; } - if (this.#partialOutput.handle) { + if (this.#partialOutput.handle && this.#handleProvider) { const resolution = await this.#handleProvider.resolveHandles({ handles: [this.#partialOutput.handle] }); if (resolution[0] !== null) { txOut.handle = resolution[0]; + txOut.address = resolution[0].resolvedAddresses.cardano; + } else { + // The an error because the handle resolved to null so we don't have + // an address for the transaction. + throw new OutputValidationMissingRequiredError(this.#partialOutput); } } diff --git a/packages/tx-construction/src/tx-builder/types.ts b/packages/tx-construction/src/tx-builder/types.ts index f6385384f74..0b72dc68ea2 100644 --- a/packages/tx-construction/src/tx-builder/types.ts +++ b/packages/tx-construction/src/tx-builder/types.ts @@ -20,7 +20,14 @@ export type PartialTxOut = Partial< export enum TxOutputFailure { MinimumCoin = 'Minimum coin not met', TokenBundleSizeExceedsLimit = 'Token Bundle Exceeds Limit', - MissingRequiredFields = 'Mandatory fields address or coin are missing' + MissingRequiredFields = 'Mandatory fields address or coin are missing', + MissingHandleProviderError = "Missing 'HandleProvider'" +} + +export class InvalidConfigurationError extends CustomError { + public constructor(public message: string) { + super(message); + } } export class OutputValidationMissingRequiredError extends CustomError { diff --git a/packages/tx-construction/test/tx-builder/TxBuilder.test.ts b/packages/tx-construction/test/tx-builder/TxBuilder.test.ts index 44127d573ac..5dfe4444ca5 100644 --- a/packages/tx-construction/test/tx-builder/TxBuilder.test.ts +++ b/packages/tx-construction/test/tx-builder/TxBuilder.test.ts @@ -46,6 +46,7 @@ describe('GenericTxBuilder', () => { let outputValidator: jest.Mocked; let txBuilder: GenericTxBuilder; let txBuilderWithHandleErrors: GenericTxBuilder; + let txBuilderWithNullHandles: GenericTxBuilder; let txBuilderProviders: jest.Mocked; let output: Cardano.TxOut; let output2: Cardano.TxOut; @@ -101,6 +102,17 @@ describe('GenericTxBuilder', () => { outputValidator, txBuilderProviders }); + txBuilderWithNullHandles = new GenericTxBuilder({ + handleProvider: { + healthCheck: jest.fn(), + resolveHandles: async () => [null] + }, + inputResolver, + keyAgent: util.createAsyncKeyAgent(keyAgent), + logger: dummyLogger, + outputValidator, + txBuilderProviders + }); txBuilderWithHandleErrors = new GenericTxBuilder({ handleProvider: { healthCheck: jest.fn(), @@ -395,20 +407,22 @@ describe('GenericTxBuilder', () => { }); it('resolves handle to address', async () => { - const outputBuilderTx = await txBuilder - .buildOutput() - .address(address) - .handle('alice') - .coin(output1Coin) - .build(); - - expect(outputBuilderTx.handle).toBe(resolvedHandle); + const txOut = await txBuilder.buildOutput().handle('alice').coin(output1Coin).build(); + + expect(txOut.handle).toBe(resolvedHandle); + expect(txOut.address).toBe(resolvedHandle.resolvedAddresses.cardano); + }); + + it('rejects with an error when a handle is not found', async () => { + await expect( + txBuilderWithNullHandles.buildOutput().handle('alice').coin(output1Coin).build() + ).rejects.toThrowError(OutputValidationMissingRequiredError); }); - it('rejects with an error when handle resolution fails', async () => { + it('rejects with an error when handle is not found', async () => { await expect( - txBuilderWithHandleErrors.buildOutput().address(address).handle('alice').coin(output1Coin).build() - ).rejects.toThrowError(/NOT_FOUND/); + txBuilderWithHandleErrors.buildOutput().handle('alice').coin(output1Coin).build() + ).rejects.toThrowError(ProviderError); }); });