diff --git a/packages/core/src/TxMetadata/index.ts b/packages/core/src/TxMetadata/index.ts deleted file mode 100644 index ad03271545d..00000000000 --- a/packages/core/src/TxMetadata/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './cip20'; diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index ec00c92aa55..9634e719a55 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -1,7 +1,6 @@ export * as Asset from './Asset'; export * as Cardano from './Cardano'; export * as Serialization from './Serialization'; -export * as TxMetadata from './TxMetadata'; export * from './Provider'; export * from './util'; export * from './errors'; diff --git a/packages/core/test/TxMetadata/cip20.test.ts b/packages/core/test/TxMetadata/cip20.test.ts deleted file mode 100644 index d03a207d29c..00000000000 --- a/packages/core/test/TxMetadata/cip20.test.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { - CIP_20_METADATUM_LABEL, - MessageValidationError, - MessageValidationFailure, - toCIP20Metadata, - validateMessage -} from '../../src/TxMetadata'; -import { Cardano } from '../../src'; -import { TxMetadata } from '../../src/Cardano'; - -describe('TxMetadata.cip20', () => { - const compliantShortMessage = 'Lorem ipsum dolor'; - const compliantMaxMessage = 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean'; - const oversizeMessage = `${compliantMaxMessage}1`; - describe('validateMessage', () => { - it('validates a CIP-20 message if a string and less than or equal to 64 bytes', () => { - expect(validateMessage(compliantShortMessage)).toStrictEqual({ valid: true }); - expect(validateMessage(compliantMaxMessage)).toStrictEqual({ valid: true }); - }); - it('invalidates a CIP-20 message if a string but over 64 bytes', () => { - expect(validateMessage(oversizeMessage)).toStrictEqual({ - failure: MessageValidationFailure.oversize, - valid: false - }); - }); - it('invalidates a CIP-20 message if wrong type', () => { - expect(validateMessage(1 as unknown as string)).toStrictEqual({ - failure: MessageValidationFailure.wrongType, - valid: false - }); - expect(validateMessage({ message: compliantShortMessage } as unknown as string)).toStrictEqual({ - failure: MessageValidationFailure.wrongType, - valid: false - }); - expect(validateMessage([compliantShortMessage] as unknown as string)).toStrictEqual({ - failure: MessageValidationFailure.wrongType, - valid: false - }); - expect( - validateMessage(new Map([[CIP_20_METADATUM_LABEL, compliantShortMessage]]) as unknown as string) - ).toStrictEqual({ failure: MessageValidationFailure.wrongType, valid: false }); - }); - }); - describe('toCIP20Metadata', () => { - describe('args object', () => { - it('produces a CIP-20-compliant TxMetadata map', () => { - const metadata = toCIP20Metadata({ messages: [compliantShortMessage] }) as TxMetadata; - expect(metadata.has(CIP_20_METADATUM_LABEL)).toBe(true); - const cip20Metadata = metadata.get(CIP_20_METADATUM_LABEL) as Cardano.MetadatumMap; - expect(cip20Metadata.get('msg')).toStrictEqual([compliantShortMessage]); - }); - it('throws an error if any messages are invalid', () => { - expect(() => - toCIP20Metadata({ - messages: [compliantShortMessage, compliantMaxMessage, oversizeMessage] - }) - ).toThrowError(MessageValidationError); - }); - }); - describe('producing a CIP-20-compliant TxMetadata map with a string arg', () => { - test('larger than 64 bytes', () => { - const metadata = toCIP20Metadata(oversizeMessage) as TxMetadata; - expect(metadata.has(CIP_20_METADATUM_LABEL)).toBe(true); - const cip20Metadata = metadata.get(CIP_20_METADATUM_LABEL) as Cardano.MetadatumMap; - expect((cip20Metadata.get('msg') as string[]).length).toBe(2); - }); - test('equal to 64 bytes', () => { - const metadata = toCIP20Metadata(compliantMaxMessage) as TxMetadata; - expect(metadata.has(CIP_20_METADATUM_LABEL)).toBe(true); - const cip20Metadata = metadata.get(CIP_20_METADATUM_LABEL) as Cardano.MetadatumMap; - expect((cip20Metadata.get('msg') as string[]).length).toBe(1); - }); - test('smaller than to 64 bytes', () => { - const metadata = toCIP20Metadata(compliantShortMessage) as TxMetadata; - expect(metadata.has(CIP_20_METADATUM_LABEL)).toBe(true); - const cip20Metadata = metadata.get(CIP_20_METADATUM_LABEL) as Cardano.MetadatumMap; - expect((cip20Metadata.get('msg') as string[]).length).toBe(1); - }); - }); - }); -}); diff --git a/packages/tx-construction/src/index.ts b/packages/tx-construction/src/index.ts index ed9c9120ae7..0335612f361 100644 --- a/packages/tx-construction/src/index.ts +++ b/packages/tx-construction/src/index.ts @@ -3,6 +3,7 @@ export * from './fees'; export * from './input-selection'; export * from './output-validation'; export * from './tx-builder'; +export * from './tx-metadata'; export * from './ensureValidityInterval'; export * from './types'; export * from './computeScriptDataHash'; diff --git a/packages/core/src/TxMetadata/cip20.ts b/packages/tx-construction/src/tx-metadata/cip20.ts similarity index 78% rename from packages/core/src/TxMetadata/cip20.ts rename to packages/tx-construction/src/tx-metadata/cip20.ts index 92ee22e017f..cac16aa979f 100644 --- a/packages/core/src/TxMetadata/cip20.ts +++ b/packages/tx-construction/src/tx-metadata/cip20.ts @@ -1,8 +1,8 @@ +import { Cardano } from '@cardano-sdk/core'; import { CustomError } from 'ts-custom-error'; import { StringUtils } from '@cardano-sdk/util'; -import { TxMetadata } from '../Cardano'; -export const CIP_20_METADATUM_LABEL = 674n; +export const METADATUM_LABEL = 674n; const MAX_BYTES = 64; export enum MessageValidationFailure { @@ -15,14 +15,14 @@ export type MessageValidationResult = { failure?: MessageValidationFailure; }; -export type CIP20TxMetadataMessage = string; +export type TxMetadataMessage = string; -export type CIP20TxMetadataArgs = { +export type TxMetadataArgs = { // An array of message strings, limited to 64 bytes each - messages: CIP20TxMetadataMessage[]; + messages: TxMetadataMessage[]; }; -export type ValidationResultMap = Map; +export type ValidationResultMap = Map; export class MessageValidationError extends CustomError { public constructor(failures: ValidationResultMap) { @@ -49,11 +49,11 @@ export const validateMessage = (entry: unknown): MessageValidationResult => { * Converts an object containing an array of individual messages into https://cips.cardano.org/cip/CIP-20 compliant * transaction metadata * - * @param args CIP20TxMetadataArgs or a string to be transformed into an array + * @param args Object containing a message property or a string to be transformed into an array * @returns CIP20-compliant transaction metadata * @throws Message validation error containing details. Use validateMessage to independently check each message before calling this function */ -export const toCIP20Metadata = (args: CIP20TxMetadataArgs | string): TxMetadata => { +export const toTxMetadata = (args: TxMetadataArgs | string): Cardano.TxMetadata => { const messages = typeof args === 'string' ? StringUtils.chunkByBytes(args, MAX_BYTES) : args.messages; const invalidMessages: ValidationResultMap = new Map(); for (const message of messages) { @@ -61,5 +61,5 @@ export const toCIP20Metadata = (args: CIP20TxMetadataArgs | string): TxMetadata if (!result.valid) invalidMessages.set(message, result); } if (invalidMessages.size > 0) throw new MessageValidationError(invalidMessages); - return new Map([[CIP_20_METADATUM_LABEL, new Map([['msg', messages]])]]); + return new Map([[METADATUM_LABEL, new Map([['msg', messages]])]]); }; diff --git a/packages/tx-construction/src/tx-metadata/index.ts b/packages/tx-construction/src/tx-metadata/index.ts new file mode 100644 index 00000000000..a31fc0aba07 --- /dev/null +++ b/packages/tx-construction/src/tx-metadata/index.ts @@ -0,0 +1 @@ +export * as CIP20 from './cip20'; diff --git a/packages/tx-construction/test/tx-metadata/cip20.test.ts b/packages/tx-construction/test/tx-metadata/cip20.test.ts new file mode 100644 index 00000000000..801b78ff6f3 --- /dev/null +++ b/packages/tx-construction/test/tx-metadata/cip20.test.ts @@ -0,0 +1,74 @@ +import { CIP20 } from '../../src'; +import { Cardano } from '@cardano-sdk/core'; + +describe('CIP20', () => { + const compliantShortMessage = 'Lorem ipsum dolor'; + const compliantMaxMessage = 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean'; + const oversizeMessage = `${compliantMaxMessage}1`; + describe('validateMessage', () => { + it('validates a CIP-20 message if a string and less than or equal to 64 bytes', () => { + expect(CIP20.validateMessage(compliantShortMessage)).toStrictEqual({ valid: true }); + expect(CIP20.validateMessage(compliantMaxMessage)).toStrictEqual({ valid: true }); + }); + it('invalidates a CIP-20 message if a string but over 64 bytes', () => { + expect(CIP20.validateMessage(oversizeMessage)).toStrictEqual({ + failure: CIP20.MessageValidationFailure.oversize, + valid: false + }); + }); + it('invalidates a CIP-20 message if wrong type', () => { + expect(CIP20.validateMessage(1 as unknown as string)).toStrictEqual({ + failure: CIP20.MessageValidationFailure.wrongType, + valid: false + }); + expect(CIP20.validateMessage({ message: compliantShortMessage } as unknown as string)).toStrictEqual({ + failure: CIP20.MessageValidationFailure.wrongType, + valid: false + }); + expect(CIP20.validateMessage([compliantShortMessage] as unknown as string)).toStrictEqual({ + failure: CIP20.MessageValidationFailure.wrongType, + valid: false + }); + expect( + CIP20.validateMessage(new Map([[CIP20.METADATUM_LABEL, compliantShortMessage]]) as unknown as string) + ).toStrictEqual({ failure: CIP20.MessageValidationFailure.wrongType, valid: false }); + }); + }); + describe('toTxMetadata', () => { + describe('args object', () => { + it('produces a CIP20-compliant TxMetadata map', () => { + const metadata = CIP20.toTxMetadata({ messages: [compliantShortMessage] }) as Cardano.TxMetadata; + expect(metadata.has(CIP20.METADATUM_LABEL)).toBe(true); + const cip20Metadata = metadata.get(CIP20.METADATUM_LABEL) as Cardano.MetadatumMap; + expect(cip20Metadata.get('msg')).toStrictEqual([compliantShortMessage]); + }); + it('throws an error if any messages are invalid', () => { + expect(() => + CIP20.toTxMetadata({ + messages: [compliantShortMessage, compliantMaxMessage, oversizeMessage] + }) + ).toThrowError(CIP20.MessageValidationError); + }); + }); + describe('produces a CIP20-compliant TxMetadata map with a string arg', () => { + test('larger than 64 bytes', () => { + const metadata = CIP20.toTxMetadata(oversizeMessage) as Cardano.TxMetadata; + expect(metadata.has(CIP20.METADATUM_LABEL)).toBe(true); + const cip20Metadata = metadata.get(CIP20.METADATUM_LABEL) as Cardano.MetadatumMap; + expect((cip20Metadata.get('msg') as string[]).length).toBe(2); + }); + test('equal to 64 bytes', () => { + const metadata = CIP20.toTxMetadata(compliantMaxMessage) as Cardano.TxMetadata; + expect(metadata.has(CIP20.METADATUM_LABEL)).toBe(true); + const cip20Metadata = metadata.get(CIP20.METADATUM_LABEL) as Cardano.MetadatumMap; + expect((cip20Metadata.get('msg') as string[]).length).toBe(1); + }); + test('smaller than to 64 bytes', () => { + const metadata = CIP20.toTxMetadata(compliantShortMessage) as Cardano.TxMetadata; + expect(metadata.has(CIP20.METADATUM_LABEL)).toBe(true); + const cip20Metadata = metadata.get(CIP20.METADATUM_LABEL) as Cardano.MetadatumMap; + expect((cip20Metadata.get('msg') as string[]).length).toBe(1); + }); + }); + }); +});