diff --git a/src/errors/parseError.ts b/src/errors/parseError.ts index caf152c..0362710 100644 --- a/src/errors/parseError.ts +++ b/src/errors/parseError.ts @@ -1,17 +1,14 @@ export enum ParseErrorReason { - INVALID_ADDRESS = 'Invalid address', - INVALID_REWARD_ACCOUNT = 'Invalid reward account', INVALID_COIN = 'Invalid coin', - INVALID_EPOCH = 'Invalid epoch', - - INVALID_POLICY_ID = 'Invalid policy id', - INVALID_ASSET_NAME = 'Invalid asset name', - INVALID_MULTIASSET = 'Invalid multiasset map', INVALID_TRANSACTION_ID = 'Invalid transaction id', INVALID_TX_INPUT_INDEX = 'Invalid transaction input index', INVALID_TX_INPUT = 'Invalid transaction input', + INVALID_TX_INPUTS = 'Invalid transaction inputs', + INVALID_POLICY_ID = 'Invalid policy id', + INVALID_ASSET_NAME = 'Invalid asset name', + INVALID_MULTIASSET = 'Invalid multiasset map', INVALID_OUTPUT_ADDRESS = 'Invalid output address', INVALID_OUTPUT_AMOUNT = 'Invalid output amount', INVALID_OUTPUT_MULTIASSET = 'Invalid output multiasset', @@ -21,6 +18,11 @@ export enum ParseErrorReason { INVALID_OUTPUT_DATUM = 'Invalid output datum', INVALID_OUTPUT_REFERENCE_SCRIPT = 'Invalid output reference script', INVALID_TX_OUTPUT = 'Invalid transaction output', + INVALID_TX_OUTPUTS = 'Invalid transaction outputs', + + INVALID_FEE = 'Invalid transaction fee', + + INVALID_TTL = 'Invalid transaction ttl', INVALID_CERTIFICATE_TYPE = 'Invalid certificate type', INVALID_CERTIFICATE = 'Invalid certificate', @@ -46,52 +48,58 @@ export enum ParseErrorReason { INVALID_POOL_METADATA_URL = 'Invalid pool metadata URL', INVALID_POOL_METADATA_METADATA_HASH = 'Invalid pool metadata metadata hash', INVALID_POOL_METADATA = 'Invalid pool metadata', + INVALID_EPOCH = 'Invalid epoch', INVALID_DREP_TYPE = 'Invalid DRep type', INVALID_DREP = 'Invalid DRep', INVALID_ANCHOR = 'Invalid anchor', INVALID_ANCHOR_URL = 'Invalid anchor URL', INVALID_ANCHOR_DATA_HASH = 'Invalid anchor data hash', + INVALID_CERTIFICATES = 'Invalid transaction certificates', INVALID_WITHDRAWAL_AMOUNT = 'Invalid withdrawal amount', - - INVALID_MINT_AMOUNT = 'Invalid mint amount', - - INVALID_COLLATERAL_INPUT_INDEX = 'Invalid transaction collateral input index', - INVALID_COLLATERAL_INPUT = 'Invalid transaction collateral input', - - INVALID_REFERENCE_INPUT_INDEX = 'Invalid transaction reference input index', - INVALID_REFERENCE_INPUT = 'Invalid transaction reference input', - - INVALID_TX_BODY_CBOR = 'Invalid transaction body CBOR', - INVALID_TX_BODY_UNKNOWN_ITEMS = 'Transaction body contains unknown items', - INVALID_TX_INPUTS = 'Invalid transaction inputs', - INVALID_TX_OUTPUTS = 'Invalid transaction outputs', - INVALID_FEE = 'Invalid transaction fee', - INVALID_TTL = 'Invalid transaction ttl', - INVALID_CERTIFICATES = 'Invalid transaction certificates', + INVALID_REWARD_ACCOUNT = 'Invalid reward account', INVALID_WITHDRAWALS = 'Invalid transaction withdrawals', + INVALID_AUXILIARY_DATA_HASH = 'Invalid transaction auxiliary data hash', + INVALID_VALIDITY_INTERVAL_START = 'Invalid transaction validity interval start', + + INVALID_MINT_AMOUNT = 'Invalid mint amount', INVALID_MINT = 'Invalid transaction mint', + INVALID_SCRIPT_DATA_HASH = 'Invalid transaction script data hash', + + INVALID_COLLATERAL_INPUT_INDEX = 'Invalid transaction collateral input index', + INVALID_COLLATERAL_INPUT = 'Invalid transaction collateral input', INVALID_COLLATERAL_INPUTS = 'Invalid transaction collateral inputs', + INVALID_REQUIRED_SIGNERS = 'Invalid transaction required signers', + INVALID_NETWORK_ID = 'Invalid transaction network id', + INVALID_TOTAL_COLLATERAL = 'Invalid transaction total collateral', + + INVALID_REFERENCE_INPUT_INDEX = 'Invalid transaction reference input index', + INVALID_REFERENCE_INPUT = 'Invalid transaction reference input', INVALID_REFERENCE_INPUTS = 'Invalid transaction reference inputs', + INVALID_VOTING_PROCEDURES = 'Invalid transaction voting procedures', INVALID_VOTING_PROCEDURES_EMPTY_MAP = 'Invalid transaction voting procedures --- an empty map included', INVALID_VOTER = 'Invalid voter', INVALID_GOV_ACTION_ID = 'Invalid governance action id', - INVALID_VOTING_PROCEDURE = 'Invalid voting procedure', INVALID_VOTE_OPTION = 'Invalid vote', + INVALID_VOTING_PROCEDURE = 'Invalid voting procedure', + INVALID_PROPOSAL_PROCEDURES = 'Invalid proposal procedures', INVALID_PROPOSAL_PROCEDURE = 'Invalid proposal procedure', + INVALID_TREASURY = 'Invalid treasury', + INVALID_DONATION = 'Invalid donation', - // TODO the order of the items in this enum is messed up? INVALID_TX_CBOR = 'Invalid transaction CBOR', + INVALID_TX_BODY_CBOR = 'Invalid transaction body CBOR', + INVALID_TX_BODY_UNKNOWN_ITEMS = 'Transaction body contains unknown items', } export class ParseError extends Error { diff --git a/src/txParsers.ts b/src/txParsers.ts index 70913cc..53bfb59 100644 --- a/src/txParsers.ts +++ b/src/txParsers.ts @@ -62,24 +62,24 @@ import { TransactionOutput, Unparsed, Withdrawal, - StakeRegCertificate, - StakeUnregCertificate, - VoteDelegCertificate, + StakeRegistrationConwayCertificate, + StakeDeregistrationConwayCertificate, + VoteDelegationCertificate, DRepType, KeyHashDRep, ScriptHashDRep, AlwaysAbstainDRep, AlwaysNoConfidenceDRep, - StakeVoteDelegCertificate, - StakeRegDelegCertificate, - VoteRegDelegCertificate, - StakeVoteRegDelegCertificate, + StakeAndVoteDelegationCertificate, + StakeRegistrationAndDelegationCertificate, + StakeRegistrationWithVoteDelegationCertificate, + StakeRegistrationWithStakeAndVoteDelegationCertificate, ANCHOR_DATA_HASH_LENGTH, Anchor, - AuthCommitteeHotCertificate, + AuthorizeCommitteeHotCertificate, ResignCommitteeColdCertificate, - DRepRegCertificate, - DRepUnregCertificate, + DRepRegistrationCertificate, + DRepDeregistrationCertificate, DRepUpdateCertificate, AmountType, ASSET_NAME_MAX_LENGTH, @@ -125,7 +125,7 @@ import { TransactionBodyKeys, undefinedOnlyAtTheEnd, } from './utils' -import { Tagged } from 'cbor' +import {Tagged} from 'cbor' // ======================== universal parsers / parsers for CDDL data types @@ -147,23 +147,29 @@ const parseCredentialType = ( return unparsedCredentialType } -const parseKeyCredential = (data: unknown[]): WithoutType => ({ - hash: parseBufferOfLength( - data[0], - KEY_HASH_LENGTH, - ParseErrorReason.INVALID_CREDENTIAL_KEY_HASH, - ), -}) +const parseKeyCredential = (data: unknown[]): WithoutType => { + validate(data.length === 1, ParseErrorReason.INVALID_CREDENTIAL) + return { + hash: parseBufferOfLength( + data[0], + KEY_HASH_LENGTH, + ParseErrorReason.INVALID_CREDENTIAL_KEY_HASH, + ), + } +} const parseScriptCredential = ( data: unknown[], -): WithoutType => ({ - hash: parseBufferOfLength( - data[0], - SCRIPT_HASH_LENGTH, - ParseErrorReason.INVALID_CREDENTIAL_SCRIPT_HASH, - ), -}) +): WithoutType => { + validate(data.length === 1, ParseErrorReason.INVALID_CREDENTIAL) + return { + hash: parseBufferOfLength( + data[0], + SCRIPT_HASH_LENGTH, + ParseErrorReason.INVALID_CREDENTIAL_SCRIPT_HASH, + ), + } +} export const parseCredential = createParser( parseBasedOnType, @@ -234,11 +240,6 @@ export const parseMultiasset = ( })) } -const parseAddress = createParser( - parseBuffer, - ParseErrorReason.INVALID_OUTPUT_ADDRESS, -) - const parseAmountWithMultiasset = (unparsedAmount: unknown): Amount => { const [coin, multiasset] = parseTuple( unparsedAmount, @@ -278,6 +279,11 @@ const parseLegacyTxOutputDatumHash = ( } : undefined +const parseAddress = createParser( + parseBuffer, + ParseErrorReason.INVALID_OUTPUT_ADDRESS, +) + const parseLegacyTxOutput = ( unparsedTxOutput: unknown, ): LegacyTransactionOutput => { @@ -393,11 +399,12 @@ const parseUnitIntervalData = createParser( createParser(parseUint, ParseErrorReason.INVALID_UNIT_INTERVAL_END), ) -const parseUnitInterval = ( - data: unknown, -): UnitInterval => { +const parseUnitInterval = (data: unknown): UnitInterval => { validate(data instanceof Tagged, ParseErrorReason.INVALID_UNIT_INTERVAL) - validate(data.tag === CborTag.UNIT_INTERVAL, ParseErrorReason.INVALID_UNIT_INTERVAL) + validate( + data.tag === CborTag.UNIT_INTERVAL, + ParseErrorReason.INVALID_UNIT_INTERVAL, + ) return parseUnitIntervalData(data.value) } @@ -423,38 +430,47 @@ const parseRelayType = (unparsedRelayType: unknown): RelayType => { const parseRelaySingleHostAddress = ( data: unknown[], -): WithoutType => ({ - port: parseNullable(data[0], parsePort), - ipv4: parseNullable( - data[1], - createParser( - parseBufferOfLength, - IPV4_LENGTH, - ParseErrorReason.INVALID_RELAY_IPV4, +): WithoutType => { + validate(data.length === 3, ParseErrorReason.INVALID_RELAY) + return { + port: parseNullable(data[0], parsePort), + ipv4: parseNullable( + data[1], + createParser( + parseBufferOfLength, + IPV4_LENGTH, + ParseErrorReason.INVALID_RELAY_IPV4, + ), ), - ), - ipv6: parseNullable( - data[2], - createParser( - parseBufferOfLength, - IPV6_LENGTH, - ParseErrorReason.INVALID_RELAY_IPV6, + ipv6: parseNullable( + data[2], + createParser( + parseBufferOfLength, + IPV6_LENGTH, + ParseErrorReason.INVALID_RELAY_IPV6, + ), ), - ), -}) + } +} const parseRelaySingleHostName = ( data: unknown[], -): WithoutType => ({ - port: parseNullable(data[0], parsePort), - dnsName: parseDnsName(data[1]), -}) +): WithoutType => { + validate(data.length === 2, ParseErrorReason.INVALID_RELAY) + return { + port: parseNullable(data[0], parsePort), + dnsName: parseDnsName(data[1]), + } +} const parseRelayMultiHostName = ( data: unknown[], -): WithoutType => ({ - dnsName: parseDnsName(data[0]), -}) +): WithoutType => { + validate(data.length === 1, ParseErrorReason.INVALID_RELAY) + return { + dnsName: parseDnsName(data[0]), + } +} const parseRelay = createParser( parseBasedOnType, @@ -541,33 +557,43 @@ const parseDRepType = (unparsedType: unknown): DRepType => { return unparsedType } -const parseKeyHashDRep = (data: unknown[]): WithoutType => ({ - keyHash: parseBufferOfLength( - data[0], - KEY_HASH_LENGTH, - ParseErrorReason.INVALID_DREP, - ), -}) +const parseKeyHashDRep = (data: unknown[]): WithoutType => { + validate(data.length === 1, ParseErrorReason.INVALID_DREP) + return { + keyHash: parseBufferOfLength( + data[0], + KEY_HASH_LENGTH, + ParseErrorReason.INVALID_DREP, + ), + } +} -const parseScriptHashDRep = (data: unknown[]): WithoutType => ({ - scriptHash: parseBufferOfLength( - data[0], - SCRIPT_HASH_LENGTH, - ParseErrorReason.INVALID_DREP, - ), -}) +const parseScriptHashDRep = (data: unknown[]): WithoutType => { + validate(data.length === 1, ParseErrorReason.INVALID_DREP) + return { + scriptHash: parseBufferOfLength( + data[0], + SCRIPT_HASH_LENGTH, + ParseErrorReason.INVALID_DREP, + ), + } +} const parseAlwaysAbstainDRep = ( - _data: unknown[], -): WithoutType => ({ + data: unknown[], +): WithoutType => { // nothing to parse -}) + validate(data.length === 0, ParseErrorReason.INVALID_DREP) + return {} +} const parseAlwaysNoConfidenceDRep = ( - _data: unknown[], -): WithoutType => ({ + data: unknown[], +): WithoutType => { // nothing to parse -}) + validate(data.length === 0, ParseErrorReason.INVALID_DREP) + return {} +} export const parseAnchor = (data: unknown): Anchor => { const [url, dataHash] = parseTuple( @@ -672,7 +698,7 @@ const parseMoveInstantaneousRewardsCertificate = ( const parseStakeRegCertificate = ( data: unknown[], -): WithoutType => { +): WithoutType => { validate(data.length === 2, ParseErrorReason.INVALID_CERTIFICATE) return { stakeCredential: parseCredential(data[0]), @@ -682,7 +708,7 @@ const parseStakeRegCertificate = ( const parseStakeUnregCertificate = ( data: unknown[], -): WithoutType => { +): WithoutType => { validate(data.length === 2, ParseErrorReason.INVALID_CERTIFICATE) return { stakeCredential: parseCredential(data[0]), @@ -692,7 +718,7 @@ const parseStakeUnregCertificate = ( const parseVoteDelegCertificate = ( data: unknown[], -): WithoutType => { +): WithoutType => { validate(data.length === 2, ParseErrorReason.INVALID_CERTIFICATE) return { stakeCredential: parseCredential(data[0]), @@ -702,19 +728,18 @@ const parseVoteDelegCertificate = ( const parseStakeVoteDelegCertificate = ( data: unknown[], -): WithoutType => { +): WithoutType => { validate(data.length === 3, ParseErrorReason.INVALID_CERTIFICATE) return { stakeCredential: parseCredential(data[0]), poolKeyHash: parsePoolKeyHash(data[1]), dRep: parseDRep(data[2]), - // TODO why don't we check data length? should be exact, not less, not more } } const parseStakeRegDelegCertificate = ( data: unknown[], -): WithoutType => { +): WithoutType => { validate(data.length === 3, ParseErrorReason.INVALID_CERTIFICATE) return { stakeCredential: parseCredential(data[0]), @@ -725,7 +750,7 @@ const parseStakeRegDelegCertificate = ( const parseVoteRegDelegCertificate = ( data: unknown[], -): WithoutType => { +): WithoutType => { validate(data.length === 3, ParseErrorReason.INVALID_CERTIFICATE) return { stakeCredential: parseCredential(data[0]), @@ -736,7 +761,7 @@ const parseVoteRegDelegCertificate = ( const parseStakeVoteRegDelegCertificate = ( data: unknown[], -): WithoutType => { +): WithoutType => { validate(data.length === 4, ParseErrorReason.INVALID_CERTIFICATE) return { stakeCredential: parseCredential(data[0]), @@ -748,7 +773,7 @@ const parseStakeVoteRegDelegCertificate = ( const parseAuthCommitteeHotCertificate = ( data: unknown[], -): WithoutType => { +): WithoutType => { validate(data.length === 2, ParseErrorReason.INVALID_CERTIFICATE) return { coldCredential: parseCredential(data[0]), @@ -768,7 +793,7 @@ const parseResignCommitteeColdCertificate = ( const parseDRepRegCertificate = ( data: unknown[], -): WithoutType => { +): WithoutType => { validate(data.length === 3, ParseErrorReason.INVALID_CERTIFICATE) return { dRepCredential: parseCredential(data[0]), @@ -779,7 +804,7 @@ const parseDRepRegCertificate = ( const parseDRepUnregCertificate = ( data: unknown[], -): WithoutType => { +): WithoutType => { validate(data.length === 2, ParseErrorReason.INVALID_CERTIFICATE) return { dRepCredential: parseCredential(data[0]), @@ -910,6 +935,14 @@ export const parseNetworkId = createParser( ParseErrorReason.INVALID_NETWORK_ID, ) +export const parseCollateralOutput = (unparsedTxOutput: unknown): TransactionOutput => { + // The reported error is somewhat inaccurate (does not refer to "collateral return output" + // at all, just "output"), but it is not worth rewriting the output parsing. + // There are some conditions on collateral return outputs + // that we do not verify here anyway (limitations on address type, datum hash presence etc.). + return parseTxOutput(unparsedTxOutput) +} + export const parseTotalCollateral = createParser( parseUint, ParseErrorReason.INVALID_TOTAL_COLLATERAL, @@ -1157,7 +1190,7 @@ export const parseTxBody = (unparsedTxBody: unknown): TransactionBody => { ), collateralReturnOutput: parseOptional( unparsedTxBody.get(TransactionBodyKeys.COLLATERAL_RETURN_OUTPUT), - parseTxOutput, + parseCollateralOutput, ), totalCollateral: parseOptional( unparsedTxBody.get(TransactionBodyKeys.TOTAL_COLLATERAL), diff --git a/src/txSerializers.ts b/src/txSerializers.ts index 5f0f9ba..84c5798 100644 --- a/src/txSerializers.ts +++ b/src/txSerializers.ts @@ -50,13 +50,9 @@ export const identity = (x: T): T => x export type Serializer = (data: T) => unknown const serializeCddlSetBase = ( - set: CddlSetBase | undefined, + set: CddlSetBase, serializeEntry: Serializer, ) => { - if (set === undefined) { - return undefined - } - const data = set.items.map(serializeEntry) if (set.hasTag) { return new Tagged(CborTag.SET, data) @@ -65,6 +61,16 @@ const serializeCddlSetBase = ( } } +const serializeCddlSetBaseOrUndefined = ( + set: CddlSetBase | undefined, + serializeEntry: Serializer, +) => { + if (set === undefined) { + return undefined + } + return serializeCddlSetBase(set, serializeEntry) +} + // export needed because of uniqueness check during parsing export const serializeTxInput = (input: TransactionInput) => [ input.transactionId, @@ -220,41 +226,41 @@ export const serializeCertificate = (certificate: Certificate) => { case CertificateType.GENESIS_KEY_DELEGATION: case CertificateType.MOVE_INSTANTANEOUS_REWARDS_CERT: return [certificate.type, ...certificate.restOfData] - case CertificateType.STAKE_REG: - case CertificateType.STAKE_UNREG: + case CertificateType.STAKE_REGISTRATION_CONWAY: + case CertificateType.STAKE_DEREGISTRATION_CONWAY: return [ certificate.type, serializeCredential(certificate.stakeCredential), certificate.deposit, ] - case CertificateType.VOTE_DELEG: + case CertificateType.VOTE_DELEGATION: return [ certificate.type, serializeCredential(certificate.stakeCredential), serializeDRep(certificate.dRep), ] - case CertificateType.STAKE_VOTE_DELEG: + case CertificateType.STAKE_AND_VOTE_DELEGATION: return [ certificate.type, serializeCredential(certificate.stakeCredential), certificate.poolKeyHash, serializeDRep(certificate.dRep), ] - case CertificateType.STAKE_REG_DELEG: + case CertificateType.STAKE_REGISTRATION_AND_DELEGATION: return [ certificate.type, serializeCredential(certificate.stakeCredential), certificate.poolKeyHash, certificate.deposit, ] - case CertificateType.VOTE_REG_DELEG: + case CertificateType.STAKE_REGISTRATION_WITH_VOTE_DELEGATION: return [ certificate.type, serializeCredential(certificate.stakeCredential), serializeDRep(certificate.dRep), certificate.deposit, ] - case CertificateType.STAKE_VOTE_REG_DELEG: + case CertificateType.STAKE_REGISTRATION_WITH_STAKE_AND_VOTE_DELEGATION: return [ certificate.type, serializeCredential(certificate.stakeCredential), @@ -262,7 +268,7 @@ export const serializeCertificate = (certificate: Certificate) => { serializeDRep(certificate.dRep), certificate.deposit, ] - case CertificateType.AUTH_COMMITTEE_HOT: + case CertificateType.AUTHORIZE_COMMITTEE_HOT: return [ certificate.type, serializeCredential(certificate.coldCredential), @@ -274,14 +280,14 @@ export const serializeCertificate = (certificate: Certificate) => { serializeCredential(certificate.coldCredential), serializeAnchor(certificate.anchor), ] - case CertificateType.DREP_REG: + case CertificateType.DREP_REGISTRATION: return [ certificate.type, serializeCredential(certificate.dRepCredential), certificate.deposit, serializeAnchor(certificate.anchor), ] - case CertificateType.DREP_UNREG: + case CertificateType.DREP_DEREGISTRATION: return [ certificate.type, serializeCredential(certificate.dRepCredential), @@ -348,7 +354,10 @@ export const serializeTxBody = (txBody: TransactionBody) => [TransactionBodyKeys.TTL, identity(txBody.ttl)], [ TransactionBodyKeys.CERTIFICATES, - serializeCddlSetBase(txBody.certificates, serializeCertificate), + serializeCddlSetBaseOrUndefined( + txBody.certificates, + serializeCertificate, + ), ], [ TransactionBodyKeys.WITHDRAWALS, @@ -367,11 +376,14 @@ export const serializeTxBody = (txBody: TransactionBody) => [TransactionBodyKeys.SCRIPT_DATA_HASH, identity(txBody.scriptDataHash)], [ TransactionBodyKeys.COLLATERAL_INPUTS, - serializeCddlSetBase(txBody.collateralInputs, serializeCollateralInput), + serializeCddlSetBaseOrUndefined( + txBody.collateralInputs, + serializeCollateralInput, + ), ], [ TransactionBodyKeys.REQUIRED_SIGNERS, - serializeCddlSetBase(txBody.requiredSigners, identity), + serializeCddlSetBaseOrUndefined(txBody.requiredSigners, identity), ], [TransactionBodyKeys.NETWORK_ID, identity(txBody.networkId)], [ @@ -382,7 +394,7 @@ export const serializeTxBody = (txBody: TransactionBody) => [TransactionBodyKeys.TOTAL_COLLATERAL, identity(txBody.totalCollateral)], [ TransactionBodyKeys.REFERENCE_INPUTS, - serializeCddlSetBase(txBody.referenceInputs, serializeTxInput), + serializeCddlSetBaseOrUndefined(txBody.referenceInputs, serializeTxInput), ], [ TransactionBodyKeys.VOTING_PROCEDURES, @@ -391,7 +403,7 @@ export const serializeTxBody = (txBody: TransactionBody) => ], [ TransactionBodyKeys.PROPOSAL_PROCEDURES, - serializeCddlSetBase( + serializeCddlSetBaseOrUndefined( txBody.proposalProcedures, serializeProposalProcedure, ), diff --git a/src/txTransformers.ts b/src/txTransformers.ts index f1fffa9..e6d010b 100644 --- a/src/txTransformers.ts +++ b/src/txTransformers.ts @@ -127,15 +127,14 @@ export const transformTxBody = ( ...txBody, outputs: txBody.outputs.map(transformTxOutput), withdrawals: transformOptionalList(txBody.withdrawals), - collateralReturnOutput: - txBody.collateralReturnOutput && - transformTxOutput(txBody.collateralReturnOutput), - // TODO check with CDDL which lists/maps are nonempty there, maybe we should check it at parsing immediately - // TODO check if keys in a set are unique by serializing into cbor auxiliaryDataHash: transformAuxiliaryDataHash( txBody.auxiliaryDataHash, auxiliaryData, ), + collateralReturnOutput: + txBody.collateralReturnOutput && + transformTxOutput(txBody.collateralReturnOutput), + votingProcedures: transformOptionalList(txBody.votingProcedures), }) export const transformTx = (tx: Transaction): Transaction => ({ diff --git a/src/txValidators.ts b/src/txValidators.ts index 566da6f..5601b13 100644 --- a/src/txValidators.ts +++ b/src/txValidators.ts @@ -247,7 +247,7 @@ function* validateCertificates( ), ) break - case CertificateType.STAKE_VOTE_DELEG: + case CertificateType.STAKE_AND_VOTE_DELEGATION: yield* validate( false, err( @@ -256,7 +256,7 @@ function* validateCertificates( ), ) break - case CertificateType.STAKE_REG_DELEG: + case CertificateType.STAKE_REGISTRATION_AND_DELEGATION: yield* validate( false, err( @@ -265,7 +265,7 @@ function* validateCertificates( ), ) break - case CertificateType.VOTE_REG_DELEG: + case CertificateType.STAKE_REGISTRATION_WITH_VOTE_DELEGATION: yield* validate( false, err( @@ -274,7 +274,7 @@ function* validateCertificates( ), ) break - case CertificateType.STAKE_VOTE_REG_DELEG: + case CertificateType.STAKE_REGISTRATION_WITH_STAKE_AND_VOTE_DELEGATION: yield* validate( false, err( @@ -283,8 +283,8 @@ function* validateCertificates( ), ) break - case CertificateType.STAKE_REG: - case CertificateType.STAKE_UNREG: + case CertificateType.STAKE_REGISTRATION_CONWAY: + case CertificateType.STAKE_DEREGISTRATION_CONWAY: yield* validateUint64( certificate.deposit, `transaction_body.certificates[${i}].deposit`, @@ -311,6 +311,7 @@ function* validateWithdrawals(withdrawals: Withdrawal[]): ValidatorReturnType { } } +// TODO does this make sense for Plutus? there can be mixed credentials? probably remove the whole function function* validateStakeCredentials( certificates: Certificate[] | undefined, withdrawals: Withdrawal[] | undefined, @@ -554,6 +555,7 @@ function* validateTxBody(txBody: TransactionBody): ValidatorReturnType { bind(validateUint64, 'transaction_body.total_collateral'), ) yield* validateOptional(txBody.referenceInputs, validateReferenceInputs) + // TODO validate voting procedures yield* validate( txBody.proposalProcedures === undefined, err( diff --git a/src/types.ts b/src/types.ts index f03fbe0..2524881 100644 --- a/src/types.ts +++ b/src/types.ts @@ -10,7 +10,7 @@ export type MaxSizeUint = Uint & {__maxSize: N} export type CddlSetBase = { items: T[] - hasTag: boolean // 258 tag, existing since Conway, optional so far + hasTag: boolean // 258 tag, existing since Conway, using the tag is optional in Conway } export type CddlSet = CddlSetBase & { _nonEmpty: false @@ -143,19 +143,19 @@ export enum CertificateType { STAKE_DELEGATION = 2, POOL_REGISTRATION = 3, POOL_RETIREMENT = 4, - GENESIS_KEY_DELEGATION = 5, - MOVE_INSTANTANEOUS_REWARDS_CERT = 6, - STAKE_REG = 7, - STAKE_UNREG = 8, - VOTE_DELEG = 9, - STAKE_VOTE_DELEG = 10, - STAKE_REG_DELEG = 11, - VOTE_REG_DELEG = 12, - STAKE_VOTE_REG_DELEG = 13, - AUTH_COMMITTEE_HOT = 14, + GENESIS_KEY_DELEGATION = 5, // deprecated since Conway + MOVE_INSTANTANEOUS_REWARDS_CERT = 6, // deprecated since Conway + STAKE_REGISTRATION_CONWAY = 7, + STAKE_DEREGISTRATION_CONWAY = 8, + VOTE_DELEGATION = 9, + STAKE_AND_VOTE_DELEGATION = 10, + STAKE_REGISTRATION_AND_DELEGATION = 11, + STAKE_REGISTRATION_WITH_VOTE_DELEGATION = 12, + STAKE_REGISTRATION_WITH_STAKE_AND_VOTE_DELEGATION = 13, + AUTHORIZE_COMMITTEE_HOT = 14, RESIGN_COMMITTEE_COLD = 15, - DREP_REG = 16, - DREP_UNREG = 17, + DREP_REGISTRATION = 16, + DREP_DEREGISTRATION = 17, DREP_UPDATE = 18, } @@ -265,14 +265,14 @@ export type MoveInstantaneousRewardsCertificate = { restOfData: Unparsed[] } -export type StakeRegCertificate = { - type: CertificateType.STAKE_REG +export type StakeRegistrationConwayCertificate = { + type: CertificateType.STAKE_REGISTRATION_CONWAY stakeCredential: Credential deposit: Coin } -export type StakeUnregCertificate = { - type: CertificateType.STAKE_UNREG +export type StakeDeregistrationConwayCertificate = { + type: CertificateType.STAKE_DEREGISTRATION_CONWAY stakeCredential: Credential deposit: Coin } @@ -308,35 +308,35 @@ export type DRep = | AlwaysAbstainDRep | AlwaysNoConfidenceDRep -export type VoteDelegCertificate = { - type: CertificateType.VOTE_DELEG +export type VoteDelegationCertificate = { + type: CertificateType.VOTE_DELEGATION stakeCredential: Credential dRep: DRep } -export type StakeVoteDelegCertificate = { - type: CertificateType.STAKE_VOTE_DELEG +export type StakeAndVoteDelegationCertificate = { + type: CertificateType.STAKE_AND_VOTE_DELEGATION stakeCredential: Credential poolKeyHash: FixLenBuffer dRep: DRep } -export type StakeRegDelegCertificate = { - type: CertificateType.STAKE_REG_DELEG +export type StakeRegistrationAndDelegationCertificate = { + type: CertificateType.STAKE_REGISTRATION_AND_DELEGATION stakeCredential: Credential poolKeyHash: FixLenBuffer deposit: Coin } -export type VoteRegDelegCertificate = { - type: CertificateType.VOTE_REG_DELEG +export type StakeRegistrationWithVoteDelegationCertificate = { + type: CertificateType.STAKE_REGISTRATION_WITH_VOTE_DELEGATION stakeCredential: Credential dRep: DRep deposit: Coin } -export type StakeVoteRegDelegCertificate = { - type: CertificateType.STAKE_VOTE_REG_DELEG +export type StakeRegistrationWithStakeAndVoteDelegationCertificate = { + type: CertificateType.STAKE_REGISTRATION_WITH_STAKE_AND_VOTE_DELEGATION stakeCredential: Credential poolKeyHash: FixLenBuffer dRep: DRep @@ -348,8 +348,8 @@ export type Anchor = { dataHash: FixLenBuffer } -export type AuthCommitteeHotCertificate = { - type: CertificateType.AUTH_COMMITTEE_HOT +export type AuthorizeCommitteeHotCertificate = { + type: CertificateType.AUTHORIZE_COMMITTEE_HOT coldCredential: Credential hotCredential: Credential } @@ -360,15 +360,15 @@ export type ResignCommitteeColdCertificate = { anchor: Anchor | null } -export type DRepRegCertificate = { - type: CertificateType.DREP_REG +export type DRepRegistrationCertificate = { + type: CertificateType.DREP_REGISTRATION dRepCredential: Credential deposit: Coin anchor: Anchor | null } -export type DRepUnregCertificate = { - type: CertificateType.DREP_UNREG +export type DRepDeregistrationCertificate = { + type: CertificateType.DREP_DEREGISTRATION dRepCredential: Credential deposit: Coin } @@ -387,17 +387,17 @@ export type Certificate = | PoolRetirementCertificate | GenesisKeyDelegation | MoveInstantaneousRewardsCertificate - | StakeRegCertificate - | StakeUnregCertificate - | VoteDelegCertificate - | StakeVoteDelegCertificate - | StakeRegDelegCertificate - | VoteRegDelegCertificate - | StakeVoteRegDelegCertificate - | AuthCommitteeHotCertificate + | StakeRegistrationConwayCertificate + | StakeDeregistrationConwayCertificate + | VoteDelegationCertificate + | StakeAndVoteDelegationCertificate + | StakeRegistrationAndDelegationCertificate + | StakeRegistrationWithVoteDelegationCertificate + | StakeRegistrationWithStakeAndVoteDelegationCertificate + | AuthorizeCommitteeHotCertificate | ResignCommitteeColdCertificate - | DRepRegCertificate - | DRepUnregCertificate + | DRepRegistrationCertificate + | DRepDeregistrationCertificate | DRepUpdateCertificate // Withdrawal diff --git a/test/integration/__fixtures__/transactions.ts b/test/integration/__fixtures__/transactions.ts index 68f9224..2dfe712 100644 --- a/test/integration/__fixtures__/transactions.ts +++ b/test/integration/__fixtures__/transactions.ts @@ -843,7 +843,7 @@ export const ValidTransactionBodyTestCases: ValidTransactionBodyTestCase[] = [ certificates: { items: [ { - type: CertificateType.VOTE_DELEG, + type: CertificateType.VOTE_DELEGATION, stakeCredential: { type: CredentialType.KEY_HASH, hash: toFixLenBuffer( @@ -860,7 +860,7 @@ export const ValidTransactionBodyTestCases: ValidTransactionBodyTestCase[] = [ }, }, { - type: CertificateType.DREP_REG, + type: CertificateType.DREP_REGISTRATION, dRepCredential: { type: CredentialType.KEY_HASH, hash: toFixLenBuffer( @@ -895,7 +895,7 @@ export const ValidTransactionBodyTestCases: ValidTransactionBodyTestCase[] = [ }, }, { - type: CertificateType.DREP_UNREG, + type: CertificateType.DREP_DEREGISTRATION, dRepCredential: { type: CredentialType.KEY_HASH, hash: toFixLenBuffer( @@ -906,7 +906,7 @@ export const ValidTransactionBodyTestCases: ValidTransactionBodyTestCase[] = [ deposit: toUint(2000000), }, { - type: CertificateType.STAKE_VOTE_DELEG, + type: CertificateType.STAKE_AND_VOTE_DELEGATION, stakeCredential: { type: CredentialType.KEY_HASH, hash: toFixLenBuffer( @@ -927,7 +927,7 @@ export const ValidTransactionBodyTestCases: ValidTransactionBodyTestCase[] = [ }, }, { - type: CertificateType.STAKE_REG_DELEG, + type: CertificateType.STAKE_REGISTRATION_AND_DELEGATION, stakeCredential: { type: CredentialType.KEY_HASH, hash: toFixLenBuffer( @@ -942,7 +942,7 @@ export const ValidTransactionBodyTestCases: ValidTransactionBodyTestCase[] = [ deposit: toUint(2000000), }, { - type: CertificateType.VOTE_REG_DELEG, + type: CertificateType.STAKE_REGISTRATION_WITH_VOTE_DELEGATION, stakeCredential: { type: CredentialType.KEY_HASH, hash: toFixLenBuffer( @@ -960,7 +960,7 @@ export const ValidTransactionBodyTestCases: ValidTransactionBodyTestCase[] = [ deposit: toUint(2000000), }, { - type: CertificateType.STAKE_VOTE_REG_DELEG, + type: CertificateType.STAKE_REGISTRATION_WITH_STAKE_AND_VOTE_DELEGATION, stakeCredential: { type: CredentialType.KEY_HASH, hash: toFixLenBuffer( diff --git a/test/unit/certificates.test.ts b/test/unit/certificates.test.ts index 12af85c..1f6c7a3 100644 --- a/test/unit/certificates.test.ts +++ b/test/unit/certificates.test.ts @@ -1,6 +1,5 @@ -import {createParser, parseArray} from '../../src/parsers' import {ParseErrorReason} from '../../src/errors' -import {parseCertificate} from '../../src/txParsers' +import {parseCertificates} from '../../src/txParsers' import { Certificate, Port, @@ -9,6 +8,7 @@ import { CredentialType, CddlSet, KeyHash, + CddlNonEmptyOrderedSet, } from '../../src/types' import { ipv4ToBuffer, @@ -21,210 +21,224 @@ import { ValidParseTestCase, } from '../test_utils' -const ValidCertificatesTestCases: ValidParseTestCase[] = [ +const ValidCertificatesTestCases: ValidParseTestCase< + CddlNonEmptyOrderedSet +>[] = [ { testName: 'One stake registration legacy', cbor: '8182008200581c2c049dfed8bc41edefbbc835ca0a739cac961557950262ef48bcff1d', - parsed: [ - { - type: CertificateType.STAKE_REGISTRATION, - stakeCredential: { - type: CredentialType.KEY_HASH, - hash: toFixLenBuffer( - '2c049dfed8bc41edefbbc835ca0a739cac961557950262ef48bcff1d', - 28, - ), + parsed: { + items: [ + { + type: CertificateType.STAKE_REGISTRATION, + stakeCredential: { + type: CredentialType.KEY_HASH, + hash: toFixLenBuffer( + '2c049dfed8bc41edefbbc835ca0a739cac961557950262ef48bcff1d', + 28, + ), + }, }, - }, - ], + ], + hasTag: false, + } as CddlNonEmptyOrderedSet, }, { testName: 'One stake registration Conway', cbor: '8183078200581c2c049dfed8bc41edefbbc835ca0a739cac961557950262ef48bcff1d06', - parsed: [ - { - type: CertificateType.STAKE_REG, - stakeCredential: { - type: CredentialType.KEY_HASH, - hash: toFixLenBuffer( - '2c049dfed8bc41edefbbc835ca0a739cac961557950262ef48bcff1d', - 28, - ), + parsed: { + items: [ + { + type: CertificateType.STAKE_REGISTRATION_CONWAY, + stakeCredential: { + type: CredentialType.KEY_HASH, + hash: toFixLenBuffer( + '2c049dfed8bc41edefbbc835ca0a739cac961557950262ef48bcff1d', + 28, + ), + }, + deposit: toUint(6), }, - deposit: toUint(6), - }, - ], + ], + hasTag: false, + } as CddlNonEmptyOrderedSet, }, { testName: 'Two stake registrations', cbor: '8282008200581c2c049dfed8bc41edefbbc835ca0a739cac961557950262ef48bcff1d82008200581cc1d58a7602c3bd8104cd2a871a2d1cb68f6f6669bd37a7688618ee55', - parsed: [ - { - type: CertificateType.STAKE_REGISTRATION, - stakeCredential: { - type: CredentialType.KEY_HASH, - hash: toFixLenBuffer( - '2c049dfed8bc41edefbbc835ca0a739cac961557950262ef48bcff1d', - 28, - ), + parsed: { + items: [ + { + type: CertificateType.STAKE_REGISTRATION, + stakeCredential: { + type: CredentialType.KEY_HASH, + hash: toFixLenBuffer( + '2c049dfed8bc41edefbbc835ca0a739cac961557950262ef48bcff1d', + 28, + ), + }, }, - }, - { - type: CertificateType.STAKE_REGISTRATION, - stakeCredential: { - type: CredentialType.KEY_HASH, - hash: toFixLenBuffer( - 'c1d58a7602c3bd8104cd2a871a2d1cb68f6f6669bd37a7688618ee55', - 28, - ), + { + type: CertificateType.STAKE_REGISTRATION, + stakeCredential: { + type: CredentialType.KEY_HASH, + hash: toFixLenBuffer( + 'c1d58a7602c3bd8104cd2a871a2d1cb68f6f6669bd37a7688618ee55', + 28, + ), + }, }, - }, - ], + ], + hasTag: false, + } as CddlNonEmptyOrderedSet, }, { testName: 'Each certificate type once', cbor: '8683078200581c2c049dfed8bc41edefbbc835ca0a739cac961557950262ef48bcff1d0683088201581cc1d58a7602c3bd8104cd2a871a2d1cb68f6f6669bd37a7688618ee550683028200581c2c049dfed8bc41edefbbc835ca0a739cac961557950262ef48bcff1d581c001337292eec9b3eefc6802f71cb34c21a7963eb12466d52836aa3908a03581c4dfbc0559b2e1d6af62c447f0a0d6290a8b05e075ef08db38c1b81a8582067c5c0b45db55e8c82752263207b9a92c2d5fa6c671aceed9df451cad3fac7a31a0001e2401a05f5e100d81e82031819581de1d7d8a321633b3d1ab1651eeb258ad898ebcef1d348b54148f18e15da82581c2c049dfed8bc41edefbbc835ca0a739cac961557950262ef48bcff1d581cf699c6400f85bdca54e44d0cad1f6141ce049a411c0d695fc30c3f7384840019029af650004706260000004700000000111100008301f676616464726573732e76616375756d6c6162732e636f6d8202781e616e6f746865722e616464726573732e76616375756d6c6162732e636f6d840019ffff447f0000fff682782468747470733a2f2f706f6f6c2d6d657461646174612e76616375756d6c6162732e636f6d5820e318d62e3d5cc3cc23ca1123438e439d7aac6c6c423320f670d159726ac9d11f8304581c4dfbc0559b2e1d6af62c447f0a0d6290a8b05e075ef08db38c1b81a81a0001dfbe84108200581c1033bbc7db733c057fed63fa085113dfb570566eb708d548d2f7cce8008276616464726573732e76616375756d6c6162732e636f6d5820E318D62E3D5CC3CC23CA1123438E439D7AAC6C6C423320F670D159726AC9D11F', - parsed: [ - { - type: CertificateType.STAKE_REG, - stakeCredential: { - type: CredentialType.KEY_HASH, - hash: toFixLenBuffer( - '2c049dfed8bc41edefbbc835ca0a739cac961557950262ef48bcff1d', - 28, - ), + parsed: { + items: [ + { + type: CertificateType.STAKE_REGISTRATION_CONWAY, + stakeCredential: { + type: CredentialType.KEY_HASH, + hash: toFixLenBuffer( + '2c049dfed8bc41edefbbc835ca0a739cac961557950262ef48bcff1d', + 28, + ), + }, + deposit: toUint(6), }, - deposit: toUint(6), - }, - { - type: CertificateType.STAKE_UNREG, - stakeCredential: { - type: CredentialType.SCRIPT_HASH, - hash: toFixLenBuffer( - 'c1d58a7602c3bd8104cd2a871a2d1cb68f6f6669bd37a7688618ee55', - 28, - ), + { + type: CertificateType.STAKE_DEREGISTRATION_CONWAY, + stakeCredential: { + type: CredentialType.SCRIPT_HASH, + hash: toFixLenBuffer( + 'c1d58a7602c3bd8104cd2a871a2d1cb68f6f6669bd37a7688618ee55', + 28, + ), + }, + deposit: toUint(6), }, - deposit: toUint(6), - }, - { - type: CertificateType.STAKE_DELEGATION, - stakeCredential: { - type: CredentialType.KEY_HASH, - hash: toFixLenBuffer( - '2c049dfed8bc41edefbbc835ca0a739cac961557950262ef48bcff1d', + { + type: CertificateType.STAKE_DELEGATION, + stakeCredential: { + type: CredentialType.KEY_HASH, + hash: toFixLenBuffer( + '2c049dfed8bc41edefbbc835ca0a739cac961557950262ef48bcff1d', + 28, + ), + }, + poolKeyHash: toFixLenBuffer( + '001337292eec9b3eefc6802f71cb34c21a7963eb12466d52836aa390', 28, ), }, - poolKeyHash: toFixLenBuffer( - '001337292eec9b3eefc6802f71cb34c21a7963eb12466d52836aa390', - 28, - ), - }, - { - type: CertificateType.POOL_REGISTRATION, - poolParams: { - operator: toFixLenBuffer( - '4DFBC0559B2E1D6AF62C447F0A0D6290A8B05E075EF08DB38C1B81A8', - 28, - ), - vrfKeyHash: toFixLenBuffer( - '67C5C0B45DB55E8C82752263207B9A92C2D5FA6C671ACEED9DF451CAD3FAC7A3', - 32, - ), - pledge: toUint(123456), - cost: toUint(100000000), - margin: [toUint(3), toUint(25)], - rewardAccount: rewardAccount( - 'stake1u8ta3gepvvan6x43v50wkfv2mzvwhnh36dyt2s2g7x8ptks528lzm', - ), - poolOwners: { - items: [ - toFixLenBuffer( - '2C049DFED8BC41EDEFBBC835CA0A739CAC961557950262EF48BCFF1D', - 28, - ), - toFixLenBuffer( - 'F699C6400F85BDCA54E44D0CAD1F6141CE049A411C0D695FC30C3F73', - 28, - ), - ], - hasTag: false, - } as CddlSet, - relays: [ - { - type: RelayType.SINGLE_HOST_ADDRESS, - port: 666 as Port, - ipv4: null, - ipv6: toFixLenBuffer('00470626000000470000000011110000', 16), - }, - { - type: RelayType.SINGLE_HOST_NAME, - port: null, - dnsName: toMaxLenString('address.vacuumlabs.com', 64), - }, - { - type: RelayType.MULTI_HOST_NAME, - dnsName: toMaxLenString('another.address.vacuumlabs.com', 64), - }, - { - type: RelayType.SINGLE_HOST_ADDRESS, - port: 65535 as Port, - ipv4: ipv4ToBuffer('127.0.0.255'), - ipv6: null, - }, - ], - poolMetadata: { - url: toMaxLenString('https://pool-metadata.vacuumlabs.com', 64), - metadataHash: toFixLenBuffer( - 'E318D62E3D5CC3CC23CA1123438E439D7AAC6C6C423320F670D159726AC9D11F', + { + type: CertificateType.POOL_REGISTRATION, + poolParams: { + operator: toFixLenBuffer( + '4DFBC0559B2E1D6AF62C447F0A0D6290A8B05E075EF08DB38C1B81A8', + 28, + ), + vrfKeyHash: toFixLenBuffer( + '67C5C0B45DB55E8C82752263207B9A92C2D5FA6C671ACEED9DF451CAD3FAC7A3', 32, ), + pledge: toUint(123456), + cost: toUint(100000000), + margin: [toUint(3), toUint(25)], + rewardAccount: rewardAccount( + 'stake1u8ta3gepvvan6x43v50wkfv2mzvwhnh36dyt2s2g7x8ptks528lzm', + ), + poolOwners: { + items: [ + toFixLenBuffer( + '2C049DFED8BC41EDEFBBC835CA0A739CAC961557950262EF48BCFF1D', + 28, + ), + toFixLenBuffer( + 'F699C6400F85BDCA54E44D0CAD1F6141CE049A411C0D695FC30C3F73', + 28, + ), + ], + hasTag: false, + } as CddlSet, + relays: [ + { + type: RelayType.SINGLE_HOST_ADDRESS, + port: 666 as Port, + ipv4: null, + ipv6: toFixLenBuffer('00470626000000470000000011110000', 16), + }, + { + type: RelayType.SINGLE_HOST_NAME, + port: null, + dnsName: toMaxLenString('address.vacuumlabs.com', 64), + }, + { + type: RelayType.MULTI_HOST_NAME, + dnsName: toMaxLenString('another.address.vacuumlabs.com', 64), + }, + { + type: RelayType.SINGLE_HOST_ADDRESS, + port: 65535 as Port, + ipv4: ipv4ToBuffer('127.0.0.255'), + ipv6: null, + }, + ], + poolMetadata: { + url: toMaxLenString('https://pool-metadata.vacuumlabs.com', 64), + metadataHash: toFixLenBuffer( + 'E318D62E3D5CC3CC23CA1123438E439D7AAC6C6C423320F670D159726AC9D11F', + 32, + ), + }, }, }, - }, - { - type: CertificateType.POOL_RETIREMENT, - poolKeyHash: toFixLenBuffer( - '4dfbc0559b2e1d6af62c447f0a0d6290a8b05e075ef08db38c1b81a8', - 28, - ), - epoch: toUint(122814), - }, - /* - TODO missing - | VoteDelegCertificate - | StakeVoteDelegCertificate - | StakeRegDelegCertificate - | VoteRegDelegCertificate - | StakeVoteRegDelegCertificate - | AuthCommitteeHotCertificate - | ResignCommitteeColdCertificate -*/ - { - type: CertificateType.DREP_REG, - dRepCredential: { - type: CredentialType.KEY_HASH, - hash: toFixLenBuffer( - '1033bbc7db733c057fed63fa085113dfb570566eb708d548d2f7cce8', + { + type: CertificateType.POOL_RETIREMENT, + poolKeyHash: toFixLenBuffer( + '4dfbc0559b2e1d6af62c447f0a0d6290a8b05e075ef08db38c1b81a8', 28, ), + epoch: toUint(122814), }, - deposit: toUint(0), - anchor: { - url: toMaxLenString('address.vacuumlabs.com', 64), - dataHash: toFixLenBuffer( - 'E318D62E3D5CC3CC23CA1123438E439D7AAC6C6C423320F670D159726AC9D11F', - 32, - ), + /* + TODO missing + | VoteDelegCertificate + | StakeVoteDelegCertificate + | StakeRegDelegCertificate + | VoteRegDelegCertificate + | StakeVoteRegDelegCertificate + | AuthCommitteeHotCertificate + | ResignCommitteeColdCertificate + */ + { + type: CertificateType.DREP_REGISTRATION, + dRepCredential: { + type: CredentialType.KEY_HASH, + hash: toFixLenBuffer( + '1033bbc7db733c057fed63fa085113dfb570566eb708d548d2f7cce8', + 28, + ), + }, + deposit: toUint(0), + anchor: { + url: toMaxLenString('address.vacuumlabs.com', 64), + dataHash: toFixLenBuffer( + 'E318D62E3D5CC3CC23CA1123438E439D7AAC6C6C423320F670D159726AC9D11F', + 32, + ), + }, }, - }, - /* - TODO missing - | DRepUnregCertificate - | DRepUpdateCertificate -*/ - ], + /* + TODO missing + | DRepUnregCertificate + | DRepUpdateCertificate + */ + ], + hasTag: false, + } as CddlNonEmptyOrderedSet, }, ] @@ -234,6 +248,11 @@ const InvalidCertificatesTestCases: InvalidParseTestCase[] = [ cbor: 'a100f6', errMsg: ParseErrorReason.INVALID_CERTIFICATES, }, + { + testName: 'Items in array not unique', + cbor: '8482008200581c2c049dfed8bc41edefbbc835ca0a739cac961557950262ef48bcff1d82008200581cc1d58a7602c3bd8104cd2a871a2d1cb68f6f6669bd37a7688618ee5582008200581c2c049dfed8bc41edefbbc835ca0a739cac961557950262ef48bcff1d82008200581c2c049dfed8bc41edefbbc835ca0a739cac961557950262ef48bcff1e', + errMsg: ParseErrorReason.INVALID_CERTIFICATES, + }, { testName: 'Invalid certificate structure', cbor: '81818200581c2c049dfed8bc41edefbbc835ca0a739cac961557950262ef48bcff1d', @@ -266,15 +285,9 @@ const InvalidCertificatesTestCases: InvalidParseTestCase[] = [ }, ] -const parseCertificateArray = createParser( - parseArray, - parseCertificate, - ParseErrorReason.INVALID_CERTIFICATES, -) - registerTests( 'Parse certificates', - parseCertificateArray, + parseCertificates, ValidCertificatesTestCases, InvalidCertificatesTestCases, )