diff --git a/packages/core/src/Serialization/Certificates/PoolParams/PoolParams.ts b/packages/core/src/Serialization/Certificates/PoolParams/PoolParams.ts index dc84c5c7629..0a65c32166d 100644 --- a/packages/core/src/Serialization/Certificates/PoolParams/PoolParams.ts +++ b/packages/core/src/Serialization/Certificates/PoolParams/PoolParams.ts @@ -2,11 +2,13 @@ import * as Cardano from '../../../Cardano'; import * as Crypto from '@cardano-sdk/crypto'; import { CborReader, CborReaderState, CborWriter } from '../../CBOR'; +import { CborSet, Hash } from '../../Common'; import { HexBlob, InvalidArgumentError } from '@cardano-sdk/util'; import { PoolMetadata } from './PoolMetadata'; import { Relay } from './Relay'; import { UnitInterval } from '../../Common/UnitInterval'; +type PoolOwners = CborSet>; /** * Stake pool update certificate parameters. * @@ -20,7 +22,7 @@ export class PoolParams { #cost: Cardano.Lovelace; #margin: UnitInterval; #rewardAccount: Cardano.RewardAddress; - #poolOwners: Array; + #poolOwners: PoolOwners; #relays: Array; #poolMetadata?: PoolMetadata; #originalBytes: HexBlob | undefined = undefined; @@ -47,7 +49,7 @@ export class PoolParams { cost: Cardano.Lovelace, margin: UnitInterval, rewardAccount: Cardano.RewardAddress, - poolOwners: Array, + poolOwners: PoolOwners, relays: Array, poolMetadata?: PoolMetadata ) { @@ -93,7 +95,7 @@ export class PoolParams { * An example is the PoolRegistration certificate which flattens the pool parameters in the pool_registration, rather * than insert as a subgroup * - * @param the parent writer that already created the subgroup + * @param writer the parent writer that already created the subgroup * @returns The PoolMetadata in CBOR format. */ toFlattenedCbor(writer: CborWriter): HexBlob { @@ -103,10 +105,7 @@ export class PoolParams { writer.writeInt(this.#cost); writer.writeEncodedValue(Buffer.from(this.#margin.toCbor(), 'hex')); writer.writeByteString(Buffer.from(this.#rewardAccount.toAddress().toBytes(), 'hex')); - - writer.writeStartArray(this.#poolOwners.length); - for (const owner of this.#poolOwners) writer.writeByteString(Buffer.from(owner, 'hex')); - + writer.writeEncodedValue(Buffer.from(this.#poolOwners.toCbor(), 'hex')); writer.writeStartArray(this.#relays.length); for (const relay of this.#relays) writer.writeEncodedValue(Buffer.from(relay.toCbor(), 'hex')); @@ -158,17 +157,14 @@ export class PoolParams { const cost = reader.readInt(); const margin = UnitInterval.fromCbor(HexBlob.fromBytes(reader.readEncodedValue())); const rewardAccount = Cardano.Address.fromBytes(HexBlob.fromBytes(reader.readByteString())).asReward()!; - const poolOwner = new Array(); const relays = new Array(); let poolMetadata; // Pool owners. - reader.readStartArray(); - - while (reader.peekState() !== CborReaderState.EndArray) - poolOwner.push(Crypto.Ed25519KeyHashHex(HexBlob.fromBytes(reader.readByteString()))); - - reader.readEndArray(); + const poolOwner = CborSet.fromCbor>( + HexBlob.fromBytes(reader.readEncodedValue()), + Hash.fromCbor + ); // Relays reader.readStartArray(); @@ -200,9 +196,9 @@ export class PoolParams { id: Cardano.PoolId.fromKeyHash(this.#operator), margin: this.#margin.toCore(), metadataJson: this.#poolMetadata?.toCore(), - owners: this.#poolOwners.map((keyHash) => - Cardano.createRewardAccount(keyHash, rewardAccountAddress.getNetworkId()) - ), + owners: this.#poolOwners + .toCore() + .map((keyHash) => Cardano.createRewardAccount(keyHash, rewardAccountAddress.getNetworkId())), pledge: this.#pledge, relays: this.#relays.map((relay) => relay.toCore()), rewardAccount: this.#rewardAccount.toAddress().toBech32() as Cardano.RewardAccount, @@ -223,8 +219,11 @@ export class PoolParams { params.cost, UnitInterval.fromCore(params.margin), Cardano.Address.fromBech32(params.rewardAccount).asReward()!, - params.owners.map((owner) => - Crypto.Ed25519KeyHashHex(Cardano.Address.fromBech32(owner).asReward()!.getPaymentCredential()!.hash) + CborSet.fromCore( + params.owners.map((owner) => + Crypto.Ed25519KeyHashHex(Cardano.Address.fromBech32(owner).asReward()!.getPaymentCredential()!.hash) + ), + Hash.fromCore ), params.relays.map((relay) => Relay.fromCore(relay)), params.metadataJson ? PoolMetadata.fromCore(params.metadataJson) : undefined @@ -356,7 +355,7 @@ export class PoolParams { * * @returns The pool owners key hashes. */ - poolOwners(): Array { + poolOwners(): PoolOwners { return this.#poolOwners; } @@ -365,8 +364,8 @@ export class PoolParams { * * @param poolOwners The pool owners key hashes. */ - setPoolOwners(poolOwners: Array): void { - this.#poolOwners = [...poolOwners]; + setPoolOwners(poolOwners: PoolOwners): void { + this.#poolOwners = poolOwners; this.#originalBytes = undefined; } diff --git a/packages/core/src/Serialization/Common/Credential.ts b/packages/core/src/Serialization/Common/Credential.ts new file mode 100644 index 00000000000..5f4d6bd9dbf --- /dev/null +++ b/packages/core/src/Serialization/Common/Credential.ts @@ -0,0 +1,50 @@ +import { Cardano } from '../..'; +import { CborReader, CborWriter } from '../CBOR'; +import { Hash28ByteBase16 } from '@cardano-sdk/crypto'; +import { HexBlob, InvalidArgumentError } from '@cardano-sdk/util'; +import { hexToBytes } from '../../util/misc'; + +const CREDENTIAL_ARRAY_SIZE = 2; + +export class Credential { + #value: Cardano.Credential; + + private constructor(value: Cardano.Credential) { + this.#value = value; + } + + toCbor() { + const writer = new CborWriter(); + writer.writeStartArray(CREDENTIAL_ARRAY_SIZE); + writer.writeInt(this.#value.type); + writer.writeByteString(hexToBytes(this.#value.hash as unknown as HexBlob)); + return writer.encodeAsHex(); + } + + static fromCbor(cbor: HexBlob): Credential { + const reader = new CborReader(cbor); + if (reader.readStartArray() !== CREDENTIAL_ARRAY_SIZE) + throw new InvalidArgumentError( + 'cbor', + `Expected an array of ${CREDENTIAL_ARRAY_SIZE} elements, but got an array of ${length} elements` + ); + + const type = Number(reader.readUInt()); + const hash = HexBlob.fromBytes(reader.readByteString()) as unknown as Hash28ByteBase16; + + reader.readEndArray(); + return new Credential({ hash, type }); + } + + toCore(): Cardano.Credential { + return { ...this.#value }; + } + + static fromCore(credential: Cardano.Credential): Credential { + return new Credential({ ...credential }); + } + + value() { + return { ...this.#value }; + } +} diff --git a/packages/core/src/Serialization/Common/Hash.ts b/packages/core/src/Serialization/Common/Hash.ts new file mode 100644 index 00000000000..d6e232c00b8 --- /dev/null +++ b/packages/core/src/Serialization/Common/Hash.ts @@ -0,0 +1,33 @@ +import { CborReader, CborWriter } from '../CBOR'; +import { HexBlob } from '@cardano-sdk/util'; + +export class Hash { + #value: T; + + constructor(value: T) { + this.#value = value; + } + + toCbor() { + const writer = new CborWriter(); + writer.writeByteString(Buffer.from(this.#value, 'hex')); + return writer.encodeAsHex(); + } + + static fromCbor(cbor: HexBlob): Hash { + const reader = new CborReader(cbor); + return new Hash(HexBlob.fromBytes(reader.readByteString()) as unknown as T); + } + + toCore() { + return this.#value; + } + + static fromCore(hash: T): Hash { + return new Hash(hash); + } + + value() { + return this.#value; + } +} diff --git a/packages/core/src/Serialization/Common/index.ts b/packages/core/src/Serialization/Common/index.ts index 541187c3278..0f5b47809c4 100644 --- a/packages/core/src/Serialization/Common/index.ts +++ b/packages/core/src/Serialization/Common/index.ts @@ -5,3 +5,5 @@ export * from './Datum'; export * from './Anchor'; export * from './GovernanceActionId'; export * from './CborSet'; +export * from './Hash'; +export * from './Credential'; diff --git a/packages/core/src/Serialization/TransactionBody/ProposalProcedure/UpdateCommittee.ts b/packages/core/src/Serialization/TransactionBody/ProposalProcedure/UpdateCommittee.ts index df3dc21f081..51cd40aed74 100644 --- a/packages/core/src/Serialization/TransactionBody/ProposalProcedure/UpdateCommittee.ts +++ b/packages/core/src/Serialization/TransactionBody/ProposalProcedure/UpdateCommittee.ts @@ -1,12 +1,12 @@ /* eslint-disable max-statements */ import * as Cardano from '../../../Cardano'; import { CborReader, CborReaderState, CborWriter } from '../../CBOR'; -import { CommitteeMember, Credential, GovernanceActionType } from '../../../Cardano'; +import { CborSet, Credential, UnitInterval } from '../../Common'; +import { CommitteeMember, GovernanceActionType } from '../../../Cardano'; import { GovernanceActionId } from '../../Common/GovernanceActionId'; import { GovernanceActionKind } from './GovernanceActionKind'; import { Hash28ByteBase16 } from '@cardano-sdk/crypto'; import { HexBlob, InvalidArgumentError } from '@cardano-sdk/util'; -import { UnitInterval } from '../../Common'; import { hexToBytes } from '../../../util/misc'; const EMBEDDED_GROUP_SIZE = 5; @@ -14,10 +14,12 @@ const CREDENTIAL_ARRAY_SIZE = 2; const CREDENTIAL_INDEX = 0; const EPOCH_INDEX = 1; +type CredentialSet = CborSet, Credential>; + /** Modifies the composition of the constitutional committee, its signature threshold, or its terms of operation. */ export class UpdateCommittee { #govActionId: GovernanceActionId | undefined; - #membersToBeRemoved: Cardano.Credential[]; + #membersToBeRemoved: CredentialSet; #membersToBeAdded: [Cardano.Credential, number][]; #newQuorum: UnitInterval; #originalBytes: HexBlob | undefined = undefined; @@ -31,7 +33,7 @@ export class UpdateCommittee { * @param govActionId Previous governance action id of `UpdateCommittee`. */ constructor( - membersToBeRemoved: Cardano.Credential[], + membersToBeRemoved: CredentialSet, membersToBeAdded: [Cardano.Credential, number][], newQuorum: UnitInterval, govActionId?: GovernanceActionId @@ -58,12 +60,7 @@ export class UpdateCommittee { writer.writeInt(GovernanceActionKind.UpdateCommittee); this.#govActionId ? writer.writeEncodedValue(hexToBytes(this.#govActionId.toCbor())) : writer.writeNull(); - writer.writeStartArray(this.#membersToBeRemoved.length); - for (const entry of this.#membersToBeRemoved) { - writer.writeStartArray(CREDENTIAL_ARRAY_SIZE); - writer.writeInt(entry.type); - writer.writeByteString(hexToBytes(entry.hash as unknown as HexBlob)); - } + writer.writeEncodedValue(hexToBytes(this.#membersToBeRemoved.toCbor())); writer.writeStartMap(this.#membersToBeAdded.length); for (const entry of this.#membersToBeAdded) { @@ -111,24 +108,10 @@ export class UpdateCommittee { govActionId = GovernanceActionId.fromCbor(HexBlob.fromBytes(reader.readEncodedValue())); } - reader.readStartArray(); - - const membersToRemove: Cardano.Credential[] = []; - while (reader.peekState() !== CborReaderState.EndArray) { - if (reader.readStartArray() !== CREDENTIAL_ARRAY_SIZE) - throw new InvalidArgumentError( - 'cbor', - `Expected an array of ${CREDENTIAL_ARRAY_SIZE} elements, but got an array of ${length} elements` - ); - - const type = Number(reader.readUInt()); - const hash = HexBlob.fromBytes(reader.readByteString()) as unknown as Hash28ByteBase16; - - reader.readEndArray(); - membersToRemove.push({ hash, type }); - } - - reader.readEndArray(); + const membersToRemove: CredentialSet = CborSet.fromCbor( + HexBlob.fromBytes(reader.readEncodedValue()), + Credential.fromCbor + ); reader.readStartMap(); @@ -173,7 +156,7 @@ export class UpdateCommittee { epoch: Cardano.EpochNo(entry[EPOCH_INDEX]) })) ), - membersToBeRemoved: new Set(this.#membersToBeRemoved), + membersToBeRemoved: new Set(this.#membersToBeRemoved.toCore()), newQuorumThreshold: this.#newQuorum.toCore() }; } @@ -185,7 +168,7 @@ export class UpdateCommittee { */ static fromCore(updateCommittee: Cardano.UpdateCommittee) { return new UpdateCommittee( - [...updateCommittee.membersToBeRemoved], + CborSet.fromCore([...updateCommittee.membersToBeRemoved], Credential.fromCore), [...updateCommittee.membersToBeAdded].map((entry) => [entry.coldCredential, entry.epoch]), UnitInterval.fromCore(updateCommittee.newQuorumThreshold), updateCommittee.governanceActionId !== null @@ -209,7 +192,7 @@ export class UpdateCommittee { * @returns the committee members to be removed. */ membersToBeRemoved(): Cardano.Credential[] { - return this.#membersToBeRemoved; + return this.#membersToBeRemoved.toCore(); } /** diff --git a/packages/core/src/Serialization/TransactionBody/TransactionBody.ts b/packages/core/src/Serialization/TransactionBody/TransactionBody.ts index 7f71ea969ff..7d625ca9106 100644 --- a/packages/core/src/Serialization/TransactionBody/TransactionBody.ts +++ b/packages/core/src/Serialization/TransactionBody/TransactionBody.ts @@ -2,6 +2,7 @@ import * as Cardano from '../../Cardano'; import * as Crypto from '@cardano-sdk/crypto'; import { CborReader, CborReaderState, CborWriter } from '../CBOR'; +import { CborSet, Hash } from '../Common'; import { Certificate } from '../Certificates'; import { HexBlob } from '@cardano-sdk/util'; import { ProposalProcedure } from './ProposalProcedure'; @@ -10,32 +11,35 @@ import { TransactionInput } from './TransactionInput'; import { TransactionOutput } from './TransactionOutput'; import { Update } from '../Update'; import { VotingProcedures } from './VotingProcedures'; +import { hexToBytes } from '../../util/misc'; import { multiAssetsToTokenMap, sortCanonically, tokenMapToMultiAsset } from './Utils'; +type TransactionInputSet = CborSet, TransactionInput>; + /** The transaction body encapsulates the core details of a transaction. */ export class TransactionBody { // Required fields - #inputs: Array; + #inputs: TransactionInputSet; #outputs: Array; #fee: Cardano.Lovelace; // Optional fields #ttl: Cardano.Slot | undefined; - #certs: Array | undefined; + #certs: CborSet, Certificate> | undefined; #withdrawals: Map | undefined; #update: Update | undefined; #auxiliaryDataHash: Crypto.Hash32ByteBase16 | undefined; #validityStartInterval: Cardano.Slot | undefined; #mint: Cardano.TokenMap | undefined; #scriptDataHash: Crypto.Hash32ByteBase16 | undefined; - #collateral: Array | undefined; - #requiredSigners: Array | undefined; + #collateral: TransactionInputSet | undefined; + #requiredSigners: CborSet> | undefined; #networkId: Cardano.NetworkId | undefined; #collateralReturn: TransactionOutput | undefined; #totalCollateral: Cardano.Lovelace | undefined; - #referenceInputs: Array | undefined; + #referenceInputs: TransactionInputSet | undefined; #votingProcedures: VotingProcedures | undefined; - #proposalProcedures: Array | undefined; + #proposalProcedures: CborSet, ProposalProcedure> | undefined; #currentTreasuryValue: Cardano.Lovelace | undefined; #donation: Cardano.Lovelace | undefined; #originalBytes: HexBlob | undefined = undefined; @@ -49,7 +53,7 @@ export class TransactionBody { * @param ttl Specifies the slot number until which the transaction is valid. If the transaction isn't included in a block by this slot, it becomes invalid. */ constructor( - inputs: Array, + inputs: TransactionInputSet, outputs: Array, fee: Cardano.Lovelace, ttl?: Cardano.Slot @@ -95,13 +99,9 @@ export class TransactionBody { // } writer.writeStartMap(this.#getMapSize()); - if (this.#inputs && this.#inputs.length > 0) { + if (this.#inputs && this.#inputs.size() > 0) { writer.writeInt(0n); - writer.writeStartArray(this.#inputs.length); - - for (const input of this.#inputs) { - writer.writeEncodedValue(Buffer.from(input.toCbor(), 'hex')); - } + writer.writeEncodedValue(hexToBytes(this.#inputs.toCbor())); } if (this.#outputs && this.#outputs.length > 0) { @@ -121,13 +121,9 @@ export class TransactionBody { writer.writeInt(this.#ttl); } - if (this.#certs && this.#certs.length > 0) { + if (this.#certs && this.#certs.size() > 0) { writer.writeInt(4n); - writer.writeStartArray(this.#certs.length); - - for (const cert of this.#certs) { - writer.writeEncodedValue(Buffer.from(cert.toCbor(), 'hex')); - } + writer.writeEncodedValue(hexToBytes(this.#certs.toCbor())); } if (this.#withdrawals && this.#withdrawals.size > 0) { @@ -195,24 +191,14 @@ export class TransactionBody { writer.writeByteString(Buffer.from(this.#scriptDataHash, 'hex')); } - if (this.#collateral && this.#collateral.length > 0) { + if (this.#collateral && this.#collateral.size() > 0) { writer.writeInt(13n); - - writer.writeStartArray(this.#collateral.length); - - for (const input of this.#collateral) { - writer.writeEncodedValue(Buffer.from(input.toCbor(), 'hex')); - } + writer.writeEncodedValue(hexToBytes(this.#collateral.toCbor())); } - if (this.#requiredSigners && this.#requiredSigners.length > 0) { + if (this.#requiredSigners && this.#requiredSigners.size() > 0) { writer.writeInt(14n); - - writer.writeStartArray(this.#requiredSigners.length); - - for (const signer of this.#requiredSigners) { - writer.writeByteString(Buffer.from(signer, 'hex')); - } + writer.writeEncodedValue(hexToBytes(this.#requiredSigners.toCbor())); } if (this.#networkId) { @@ -230,14 +216,9 @@ export class TransactionBody { writer.writeInt(this.#totalCollateral); } - if (this.#referenceInputs && this.#referenceInputs.length > 0) { + if (this.#referenceInputs && this.#referenceInputs.size() > 0) { writer.writeInt(18n); - - writer.writeStartArray(this.#referenceInputs.length); - - for (const input of this.#referenceInputs) { - writer.writeEncodedValue(Buffer.from(input.toCbor(), 'hex')); - } + writer.writeEncodedValue(hexToBytes(this.#referenceInputs.toCbor())); } if (this.#votingProcedures) { @@ -245,13 +226,9 @@ export class TransactionBody { writer.writeEncodedValue(Buffer.from(this.#votingProcedures.toCbor(), 'hex')); } - if (this.#proposalProcedures && this.#proposalProcedures.length > 0) { + if (this.#proposalProcedures && this.#proposalProcedures.size() > 0) { writer.writeInt(20n); - writer.writeStartArray(this.#proposalProcedures.length); - - for (const procedure of this.#proposalProcedures) { - writer.writeEncodedValue(Buffer.from(procedure.toCbor(), 'hex')); - } + writer.writeEncodedValue(hexToBytes(this.#proposalProcedures.toCbor())); } if (this.#currentTreasuryValue) { @@ -276,7 +253,7 @@ export class TransactionBody { static fromCbor(cbor: HexBlob): TransactionBody { const reader = new CborReader(cbor); - const inputs: Array = new Array(); + const inputs = CborSet.fromCore([], TransactionInput.fromCore); const outputs: Array = new Array(); const fee: Cardano.Lovelace = 0n; const body = new TransactionBody(inputs, outputs, fee); @@ -288,14 +265,8 @@ export class TransactionBody { switch (key) { case 0n: { - reader.readStartArray(); - - while (reader.peekState() !== CborReaderState.EndArray) { - body.inputs().push(TransactionInput.fromCbor(HexBlob.fromBytes(reader.readEncodedValue()))); - } - - reader.readEndArray(); - + const inputsBytes = reader.readEncodedValue(); + body.setInputs(CborSet.fromCbor(HexBlob.fromBytes(inputsBytes), TransactionInput.fromCbor)); break; } case 1n: { @@ -316,14 +287,7 @@ export class TransactionBody { body.setTtl(Cardano.Slot(Number(reader.readInt()))); break; case 4n: { - reader.readStartArray(); - - body.setCerts(new Array()); - while (reader.peekState() !== CborReaderState.EndArray) { - body.certs()!.push(Certificate.fromCbor(HexBlob.fromBytes(reader.readEncodedValue()))); - } - - reader.readEndArray(); + body.setCerts(CborSet.fromCbor(HexBlob.fromBytes(reader.readEncodedValue()), Certificate.fromCbor)); break; } case 5n: { @@ -379,26 +343,15 @@ export class TransactionBody { body.setScriptDataHash(HexBlob.fromBytes(reader.readByteString()) as unknown as Crypto.Hash32ByteBase16); break; case 13n: - body.setCollateral(new Array()); - reader.readStartArray(); - - while (reader.peekState() !== CborReaderState.EndArray) { - body.collateral()!.push(TransactionInput.fromCbor(HexBlob.fromBytes(reader.readEncodedValue()))); - } - - reader.readEndArray(); + body.setCollateral(CborSet.fromCbor(HexBlob.fromBytes(reader.readEncodedValue()), TransactionInput.fromCbor)); break; case 14n: - body.setRequiredSigners(new Array()); - reader.readStartArray(); - - while (reader.peekState() !== CborReaderState.EndArray) { - body - .requiredSigners()! - .push(HexBlob.fromBytes(reader.readByteString()) as unknown as Crypto.Ed25519KeyHashHex); - } - - reader.readEndArray(); + body.setRequiredSigners( + CborSet.fromCbor>( + HexBlob.fromBytes(reader.readEncodedValue()), + Hash.fromCbor + ) + ); break; case 15n: body.setNetworkId(Number(reader.readInt()) as Cardano.NetworkId); @@ -410,27 +363,17 @@ export class TransactionBody { body.setTotalCollateral(reader.readInt()); break; case 18n: - body.setReferenceInputs(new Array()); - reader.readStartArray(); - - while (reader.peekState() !== CborReaderState.EndArray) { - body.referenceInputs()!.push(TransactionInput.fromCbor(HexBlob.fromBytes(reader.readEncodedValue()))); - } - - reader.readEndArray(); + body.setReferenceInputs( + CborSet.fromCbor(HexBlob.fromBytes(reader.readEncodedValue()), TransactionInput.fromCbor) + ); break; case 19n: body.setVotingProcedures(VotingProcedures.fromCbor(HexBlob.fromBytes(reader.readEncodedValue()))); break; case 20n: - body.setProposalProcedures(new Array()); - reader.readStartArray(); - - while (reader.peekState() !== CborReaderState.EndArray) { - body.proposalProcedures()!.push(ProposalProcedure.fromCbor(HexBlob.fromBytes(reader.readEncodedValue()))); - } - - reader.readEndArray(); + body.setProposalProcedures( + CborSet.fromCbor(HexBlob.fromBytes(reader.readEncodedValue()), ProposalProcedure.fromCbor) + ); break; case 21n: body.setCurrentTreasuryValue(reader.readInt()); @@ -456,20 +399,18 @@ export class TransactionBody { toCore(): Cardano.TxBody { return { auxiliaryDataHash: this.#auxiliaryDataHash, - certificates: this.#certs ? this.#certs.map((cert) => cert.toCore()) : undefined, + certificates: this.#certs?.values() ? this.#certs.toCore() : undefined, collateralReturn: this.#collateralReturn?.toCore(), - collaterals: this.#collateral ? this.#collateral.map((input) => input.toCore()) : undefined, + collaterals: this.#collateral?.values() ? this.#collateral.toCore() : undefined, donation: this.#donation, fee: this.#fee, - inputs: this.#inputs.map((input) => input.toCore()), + inputs: this.#inputs.toCore(), mint: this.#mint, networkId: this.#networkId, outputs: this.#outputs.map((output) => output.toCore()), - proposalProcedures: this.#proposalProcedures - ? this.#proposalProcedures.map((input) => input.toCore()) - : undefined, - referenceInputs: this.#referenceInputs ? this.#referenceInputs.map((input) => input.toCore()) : undefined, - requiredExtraSignatures: this.#requiredSigners, + proposalProcedures: this.#proposalProcedures?.values() ? this.#proposalProcedures.toCore() : undefined, + referenceInputs: this.#referenceInputs?.size() ? this.#referenceInputs.toCore() : undefined, + requiredExtraSignatures: this.#requiredSigners?.toCore(), scriptIntegrityHash: this.#scriptDataHash, totalCollateral: this.#totalCollateral, treasuryValue: this.#currentTreasuryValue, @@ -495,7 +436,8 @@ export class TransactionBody { */ static fromCore(coreTransactionBody: Cardano.TxBody): TransactionBody { const body = new TransactionBody( - coreTransactionBody.inputs.map((input) => TransactionInput.fromCore(input)), + CborSet.fromCore(coreTransactionBody.inputs, TransactionInput.fromCore), + // new CborSet(coreTransactionBody.inputs.map((input) => TransactionInput.fromCore(input))), coreTransactionBody.outputs.map((output) => TransactionOutput.fromCore(output)), coreTransactionBody.fee ); @@ -503,23 +445,23 @@ export class TransactionBody { if (coreTransactionBody.auxiliaryDataHash) body.setAuxiliaryDataHash(coreTransactionBody.auxiliaryDataHash); if (coreTransactionBody.certificates) - body.setCerts(coreTransactionBody.certificates.map((cert) => Certificate.fromCore(cert))); + body.setCerts(CborSet.fromCore(coreTransactionBody.certificates, Certificate.fromCore)); if (coreTransactionBody.collateralReturn) body.setCollateralReturn(TransactionOutput.fromCore(coreTransactionBody.collateralReturn)); if (coreTransactionBody.collaterals) - body.setCollateral(coreTransactionBody.collaterals.map((input) => TransactionInput.fromCore(input))); + body.setCollateral(CborSet.fromCore(coreTransactionBody.collaterals, TransactionInput.fromCore)); if (coreTransactionBody.mint) body.setMint(coreTransactionBody.mint); if (coreTransactionBody.networkId) body.setNetworkId(coreTransactionBody.networkId); if (coreTransactionBody.referenceInputs) - body.setReferenceInputs(coreTransactionBody.referenceInputs.map((input) => TransactionInput.fromCore(input))); + body.setReferenceInputs(CborSet.fromCore(coreTransactionBody.referenceInputs, TransactionInput.fromCore)); if (coreTransactionBody.requiredExtraSignatures) - body.setRequiredSigners(coreTransactionBody.requiredExtraSignatures); + body.setRequiredSigners(CborSet.fromCore(coreTransactionBody.requiredExtraSignatures, Hash.fromCore)); if (coreTransactionBody.scriptIntegrityHash) body.setScriptDataHash(coreTransactionBody.scriptIntegrityHash); @@ -547,9 +489,7 @@ export class TransactionBody { if (coreTransactionBody.votingProcedures) body.setVotingProcedures(VotingProcedures.fromCore(coreTransactionBody.votingProcedures)); if (coreTransactionBody.proposalProcedures) - body.setProposalProcedures( - coreTransactionBody.proposalProcedures.map((core) => ProposalProcedure.fromCore(core)) - ); + body.setProposalProcedures(CborSet.fromCore(coreTransactionBody.proposalProcedures, ProposalProcedure.fromCore)); return body; } @@ -560,7 +500,7 @@ export class TransactionBody { * * @param inputs the list of references to UTxOs. */ - setInputs(inputs: Array) { + setInputs(inputs: TransactionInputSet) { this.#inputs = inputs; this.#originalBytes = undefined; } @@ -571,7 +511,7 @@ export class TransactionBody { * * @returns The list of references to UTxOs. */ - inputs(): Array { + inputs() { return this.#inputs; } @@ -644,7 +584,7 @@ export class TransactionBody { * * @param certs The certificates to be issued by this transaction. */ - setCerts(certs: Array): void { + setCerts(certs: CborSet, Certificate>): void { this.#certs = certs; this.#originalBytes = undefined; } @@ -655,7 +595,7 @@ export class TransactionBody { * * @returns The certificates to be issued by this transaction. */ - certs(): Array | undefined { + certs() { return this.#certs; } @@ -785,7 +725,7 @@ export class TransactionBody { * * @param collateral The UTxOs that a sender commits to forfeit. */ - setCollateral(collateral: Array): void { + setCollateral(collateral: TransactionInputSet): void { this.#collateral = collateral; this.#originalBytes = undefined; } @@ -796,7 +736,7 @@ export class TransactionBody { * * @returns The UTxOs that a sender commits to forfeit. */ - collateral(): Array | undefined { + collateral() { return this.#collateral; } @@ -805,7 +745,7 @@ export class TransactionBody { * * @param requiredSigners The set of keys which need to sign a transaction */ - setRequiredSigners(requiredSigners: Array): void { + setRequiredSigners(requiredSigners: CborSet>): void { this.#requiredSigners = requiredSigners; this.#originalBytes = undefined; } @@ -815,7 +755,7 @@ export class TransactionBody { * * @returns The set of keys which need to sign a transaction */ - requiredSigners(): Array | undefined { + requiredSigners() { return this.#requiredSigners; } @@ -891,7 +831,7 @@ export class TransactionBody { * Reference inputs allows looking at an output without spending it. This facilitates access to information * stored on the blockchain without the need of spending and recreating UTxOs. */ - setReferenceInputs(referenceInputs: Array): void { + setReferenceInputs(referenceInputs: TransactionInputSet): void { this.#referenceInputs = referenceInputs; this.#originalBytes = undefined; } @@ -901,7 +841,7 @@ export class TransactionBody { * * @returns the reference inputs. */ - referenceInputs(): Array | undefined { + referenceInputs() { return this.#referenceInputs; } @@ -929,7 +869,7 @@ export class TransactionBody { * * @param proposalProcedure the proposal procedures. */ - setProposalProcedures(proposalProcedure: Array): void { + setProposalProcedures(proposalProcedure: CborSet, ProposalProcedure>): void { this.#proposalProcedures = proposalProcedure; this.#originalBytes = undefined; } @@ -939,7 +879,7 @@ export class TransactionBody { * * @returns the proposal procedures. */ - proposalProcedures(): Array | undefined { + proposalProcedures() { return this.#proposalProcedures; } @@ -989,25 +929,25 @@ export class TransactionBody { #getMapSize(): number { let mapSize = 0; - if (this.#inputs !== undefined && this.#inputs.length > 0) ++mapSize; + if (this.#inputs !== undefined && this.#inputs.size() > 0) ++mapSize; if (this.#outputs !== undefined && this.#outputs.length > 0) ++mapSize; if (this.#fee !== undefined) ++mapSize; if (this.#ttl !== undefined) ++mapSize; - if (this.#certs !== undefined && this.#certs.length > 0) ++mapSize; + if (this.#certs !== undefined && this.#certs.size() > 0) ++mapSize; if (this.#withdrawals !== undefined && this.#withdrawals.size > 0) ++mapSize; if (this.#update !== undefined) ++mapSize; if (this.#auxiliaryDataHash !== undefined) ++mapSize; if (this.#validityStartInterval !== undefined) ++mapSize; if (this.#mint !== undefined && this.#mint.size > 0) ++mapSize; if (this.#scriptDataHash !== undefined) ++mapSize; - if (this.#collateral !== undefined && this.#collateral.length > 0) ++mapSize; - if (this.#requiredSigners !== undefined && this.#requiredSigners.length > 0) ++mapSize; + if (this.#collateral !== undefined && this.#collateral.size() > 0) ++mapSize; + if (this.#requiredSigners?.values() !== undefined && this.#requiredSigners.size() > 0) ++mapSize; if (this.#networkId !== undefined) ++mapSize; if (this.#collateralReturn !== undefined) ++mapSize; if (this.#totalCollateral !== undefined) ++mapSize; - if (this.#referenceInputs !== undefined && this.#referenceInputs.length > 0) ++mapSize; + if (this.#referenceInputs !== undefined && this.#referenceInputs.size() > 0) ++mapSize; if (this.#votingProcedures !== undefined) ++mapSize; - if (this.#proposalProcedures !== undefined && this.#proposalProcedures.length > 0) ++mapSize; + if (this.#proposalProcedures !== undefined && this.#proposalProcedures.size() > 0) ++mapSize; if (this.#currentTreasuryValue !== undefined) ++mapSize; if (this.#donation !== undefined) ++mapSize; diff --git a/packages/core/src/Serialization/TransactionWitnessSet/TransactionWitnessSet.ts b/packages/core/src/Serialization/TransactionWitnessSet/TransactionWitnessSet.ts index 7408a25b9d5..c8b73b9e56e 100644 --- a/packages/core/src/Serialization/TransactionWitnessSet/TransactionWitnessSet.ts +++ b/packages/core/src/Serialization/TransactionWitnessSet/TransactionWitnessSet.ts @@ -2,20 +2,23 @@ import * as Cardano from '../../Cardano'; import { BootstrapWitness } from './BootstrapWitness'; import { CborReader, CborReaderState, CborWriter } from '../CBOR'; +import { CborSet } from '../Common'; import { HexBlob } from '@cardano-sdk/util'; import { NativeScript, PlutusV1Script, PlutusV2Script, PlutusV3Script } from '../Scripts'; import { PlutusData } from '../PlutusData/PlutusData'; import { Redeemer } from './Redeemer'; import { SerializationError, SerializationFailure } from '../../errors'; import { VkeyWitness } from './VkeyWitness'; +import { hexToBytes } from '../../util/misc'; +import _groupBy from 'lodash/groupBy'; import uniqWith from 'lodash/uniqWith'; /** This type represents the segregated CDDL scripts. */ type CddlScripts = { - native: Array | undefined; - plutusV1: Array | undefined; - plutusV2: Array | undefined; - plutusV3: Array | undefined; + native?: CborSet, NativeScript>; + plutusV1?: CborSet, PlutusV1Script>; + plutusV2?: CborSet, PlutusV2Script>; + plutusV3?: CborSet, PlutusV3Script>; }; /** @@ -27,14 +30,14 @@ type CddlScripts = { * smart contract execution. */ export class TransactionWitnessSet { - #vkeywitnesses: Array | undefined; - #nativeScripts: Array | undefined; - #bootstrapWitnesses: Array | undefined; - #plutusV1Scripts: Array | undefined; - #plutusData: Array | undefined; + #vkeywitnesses: CborSet, VkeyWitness> | undefined; + #nativeScripts: CborSet, NativeScript> | undefined; + #bootstrapWitnesses: CborSet, BootstrapWitness> | undefined; + #plutusV1Scripts: CborSet, PlutusV1Script> | undefined; + #plutusData: CborSet, PlutusData> | undefined; #redeemers: Array | undefined; - #plutusV2Scripts: Array | undefined; - #plutusV3Scripts: Array | undefined; + #plutusV2Scripts: CborSet, PlutusV2Script> | undefined; + #plutusV3Scripts: CborSet, PlutusV3Script> | undefined; #originalBytes: HexBlob | undefined = undefined; /** @@ -49,64 +52,48 @@ export class TransactionWitnessSet { // CDDL // transaction_witness_set = - // { ? 0: [* vkeywitness ] - // , ? 1: [* native_script ] - // , ? 2: [* bootstrap_witness ] - // , ? 3: [* plutus_v1_script ] - // , ? 4: [* plutus_data ] - // , ? 5: [* redeemer ] - // , ? 6: [* plutus_v2_script ] - // , ? 7: [* plutus_v3_script ] + // { ? 0: nonempty_set + // , ? 1: nonempty_set + // , ? 2: nonempty_set + // , ? 3: nonempty_set + // , ? 4: nonempty_set + // , ? 5: redeemers + // , ? 6: nonempty_set + // , ? 7: nonempty_set // } + // + // redeemers = + // [ + [ tag: redeemer_tag, index: uint, data: plutus_data, ex_units: ex_units ] ] + // / { + [ tag: redeemer_tag, index: uint ] => [ data: plutus_data, ex_units: ex_units ] } writer.writeStartMap(this.#getMapSize()); - if (this.#vkeywitnesses && this.#vkeywitnesses.length > 0) { - const uniqueWitnesses = uniqWith(this.#vkeywitnesses, (lhs, rhs) => lhs.vkey() === rhs.vkey()); - + if (this.#vkeywitnesses && this.#vkeywitnesses.size() > 0) { + this.#vkeywitnesses.setValues(uniqWith(this.#vkeywitnesses.values(), (lhs, rhs) => lhs.vkey() === rhs.vkey())); writer.writeInt(0n); - writer.writeStartArray(uniqueWitnesses.length); - - for (const witness of uniqueWitnesses) { - writer.writeEncodedValue(Buffer.from(witness.toCbor(), 'hex')); - } + writer.writeEncodedValue(Buffer.from(this.#vkeywitnesses.toCbor(), 'hex')); } - if (this.#nativeScripts && this.#nativeScripts.length > 0) { + if (this.#nativeScripts && this.#nativeScripts.size() > 0) { writer.writeInt(1n); - writer.writeStartArray(this.#nativeScripts.length); - - for (const script of this.#nativeScripts) { - writer.writeEncodedValue(Buffer.from(script.toCbor(), 'hex')); - } + writer.writeEncodedValue(Buffer.from(this.#nativeScripts.toCbor(), 'hex')); } - if (this.#bootstrapWitnesses && this.#bootstrapWitnesses.length > 0) { - const uniqueWitnesses = uniqWith(this.#bootstrapWitnesses, (lhs, rhs) => lhs.vkey() === rhs.vkey()); - + if (this.#bootstrapWitnesses && this.#bootstrapWitnesses.size() > 0) { + this.#bootstrapWitnesses.setValues( + uniqWith(this.#bootstrapWitnesses.values(), (lhs, rhs) => lhs.vkey() === rhs.vkey()) + ); writer.writeInt(2n); - writer.writeStartArray(uniqueWitnesses.length); - - for (const witness of uniqueWitnesses) { - writer.writeEncodedValue(Buffer.from(witness.toCbor(), 'hex')); - } + writer.writeEncodedValue(Buffer.from(this.#bootstrapWitnesses.toCbor(), 'hex')); } - if (this.#plutusV1Scripts && this.#plutusV1Scripts.length > 0) { + if (this.#plutusV1Scripts && this.#plutusV1Scripts.size() > 0) { writer.writeInt(3n); - writer.writeStartArray(this.#plutusV1Scripts.length); - - for (const script of this.#plutusV1Scripts) { - writer.writeEncodedValue(Buffer.from(script.toCbor(), 'hex')); - } + writer.writeEncodedValue(Buffer.from(this.#plutusV1Scripts.toCbor(), 'hex')); } - if (this.#plutusData && this.#plutusData.length > 0) { + if (this.#plutusData && this.#plutusData.size() > 0) { writer.writeInt(4n); - writer.writeStartArray(this.#plutusData.length); - - for (const data of this.#plutusData) { - writer.writeEncodedValue(Buffer.from(data.toCbor(), 'hex')); - } + writer.writeEncodedValue(Buffer.from(this.#plutusData.toCbor(), 'hex')); } if (this.#redeemers && this.#redeemers.length > 0) { @@ -118,22 +105,14 @@ export class TransactionWitnessSet { } } - if (this.#plutusV2Scripts && this.#plutusV2Scripts.length > 0) { + if (this.#plutusV2Scripts && this.#plutusV2Scripts.size() > 0) { writer.writeInt(6n); - writer.writeStartArray(this.#plutusV2Scripts.length); - - for (const script of this.#plutusV2Scripts) { - writer.writeEncodedValue(Buffer.from(script.toCbor(), 'hex')); - } + writer.writeEncodedValue(Buffer.from(this.#plutusV2Scripts.toCbor(), 'hex')); } - if (this.#plutusV3Scripts && this.#plutusV3Scripts.length > 0) { + if (this.#plutusV3Scripts && this.#plutusV3Scripts.size() > 0) { writer.writeInt(7n); - writer.writeStartArray(this.#plutusV3Scripts.length); - - for (const script of this.#plutusV3Scripts) { - writer.writeEncodedValue(Buffer.from(script.toCbor(), 'hex')); - } + writer.writeEncodedValue(Buffer.from(this.#plutusV3Scripts.toCbor(), 'hex')); } return writer.encodeAsHex(); @@ -157,54 +136,25 @@ export class TransactionWitnessSet { switch (key) { case 0n: - witness.setVkeys(new Array()); - reader.readStartArray(); - - while (reader.peekState() !== CborReaderState.EndArray) { - witness.vkeys()!.push(VkeyWitness.fromCbor(HexBlob.fromBytes(reader.readEncodedValue()))); - } - - reader.readEndArray(); + witness.setVkeys(CborSet.fromCbor(HexBlob.fromBytes(reader.readEncodedValue()), VkeyWitness.fromCbor)); break; case 1n: - witness.setNativeScripts(new Array()); - reader.readStartArray(); - - while (reader.peekState() !== CborReaderState.EndArray) { - witness.nativeScripts()!.push(NativeScript.fromCbor(HexBlob.fromBytes(reader.readEncodedValue()))); - } - - reader.readEndArray(); + witness.setNativeScripts( + CborSet.fromCbor(HexBlob.fromBytes(reader.readEncodedValue()), NativeScript.fromCbor) + ); break; case 2n: - witness.setBootstraps(new Array()); - reader.readStartArray(); - - while (reader.peekState() !== CborReaderState.EndArray) { - witness.bootstraps()!.push(BootstrapWitness.fromCbor(HexBlob.fromBytes(reader.readEncodedValue()))); - } - - reader.readEndArray(); + witness.setBootstraps( + CborSet.fromCbor(HexBlob.fromBytes(reader.readEncodedValue()), BootstrapWitness.fromCbor) + ); break; case 3n: - witness.setPlutusV1Scripts(new Array()); - reader.readStartArray(); - - while (reader.peekState() !== CborReaderState.EndArray) { - witness.plutusV1Scripts()!.push(PlutusV1Script.fromCbor(HexBlob.fromBytes(reader.readEncodedValue()))); - } - - reader.readEndArray(); + witness.setPlutusV1Scripts( + CborSet.fromCbor(HexBlob.fromBytes(reader.readEncodedValue()), PlutusV1Script.fromCbor) + ); break; case 4n: - witness.setPlutusData(new Array()); - reader.readStartArray(); - - while (reader.peekState() !== CborReaderState.EndArray) { - witness.plutusData()!.push(PlutusData.fromCbor(HexBlob.fromBytes(reader.readEncodedValue()))); - } - - reader.readEndArray(); + witness.setPlutusData(CborSet.fromCbor(HexBlob.fromBytes(reader.readEncodedValue()), PlutusData.fromCbor)); break; case 5n: witness.setRedeemers(new Array()); @@ -217,24 +167,14 @@ export class TransactionWitnessSet { reader.readEndArray(); break; case 6n: - witness.setPlutusV2Scripts(new Array()); - reader.readStartArray(); - - while (reader.peekState() !== CborReaderState.EndArray) { - witness.plutusV2Scripts()!.push(PlutusV2Script.fromCbor(HexBlob.fromBytes(reader.readEncodedValue()))); - } - - reader.readEndArray(); + witness.setPlutusV2Scripts( + CborSet.fromCbor(HexBlob.fromBytes(reader.readEncodedValue()), PlutusV2Script.fromCbor) + ); break; case 7n: - witness.setPlutusV3Scripts(new Array()); - reader.readStartArray(); - - while (reader.peekState() !== CborReaderState.EndArray) { - witness.plutusV3Scripts()!.push(PlutusV3Script.fromCbor(HexBlob.fromBytes(reader.readEncodedValue()))); - } - - reader.readEndArray(); + witness.setPlutusV3Scripts( + CborSet.fromCbor(HexBlob.fromBytes(reader.readEncodedValue()), PlutusV3Script.fromCbor) + ); break; } } @@ -254,11 +194,11 @@ export class TransactionWitnessSet { toCore(): Cardano.Witness { const scripts = this.#getCoreScripts(); return { - bootstrap: this.#bootstrapWitnesses ? this.#bootstrapWitnesses.map((witness) => witness.toCore()) : undefined, - datums: this.#plutusData ? this.#plutusData.map((data) => data.toCore()) : undefined, + bootstrap: this.#bootstrapWitnesses ? this.#bootstrapWitnesses.toCore() : undefined, + datums: this.#plutusData ? this.#plutusData.toCore() : undefined, redeemers: this.#redeemers ? this.#redeemers.map((data) => data.toCore()) : undefined, scripts: scripts.length > 0 ? scripts : undefined, - signatures: this.#vkeywitnesses ? new Map(this.#vkeywitnesses.map((witness) => witness.toCore())) : new Map() + signatures: this.#vkeywitnesses ? new Map(this.#vkeywitnesses.toCore()) : new Map() }; } @@ -271,7 +211,7 @@ export class TransactionWitnessSet { const witness = new TransactionWitnessSet(); if (coreWitness.signatures) { - witness.setVkeys([...coreWitness.signatures].map((vkWitness) => VkeyWitness.fromCore(vkWitness))); + witness.setVkeys(CborSet.fromCore([...coreWitness.signatures], VkeyWitness.fromCore)); } if (coreWitness.scripts) { @@ -288,11 +228,11 @@ export class TransactionWitnessSet { } if (coreWitness.datums) { - witness.setPlutusData(coreWitness.datums.map((data) => PlutusData.fromCore(data))); + witness.setPlutusData(CborSet.fromCore(coreWitness.datums, PlutusData.fromCore)); } if (coreWitness.bootstrap) { - witness.setBootstraps(coreWitness.bootstrap.map((bootstrap) => BootstrapWitness.fromCore(bootstrap))); + witness.setBootstraps(CborSet.fromCore(coreWitness.bootstrap, BootstrapWitness.fromCore)); } return witness; @@ -304,7 +244,7 @@ export class TransactionWitnessSet { * * @param vkeys The set of verification key witnesses. */ - setVkeys(vkeys: Array) { + setVkeys(vkeys: CborSet, VkeyWitness>) { this.#vkeywitnesses = vkeys; this.#originalBytes = undefined; } @@ -315,7 +255,7 @@ export class TransactionWitnessSet { * * @returns The set of verification key witnesses. */ - vkeys(): Array | undefined { + vkeys() { return this.#vkeywitnesses; } @@ -324,7 +264,7 @@ export class TransactionWitnessSet { * * @param nativeScripts The set of native scripts. */ - setNativeScripts(nativeScripts: Array) { + setNativeScripts(nativeScripts: CborSet, NativeScript>) { this.#nativeScripts = nativeScripts; this.#originalBytes = undefined; } @@ -334,7 +274,7 @@ export class TransactionWitnessSet { * * @returns The set of native scripts. */ - nativeScripts(): Array | undefined { + nativeScripts() { return this.#nativeScripts; } @@ -343,7 +283,7 @@ export class TransactionWitnessSet { * * @param bootstraps The Bootstrap witnesses for this transaction. */ - setBootstraps(bootstraps: Array) { + setBootstraps(bootstraps: CborSet, BootstrapWitness>) { this.#bootstrapWitnesses = bootstraps; this.#originalBytes = undefined; } @@ -353,7 +293,7 @@ export class TransactionWitnessSet { * * @returns The Bootstrap witnesses for this transaction. */ - bootstraps(): Array | undefined { + bootstraps() { return this.#bootstrapWitnesses; } @@ -362,7 +302,7 @@ export class TransactionWitnessSet { * * @param plutusV1Scripts The set of plutus v1 scripts. */ - setPlutusV1Scripts(plutusV1Scripts: Array) { + setPlutusV1Scripts(plutusV1Scripts: CborSet, PlutusV1Script>) { this.#plutusV1Scripts = plutusV1Scripts; this.#originalBytes = undefined; } @@ -372,7 +312,7 @@ export class TransactionWitnessSet { * * @returns The set of plutus v1 scripts. */ - plutusV1Scripts(): Array | undefined { + plutusV1Scripts() { return this.#plutusV1Scripts; } @@ -381,7 +321,7 @@ export class TransactionWitnessSet { * * @param plutusData The Plutus Data. */ - setPlutusData(plutusData: Array) { + setPlutusData(plutusData: CborSet, PlutusData>) { this.#plutusData = plutusData; this.#originalBytes = undefined; } @@ -391,7 +331,7 @@ export class TransactionWitnessSet { * * @returns The Plutus Data. */ - plutusData(): Array | undefined { + plutusData() { return this.#plutusData; } @@ -419,7 +359,7 @@ export class TransactionWitnessSet { * * @param plutusV2Scripts The set of plutus v2 scripts. */ - setPlutusV2Scripts(plutusV2Scripts: Array) { + setPlutusV2Scripts(plutusV2Scripts: CborSet, PlutusV2Script>) { this.#plutusV2Scripts = plutusV2Scripts; this.#originalBytes = undefined; } @@ -429,7 +369,7 @@ export class TransactionWitnessSet { * * @returns The set of plutus v2 scripts. */ - plutusV2Scripts(): Array | undefined { + plutusV2Scripts() { return this.#plutusV2Scripts; } @@ -438,7 +378,7 @@ export class TransactionWitnessSet { * * @param plutusV3Scripts The set of plutus v3 scripts. */ - setPlutusV3Scripts(plutusV3Scripts: Array) { + setPlutusV3Scripts(plutusV3Scripts: CborSet, PlutusV3Script>) { this.#plutusV3Scripts = plutusV3Scripts; this.#originalBytes = undefined; } @@ -448,7 +388,7 @@ export class TransactionWitnessSet { * * @returns The set of plutus v3 scripts. */ - plutusV3Scripts(): Array | undefined { + plutusV3Scripts() { return this.#plutusV3Scripts; } @@ -459,10 +399,10 @@ export class TransactionWitnessSet { * @private */ #getCoreScripts(): Array { - const plutusV1 = this.#plutusV1Scripts ? this.#plutusV1Scripts.map((script) => script.toCore()) : []; - const plutusV2 = this.#plutusV2Scripts ? this.#plutusV2Scripts.map((script) => script.toCore()) : []; - const plutusV3 = this.#plutusV3Scripts ? this.#plutusV3Scripts.map((script) => script.toCore()) : []; - const native = this.#nativeScripts ? this.#nativeScripts.map((script) => script.toCore()) : []; + const plutusV1 = this.#plutusV1Scripts ? this.#plutusV1Scripts.toCore() : []; + const plutusV2 = this.#plutusV2Scripts ? this.#plutusV2Scripts.toCore() : []; + const plutusV3 = this.#plutusV3Scripts ? this.#plutusV3Scripts.toCore() : []; + const native = this.#nativeScripts ? this.#nativeScripts.toCore() : []; return [...plutusV1, ...plutusV2, ...plutusV3, ...native]; } @@ -474,36 +414,46 @@ export class TransactionWitnessSet { * @private */ static #getCddlScripts(scripts: Array): CddlScripts { - const result: CddlScripts = { native: undefined, plutusV1: undefined, plutusV2: undefined, plutusV3: undefined }; - - for (const script of scripts) { - switch (script.__type) { - case Cardano.ScriptType.Native: - if (!result.native) result.native = new Array(); - - result.native.push(NativeScript.fromCore(script)); + const [coreNative, coreV1, coreV2, coreV3] = scripts.reduce< + [ + Cardano.NativeScript[] | null, + Cardano.PlutusScript[] | null, + Cardano.PlutusScript[] | null, + Cardano.PlutusScript[] | null + ] + >( + ([native, v1, v2, v3], script) => { + if (script.__type === Cardano.ScriptType.Native) { + native ? native.push(script) : (native = [script]); + } else { + switch (script.version) { + case Cardano.PlutusLanguageVersion.V1: + v1 ? v1.push(script) : (v1 = [script]); + break; + case Cardano.PlutusLanguageVersion.V2: + v2 ? v2.push(script) : (v2 = [script]); break; - case Cardano.ScriptType.Plutus: - if (script.version === Cardano.PlutusLanguageVersion.V1) { - if (!result.plutusV1) result.plutusV1 = new Array(); - - result.plutusV1.push(PlutusV1Script.fromCore(script)); - } else if (script.version === Cardano.PlutusLanguageVersion.V2) { - if (!result.plutusV2) result.plutusV2 = new Array(); - - result.plutusV2.push(PlutusV2Script.fromCore(script)); - } else if (script.version === Cardano.PlutusLanguageVersion.V3) { - if (!result.plutusV3) result.plutusV3 = new Array(); - - result.plutusV3.push(PlutusV3Script.fromCore(script)); - } + case Cardano.PlutusLanguageVersion.V3: + v3 ? v3.push(script) : (v3 = [script]); break; default: - throw new SerializationError(SerializationFailure.InvalidScriptType, `Script '${script}' is not supported.`); + throw new SerializationError( + SerializationFailure.InvalidScriptType, + `Script '${script}' is not supported.` + ); } } + return [native, v1, v2, v3]; + }, + [null, null, null, null] + ); - return result; + return { + ...(coreNative && { native: CborSet.fromCore(coreNative, NativeScript.fromCore) }), + ...(coreV1 && { plutusV1: CborSet.fromCore(coreV1, PlutusV1Script.fromCore) }), + ...(coreV2 && { plutusV2: CborSet.fromCore(coreV2, PlutusV2Script.fromCore) }), + ...(coreV3 && { plutusV3: CborSet.fromCore(coreV3, PlutusV3Script.fromCore) }) + }; } /** @@ -514,14 +464,14 @@ export class TransactionWitnessSet { #getMapSize(): number { let mapSize = 0; - if (this.#vkeywitnesses !== undefined && this.#vkeywitnesses.length > 0) ++mapSize; - if (this.#nativeScripts !== undefined && this.#nativeScripts.length > 0) ++mapSize; - if (this.#bootstrapWitnesses !== undefined && this.#bootstrapWitnesses.length > 0) ++mapSize; - if (this.#plutusV1Scripts !== undefined && this.#plutusV1Scripts.length > 0) ++mapSize; - if (this.#plutusData !== undefined && this.#plutusData.length > 0) ++mapSize; + if (this.#vkeywitnesses !== undefined && this.#vkeywitnesses.size() > 0) ++mapSize; + if (this.#nativeScripts !== undefined && this.#nativeScripts.size() > 0) ++mapSize; + if (this.#bootstrapWitnesses !== undefined && this.#bootstrapWitnesses.size() > 0) ++mapSize; + if (this.#plutusV1Scripts !== undefined && this.#plutusV1Scripts.size() > 0) ++mapSize; + if (this.#plutusData !== undefined && this.#plutusData.size() > 0) ++mapSize; if (this.#redeemers !== undefined && this.#redeemers.length > 0) ++mapSize; - if (this.#plutusV2Scripts !== undefined && this.#plutusV2Scripts.length > 0) ++mapSize; - if (this.#plutusV3Scripts !== undefined && this.#plutusV3Scripts.length > 0) ++mapSize; + if (this.#plutusV2Scripts !== undefined && this.#plutusV2Scripts.size() > 0) ++mapSize; + if (this.#plutusV3Scripts !== undefined && this.#plutusV3Scripts.size() > 0) ++mapSize; return mapSize; } diff --git a/packages/core/test/Serialization/Certificates/Certificate.test.ts b/packages/core/test/Serialization/Certificates/Certificate.test.ts index 54c29bee84a..d32e624dcf9 100644 --- a/packages/core/test/Serialization/Certificates/Certificate.test.ts +++ b/packages/core/test/Serialization/Certificates/Certificate.test.ts @@ -344,6 +344,7 @@ describe('Certificate', () => { expect( params .poolOwners() + .toCore() .map((keyHash) => Cardano.createRewardAccount(keyHash, params.rewardAccount().toAddress().getNetworkId())) ).toEqual([Cardano.RewardAccount('stake1u89sasnfyjtmgk8ydqfv3fdl52f36x3djedfnzfc9rkgzrcss5vgr')]); expect(params.relays().map((relay) => relay.toCore())).toEqual([ @@ -392,6 +393,7 @@ describe('Certificate', () => { expect( params .poolOwners() + .toCore() .map((keyHash) => Cardano.createRewardAccount(keyHash, params.rewardAccount().toAddress().getNetworkId())) ).toEqual([Cardano.RewardAccount('stake1u89sasnfyjtmgk8ydqfv3fdl52f36x3djedfnzfc9rkgzrcss5vgr')]); expect(params.relays().map((relay) => relay.toCore())).toEqual([ diff --git a/packages/core/test/Serialization/Certificates/PoolParams/PoolParams.test.ts b/packages/core/test/Serialization/Certificates/PoolParams/PoolParams.test.ts index 2490ac29e55..3d7a6b451e2 100644 --- a/packages/core/test/Serialization/Certificates/PoolParams/PoolParams.test.ts +++ b/packages/core/test/Serialization/Certificates/PoolParams/PoolParams.test.ts @@ -52,6 +52,7 @@ describe('PoolParams', () => { expect( params .poolOwners() + .toCore() .map((keyHash) => Cardano.createRewardAccount(keyHash, params.rewardAccount().toAddress().getNetworkId())) ).toEqual([Cardano.RewardAccount('stake1u89sasnfyjtmgk8ydqfv3fdl52f36x3djedfnzfc9rkgzrcss5vgr')]); expect(params.relays().map((relay) => relay.toCore())).toEqual([ @@ -87,6 +88,7 @@ describe('PoolParams', () => { expect( params .poolOwners() + .toCore() .map((keyHash) => Cardano.createRewardAccount(keyHash, params.rewardAccount().toAddress().getNetworkId())) ).toEqual([Cardano.RewardAccount('stake1u89sasnfyjtmgk8ydqfv3fdl52f36x3djedfnzfc9rkgzrcss5vgr')]); expect(params.relays().map((relay) => relay.toCore())).toEqual([ diff --git a/packages/core/test/Serialization/Certificates/PoolRegistration.test.ts b/packages/core/test/Serialization/Certificates/PoolRegistration.test.ts index 89a2e5e680c..481720815a0 100644 --- a/packages/core/test/Serialization/Certificates/PoolRegistration.test.ts +++ b/packages/core/test/Serialization/Certificates/PoolRegistration.test.ts @@ -8,6 +8,10 @@ const cbor = HexBlob( '8a03581cd85087c646951407198c27b1b950fd2e99f28586c000ce39f6e6ef9258208dd154228946bd12967c12bedb1cb6038b78f8b84a1760b1a788fa72a4af3db01927101903e8d81e820105581de1cb0ec2692497b458e46812c8a5bfa2931d1a2d965a99893828ec810f81581ccb0ec2692497b458e46812c8a5bfa2931d1a2d965a99893828ec810f8383011913886b6578616d706c652e636f6d8400191770447f000001f682026b6578616d706c652e636f6d827368747470733a2f2f6578616d706c652e636f6d58200f3abbc8fc19c2e61bab6059bf8a466e6e754833a08a62a6c56fe0e78f19d9d5' ); +const cborWithSets = HexBlob( + '8a03581cd85087c646951407198c27b1b950fd2e99f28586c000ce39f6e6ef9258208dd154228946bd12967c12bedb1cb6038b78f8b84a1760b1a788fa72a4af3db01927101903e8d81e820105581de1cb0ec2692497b458e46812c8a5bfa2931d1a2d965a99893828ec810fd9010281581ccb0ec2692497b458e46812c8a5bfa2931d1a2d965a99893828ec810f8383011913886b6578616d706c652e636f6d8400191770447f000001f682026b6578616d706c652e636f6d827368747470733a2f2f6578616d706c652e636f6d58200f3abbc8fc19c2e61bab6059bf8a466e6e754833a08a62a6c56fe0e78f19d9d5' +); + const poolParameters: Cardano.PoolParameters = { cost: 1000n, id: Cardano.PoolId('pool1mpgg03jxj52qwxvvy7cmj58a96vl9pvxcqqvuw0kumheygxmn34'), @@ -57,6 +61,7 @@ describe('PoolRegistration', () => { expect( params .poolOwners() + .toCore() .map((keyHash) => Cardano.createRewardAccount(keyHash, params.rewardAccount().toAddress().getNetworkId())) ).toEqual([Cardano.RewardAccount('stake1u89sasnfyjtmgk8ydqfv3fdl52f36x3djedfnzfc9rkgzrcss5vgr')]); expect(params.relays().map((relay) => relay.toCore())).toEqual([ @@ -93,6 +98,7 @@ describe('PoolRegistration', () => { expect( params .poolOwners() + .toCore() .map((keyHash) => Cardano.createRewardAccount(keyHash, params.rewardAccount().toAddress().getNetworkId())) ).toEqual([Cardano.RewardAccount('stake1u89sasnfyjtmgk8ydqfv3fdl52f36x3djedfnzfc9rkgzrcss5vgr')]); expect(params.relays().map((relay) => relay.toCore())).toEqual([ @@ -121,4 +127,9 @@ describe('PoolRegistration', () => { expect(certificate.toCore()).toEqual(core); }); + + it('can encode PoolRegistration with 6.248 tags to Core', () => { + const certificate = PoolRegistration.fromCbor(cborWithSets); + expect(certificate.toCore()).toEqual(core); + }); }); diff --git a/packages/core/test/Serialization/Common/Credential.test.ts b/packages/core/test/Serialization/Common/Credential.test.ts new file mode 100644 index 00000000000..c8e1bfe92a5 --- /dev/null +++ b/packages/core/test/Serialization/Common/Credential.test.ts @@ -0,0 +1,28 @@ +import * as Crypto from '@cardano-sdk/crypto'; +import { HexBlob } from '@cardano-sdk/util'; + +import { Cardano } from '../../../src'; +import { Credential } from '../../../src/Serialization/Common'; + +describe('Credential', () => { + const cbor = HexBlob('8200581c30000000000000000000000000000000000000000000000000000000'); + const cborArraySize3 = HexBlob('8300581c3000000000000000000000000000000000000000000000000000000000'); + const coreCredential: Cardano.Credential = { + hash: Crypto.Hash28ByteBase16('30000000000000000000000000000000000000000000000000000000'), + type: Cardano.CredentialType.KeyHash + }; + + it('can encode init from Core', () => { + const credential = Credential.fromCore(coreCredential); + expect(credential.toCbor()).toEqual(cbor); + }); + + it('can encode to Core', () => { + const credential = Credential.fromCbor(cbor); + expect(credential.toCore()).toEqual(coreCredential); + }); + + it('politely refuses an invalid credential cbor', () => { + expect(() => Credential.fromCbor(cborArraySize3)).toThrow(); + }); +}); diff --git a/packages/core/test/Serialization/Transaction.test.ts b/packages/core/test/Serialization/Transaction.test.ts index 2401e93bfbc..473a7a3d887 100644 --- a/packages/core/test/Serialization/Transaction.test.ts +++ b/packages/core/test/Serialization/Transaction.test.ts @@ -28,7 +28,7 @@ describe('Transaction', () => { expect(tx.body()).toBeInstanceOf(TransactionBody); const witnessSet = tx.witnessSet(); const vKeys = witnessSet.vkeys(); - const witness = vKeys![0]; + const witness = vKeys!.values()[0]; const witnessSignature = witness.signature(); const vKey = witness.vkey(); expect(vKey).toBe(vkey); diff --git a/packages/core/test/Serialization/TransactionBody/ProposalProcedure/UpdateCommittee.test.ts b/packages/core/test/Serialization/TransactionBody/ProposalProcedure/UpdateCommittee.test.ts index 40185970c83..b7d3ddb8255 100644 --- a/packages/core/test/Serialization/TransactionBody/ProposalProcedure/UpdateCommittee.test.ts +++ b/packages/core/test/Serialization/TransactionBody/ProposalProcedure/UpdateCommittee.test.ts @@ -8,6 +8,10 @@ const cbor = HexBlob( '8504825820000000000000000000000000000000000000000000000000000000000000000003828200581c000000000000000000000000000000000000000000000000000000008200581c20000000000000000000000000000000000000000000000000000000a28200581c30000000000000000000000000000000000000000000000000000000018200581c4000000000000000000000000000000000000000000000000000000002d81e820105' ); +const cborWithConwaySet = HexBlob( + '8504825820000000000000000000000000000000000000000000000000000000000000000003d90102828200581c000000000000000000000000000000000000000000000000000000008200581c20000000000000000000000000000000000000000000000000000000a28200581c30000000000000000000000000000000000000000000000000000000018200581c4000000000000000000000000000000000000000000000000000000002d81e820105' +); + const core = { __typename: Cardano.GovernanceActionType.update_committee, governanceActionId: { actionIndex: 3, id: '0000000000000000000000000000000000000000000000000000000000000000' }, @@ -52,4 +56,9 @@ describe('UpdateCommittee', () => { expect(action.toCore()).toEqual(core); }); + + it('can encode UpdateCommittee with 6.248 tags to Core', () => { + const body = UpdateCommittee.fromCbor(cborWithConwaySet); + expect(body.toCore()).toEqual(core); + }); }); diff --git a/packages/core/test/Serialization/TransactionBody/TransactionBody.test.ts b/packages/core/test/Serialization/TransactionBody/TransactionBody.test.ts index 045e504ec1a..db5725e1c53 100644 --- a/packages/core/test/Serialization/TransactionBody/TransactionBody.test.ts +++ b/packages/core/test/Serialization/TransactionBody/TransactionBody.test.ts @@ -15,6 +15,10 @@ const conwayCbor = HexBlob( 'b500818258200f3abbc8fc19c2e61bab6059bf8a466e6e754833a08a62a6c56fe0e78f19d9d5000181825839009493315cd92eb5d8c4304e67b7e16ae36d61d34502694657811a2c8e32c728d3861e164cab28cb8f006448139c8f1740ffb8e7aa9e5232dc820aa3581c2a286ad895d091f2b3d168a6091ad2627d30a72761a5bc36eef00740a14014581c659f2917fb63f12b33667463ee575eeac1845bbc736b9c0bbc40ba82a14454534c411832581c7eae28af2208be856f7a119668ae52a49b73725e326dc16579dcc373a240182846504154415445181e020a031903e804828304581c26b17b78de4f035dc0bfce60d1d3c3a8085c38dcce5fb8767e518bed1901f48405581c0d94e174732ef9aae73f395ab44507bfa983d65023c11a951f0c32e4581ca646474b8f5431261506b6c273d307c7569a4eb6c96b42dd4a29520a582003170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c11131405a2581de013cf55d175ea848b87deb3e914febd7e028e2bf6534475d52fb9c3d005581de0404b5a4088ae9abcf486a7e7b8f82069e6fcfe1bf226f1851ce72570030682a3581c00000000000000000000000000000000000000000000000000000001b60018640118c80219012c03190190041901f4051a001e8480061a0bebc200071903200819038409d81e8201020ad81e8201030bd81e8201040cd81e8201050d8201582000000000000000000000000000000000000000000000000000000000000000000e820103101903e8111988b812a10098a61a0003236119032c01011903e819023b00011903e8195e7104011903e818201a0001ca761928eb041959d818641959d818641959d818641959d818641959d818641959d81864186418641959d81864194c5118201a0002acfa182019b551041a000363151901ff00011a00015c3518201a000797751936f404021a0002ff941a0006ea7818dc0001011903e8196ff604021a0003bd081a00034ec5183e011a00102e0f19312a011a00032e801901a5011a0002da781903e819cf06011a00013a34182019a8f118201903e818201a00013aac0119e143041903e80a1a00030219189c011a00030219189c011a0003207c1901d9011a000330001901ff0119ccf3182019fd40182019ffd5182019581e18201940b318201a00012adf18201a0002ff941a0006ea7818dc0001011a00010f92192da7000119eabb18201a0002ff941a0006ea7818dc0001011a0002ff941a0006ea7818dc0001011a000c504e197712041a001d6af61a0001425b041a00040c660004001a00014fab18201a0003236119032c010119a0de18201a00033d7618201979f41820197fb8182019a95d1820197df718201995aa18201a0374f693194a1f0a1382d81e820102d81e82010214821b00000001000000001b000000010000000015821b00000001000000001b0000000100000000161903ba581c00000000000000000000000000000000000000000000000000000002b60018640118c80219012c03190190041901f4051a001e8480061a0bebc200071903200819038409d81e8201020ad81e8201030bd81e8201040cd81e8201050d8201582000000000000000000000000000000000000000000000000000000000000000000e820103101903e8111988b812a10098a61a0003236119032c01011903e819023b00011903e8195e7104011903e818201a0001ca761928eb041959d818641959d818641959d818641959d818641959d818641959d81864186418641959d81864194c5118201a0002acfa182019b551041a000363151901ff00011a00015c3518201a000797751936f404021a0002ff941a0006ea7818dc0001011903e8196ff604021a0003bd081a00034ec5183e011a00102e0f19312a011a00032e801901a5011a0002da781903e819cf06011a00013a34182019a8f118201903e818201a00013aac0119e143041903e80a1a00030219189c011a00030219189c011a0003207c1901d9011a000330001901ff0119ccf3182019fd40182019ffd5182019581e18201940b318201a00012adf18201a0002ff941a0006ea7818dc0001011a00010f92192da7000119eabb18201a0002ff941a0006ea7818dc0001011a0002ff941a0006ea7818dc0001011a000c504e197712041a001d6af61a0001425b041a00040c660004001a00014fab18201a0003236119032c010119a0de18201a00033d7618201979f41820197fb8182019a95d1820197df718201995aa18201a0374f693194a1f0a1382d81e820102d81e82010214821b00000001000000001b000000010000000015821b00000001000000001b0000000100000000161903ba581c00000000000000000000000000000000000000000000000000000003b60018640118c80219012c03190190041901f4051a001e8480061a0bebc200071903200819038409d81e8201020ad81e8201030bd81e8201040cd81e8201050d8201582000000000000000000000000000000000000000000000000000000000000000000e820103101903e8111988b812a10098a61a0003236119032c01011903e819023b00011903e8195e7104011903e818201a0001ca761928eb041959d818641959d818641959d818641959d818641959d818641959d81864186418641959d81864194c5118201a0002acfa182019b551041a000363151901ff00011a00015c3518201a000797751936f404021a0002ff941a0006ea7818dc0001011903e8196ff604021a0003bd081a00034ec5183e011a00102e0f19312a011a00032e801901a5011a0002da781903e819cf06011a00013a34182019a8f118201903e818201a00013aac0119e143041903e80a1a00030219189c011a00030219189c011a0003207c1901d9011a000330001901ff0119ccf3182019fd40182019ffd5182019581e18201940b318201a00012adf18201a0002ff941a0006ea7818dc0001011a00010f92192da7000119eabb18201a0002ff941a0006ea7818dc0001011a0002ff941a0006ea7818dc0001011a000c504e197712041a001d6af61a0001425b041a00040c660004001a00014fab18201a0003236119032c010119a0de18201a00033d7618201979f41820197fb8182019a95d1820197df718201995aa18201a0374f693194a1f0a1382d81e820102d81e82010214821b00000001000000001b000000010000000015821b00000001000000001b0000000100000000161903ba19020b0758202ceb364d93225b4a0f004a0975a13eb50c3cc6348474b4fe9121f8dc72ca0cfa08186409a3581c2a286ad895d091f2b3d168a6091ad2627d30a72761a5bc36eef00740a14014581c659f2917fb63f12b33667463ee575eeac1845bbc736b9c0bbc40ba82a14454534c413831581c7eae28af2208be856f7a119668ae52a49b73725e326dc16579dcc373a240182846504154415445181e0b58206199186adb51974690d7247d2646097d2c62763b16fb7ed3f9f55d38abc123de0d818258200f3abbc8fc19c2e61bab6059bf8a466e6e754833a08a62a6c56fe0e78f19d9d5010e81581c6199186adb51974690d7247d2646097d2c62763b16fb7ed3f9f55d390f0110825839009493315cd92eb5d8c4304e67b7e16ae36d61d34502694657811a2c8e32c728d3861e164cab28cb8f006448139c8f1740ffb8e7aa9e5232dc820aa3581c2a286ad895d091f2b3d168a6091ad2627d30a72761a5bc36eef00740a14014581c659f2917fb63f12b33667463ee575eeac1845bbc736b9c0bbc40ba82a14454534c411832581c7eae28af2208be856f7a119668ae52a49b73725e326dc16579dcc373a240182846504154415445181e11186412818258200f3abbc8fc19c2e61bab6059bf8a466e6e754833a08a62a6c56fe0e78f19d9d50013a28202581c10000000000000000000000000000000000000000000000000000000a38258201000000000000000000000000000000000000000000000000000000000000000038200827668747470733a2f2f7777772e736f6d6575726c2e696f582000000000000000000000000000000000000000000000000000000000000000008258202000000000000000000000000000000000000000000000000000000000000000038200827668747470733a2f2f7777772e736f6d6575726c2e696f582000000000000000000000000000000000000000000000000000000000000000008258203000000000000000000000000000000000000000000000000000000000000000038200827668747470733a2f2f7777772e736f6d6575726c2e696f582000000000000000000000000000000000000000000000000000000000000000008203581c20000000000000000000000000000000000000000000000000000000a28258201000000000000000000000000000000000000000000000000000000000000000038200827668747470733a2f2f7777772e736f6d6575726c2e696f582000000000000000000000000000000000000000000000000000000000000000008258203000000000000000000000000000000000000000000000000000000000000000038200827668747470733a2f2f7777772e736f6d6575726c2e696f582000000000000000000000000000000000000000000000000000000000000000001481841a000f4240581de1cb0ec2692497b458e46812c8a5bfa2931d1a2d965a99893828ec810f830582582000000000000000000000000000000000000000000000000000000000000000000382827668747470733a2f2f7777772e736f6d6575726c2e696f58200000000000000000000000000000000000000000000000000000000000000000f6827668747470733a2f2f7777772e736f6d6575726c2e696f58200000000000000000000000000000000000000000000000000000000000000000151907d0161903e8' ); +const conwayCborWithSets = HexBlob( + 'b500d90102818258200f3abbc8fc19c2e61bab6059bf8a466e6e754833a08a62a6c56fe0e78f19d9d5000181825839009493315cd92eb5d8c4304e67b7e16ae36d61d34502694657811a2c8e32c728d3861e164cab28cb8f006448139c8f1740ffb8e7aa9e5232dc820aa3581c2a286ad895d091f2b3d168a6091ad2627d30a72761a5bc36eef00740a14014581c659f2917fb63f12b33667463ee575eeac1845bbc736b9c0bbc40ba82a14454534c411832581c7eae28af2208be856f7a119668ae52a49b73725e326dc16579dcc373a240182846504154415445181e020a031903e804d90102828304581c26b17b78de4f035dc0bfce60d1d3c3a8085c38dcce5fb8767e518bed1901f48405581c0d94e174732ef9aae73f395ab44507bfa983d65023c11a951f0c32e4581ca646474b8f5431261506b6c273d307c7569a4eb6c96b42dd4a29520a582003170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c11131405a2581de013cf55d175ea848b87deb3e914febd7e028e2bf6534475d52fb9c3d005581de0404b5a4088ae9abcf486a7e7b8f82069e6fcfe1bf226f1851ce72570030682a3581c00000000000000000000000000000000000000000000000000000001b60018640118c80219012c03190190041901f4051a001e8480061a0bebc200071903200819038409d81e8201020ad81e8201030bd81e8201040cd81e8201050d8201582000000000000000000000000000000000000000000000000000000000000000000e820103101903e8111988b812a10098a61a0003236119032c01011903e819023b00011903e8195e7104011903e818201a0001ca761928eb041959d818641959d818641959d818641959d818641959d818641959d81864186418641959d81864194c5118201a0002acfa182019b551041a000363151901ff00011a00015c3518201a000797751936f404021a0002ff941a0006ea7818dc0001011903e8196ff604021a0003bd081a00034ec5183e011a00102e0f19312a011a00032e801901a5011a0002da781903e819cf06011a00013a34182019a8f118201903e818201a00013aac0119e143041903e80a1a00030219189c011a00030219189c011a0003207c1901d9011a000330001901ff0119ccf3182019fd40182019ffd5182019581e18201940b318201a00012adf18201a0002ff941a0006ea7818dc0001011a00010f92192da7000119eabb18201a0002ff941a0006ea7818dc0001011a0002ff941a0006ea7818dc0001011a000c504e197712041a001d6af61a0001425b041a00040c660004001a00014fab18201a0003236119032c010119a0de18201a00033d7618201979f41820197fb8182019a95d1820197df718201995aa18201a0374f693194a1f0a1382d81e820102d81e82010214821b00000001000000001b000000010000000015821b00000001000000001b0000000100000000161903ba581c00000000000000000000000000000000000000000000000000000002b60018640118c80219012c03190190041901f4051a001e8480061a0bebc200071903200819038409d81e8201020ad81e8201030bd81e8201040cd81e8201050d8201582000000000000000000000000000000000000000000000000000000000000000000e820103101903e8111988b812a10098a61a0003236119032c01011903e819023b00011903e8195e7104011903e818201a0001ca761928eb041959d818641959d818641959d818641959d818641959d818641959d81864186418641959d81864194c5118201a0002acfa182019b551041a000363151901ff00011a00015c3518201a000797751936f404021a0002ff941a0006ea7818dc0001011903e8196ff604021a0003bd081a00034ec5183e011a00102e0f19312a011a00032e801901a5011a0002da781903e819cf06011a00013a34182019a8f118201903e818201a00013aac0119e143041903e80a1a00030219189c011a00030219189c011a0003207c1901d9011a000330001901ff0119ccf3182019fd40182019ffd5182019581e18201940b318201a00012adf18201a0002ff941a0006ea7818dc0001011a00010f92192da7000119eabb18201a0002ff941a0006ea7818dc0001011a0002ff941a0006ea7818dc0001011a000c504e197712041a001d6af61a0001425b041a00040c660004001a00014fab18201a0003236119032c010119a0de18201a00033d7618201979f41820197fb8182019a95d1820197df718201995aa18201a0374f693194a1f0a1382d81e820102d81e82010214821b00000001000000001b000000010000000015821b00000001000000001b0000000100000000161903ba581c00000000000000000000000000000000000000000000000000000003b60018640118c80219012c03190190041901f4051a001e8480061a0bebc200071903200819038409d81e8201020ad81e8201030bd81e8201040cd81e8201050d8201582000000000000000000000000000000000000000000000000000000000000000000e820103101903e8111988b812a10098a61a0003236119032c01011903e819023b00011903e8195e7104011903e818201a0001ca761928eb041959d818641959d818641959d818641959d818641959d818641959d81864186418641959d81864194c5118201a0002acfa182019b551041a000363151901ff00011a00015c3518201a000797751936f404021a0002ff941a0006ea7818dc0001011903e8196ff604021a0003bd081a00034ec5183e011a00102e0f19312a011a00032e801901a5011a0002da781903e819cf06011a00013a34182019a8f118201903e818201a00013aac0119e143041903e80a1a00030219189c011a00030219189c011a0003207c1901d9011a000330001901ff0119ccf3182019fd40182019ffd5182019581e18201940b318201a00012adf18201a0002ff941a0006ea7818dc0001011a00010f92192da7000119eabb18201a0002ff941a0006ea7818dc0001011a0002ff941a0006ea7818dc0001011a000c504e197712041a001d6af61a0001425b041a00040c660004001a00014fab18201a0003236119032c010119a0de18201a00033d7618201979f41820197fb8182019a95d1820197df718201995aa18201a0374f693194a1f0a1382d81e820102d81e82010214821b00000001000000001b000000010000000015821b00000001000000001b0000000100000000161903ba19020b0758202ceb364d93225b4a0f004a0975a13eb50c3cc6348474b4fe9121f8dc72ca0cfa08186409a3581c2a286ad895d091f2b3d168a6091ad2627d30a72761a5bc36eef00740a14014581c659f2917fb63f12b33667463ee575eeac1845bbc736b9c0bbc40ba82a14454534c413831581c7eae28af2208be856f7a119668ae52a49b73725e326dc16579dcc373a240182846504154415445181e0b58206199186adb51974690d7247d2646097d2c62763b16fb7ed3f9f55d38abc123de0dd90102818258200f3abbc8fc19c2e61bab6059bf8a466e6e754833a08a62a6c56fe0e78f19d9d5010ed9010281581c6199186adb51974690d7247d2646097d2c62763b16fb7ed3f9f55d390f0110825839009493315cd92eb5d8c4304e67b7e16ae36d61d34502694657811a2c8e32c728d3861e164cab28cb8f006448139c8f1740ffb8e7aa9e5232dc820aa3581c2a286ad895d091f2b3d168a6091ad2627d30a72761a5bc36eef00740a14014581c659f2917fb63f12b33667463ee575eeac1845bbc736b9c0bbc40ba82a14454534c411832581c7eae28af2208be856f7a119668ae52a49b73725e326dc16579dcc373a240182846504154415445181e11186412d90102818258200f3abbc8fc19c2e61bab6059bf8a466e6e754833a08a62a6c56fe0e78f19d9d50013a28202581c10000000000000000000000000000000000000000000000000000000a38258201000000000000000000000000000000000000000000000000000000000000000038200827668747470733a2f2f7777772e736f6d6575726c2e696f582000000000000000000000000000000000000000000000000000000000000000008258202000000000000000000000000000000000000000000000000000000000000000038200827668747470733a2f2f7777772e736f6d6575726c2e696f582000000000000000000000000000000000000000000000000000000000000000008258203000000000000000000000000000000000000000000000000000000000000000038200827668747470733a2f2f7777772e736f6d6575726c2e696f582000000000000000000000000000000000000000000000000000000000000000008203581c20000000000000000000000000000000000000000000000000000000a28258201000000000000000000000000000000000000000000000000000000000000000038200827668747470733a2f2f7777772e736f6d6575726c2e696f582000000000000000000000000000000000000000000000000000000000000000008258203000000000000000000000000000000000000000000000000000000000000000038200827668747470733a2f2f7777772e736f6d6575726c2e696f5820000000000000000000000000000000000000000000000000000000000000000014d9010281841a000f4240581de1cb0ec2692497b458e46812c8a5bfa2931d1a2d965a99893828ec810f830582582000000000000000000000000000000000000000000000000000000000000000000382827668747470733a2f2f7777772e736f6d6575726c2e696f58200000000000000000000000000000000000000000000000000000000000000000f6827668747470733a2f2f7777772e736f6d6575726c2e696f58200000000000000000000000000000000000000000000000000000000000000000151907d0161903e8' +); + export const core: Cardano.TxBody = { auxiliaryDataHash: Crypto.Hash32ByteBase16('2ceb364d93225b4a0f004a0975a13eb50c3cc6348474b4fe9121f8dc72ca0cfa'), certificates: [ @@ -246,6 +250,11 @@ describe('TransactionBody', () => { expect(body.toCore()).toEqual(expectedConwayCore); }); + it('can encode TransactionBody with 6.248 tags to Core', () => { + const body = TransactionBody.fromCbor(conwayCborWithSets); + expect(body.toCore()).toEqual(expectedConwayCore); + }); + it('sorts withdrawals canonically', () => { const body = TransactionBody.fromCbor(cbor); const withdrawals = body.withdrawals(); diff --git a/packages/core/test/Serialization/TransactionWitnessSet/TransactionWitnessSet.test.ts b/packages/core/test/Serialization/TransactionWitnessSet/TransactionWitnessSet.test.ts index c3b6bc1e4cc..d44c4310653 100644 --- a/packages/core/test/Serialization/TransactionWitnessSet/TransactionWitnessSet.test.ts +++ b/packages/core/test/Serialization/TransactionWitnessSet/TransactionWitnessSet.test.ts @@ -10,6 +10,10 @@ const cbor = HexBlob( 'a700838258204a352f53eb4311d552aa9e1c6f0125846a3b607011d691f0e774d893d940b8525840c4f13cc397a50193061ce899b3eda906ad1adf3f3d515b52248ea5aa142781cd9c2ccc52ac62b2e1b5226de890104ec530bda4c38a19b691946da9addb3213f5825820290c08454c58a8c7fad6351e65a652460bd4f80f485f1ccfc350ff6a4d5bd4de5840026f47bab2f24da9690746bdb0e55d53a5eef45a969e3dd2873a3e6bb8ef3316d9f80489bacfd2f543108e284a40847ae7ce33fa358fcfe439a37990ad3107e98258204d953d6a9d556da3f3e26622c725923130f5733d1a3c4013ef8c34d15a070fd75840f9218e5a569c5ace38b1bb81e1f1c0b2d7fea2fe7fb913fdd06d79906436103345347a81494b83f83bf43466b0cebdbbdcef15384f67c255e826c249336ce2c701848204038205098202818200581c3542acb3a64d80c29302260d62c3b87a742ad14abf855ebc6733081e830300818200581cb5ae663aaea8e500157bdf4baafd6f5ba0ce5759f7cd4101fc132f5402828458203d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c58406291d657deec24024827e69c3abe01a30ce548a284743a445e3680d7db5ac3ac18ff9b538d16f290ae67f760984dc6594a7c15e9716ed28dc027beceea1ec40a5820000000000000000000000000000000000000000000000000000000000000000041a08458203d4017c3e863895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c58406291d657deec24024827e69c3abe01a30ce548a284743a445e3680d7db5ac3ac18ff9b538d16f290ae67f760984dc6594a7c15e9716ed28dc027beceea1ec40a5820ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff41a00384474601000022001047460100002200114746010000220012474601000022001304833bffffffffffffffff3bffffffffffffffff3bffffffffffffffff0584840000d8799f0102030405ff821b000086788ffc4e831b00015060e9e46451840100d8799f0102030405ff821b000086788ffc4e831b00015060e9e46451840200d8799f0102030405ff821b000086788ffc4e831b00015060e9e46451840300d8799f0102030405ff821b000086788ffc4e831b00015060e9e4645106844746010000220010474601000022001147460100002200124746010000220013' ); +const cborWithSets = HexBlob( + 'a700d90102838258204a352f53eb4311d552aa9e1c6f0125846a3b607011d691f0e774d893d940b8525840c4f13cc397a50193061ce899b3eda906ad1adf3f3d515b52248ea5aa142781cd9c2ccc52ac62b2e1b5226de890104ec530bda4c38a19b691946da9addb3213f5825820290c08454c58a8c7fad6351e65a652460bd4f80f485f1ccfc350ff6a4d5bd4de5840026f47bab2f24da9690746bdb0e55d53a5eef45a969e3dd2873a3e6bb8ef3316d9f80489bacfd2f543108e284a40847ae7ce33fa358fcfe439a37990ad3107e98258204d953d6a9d556da3f3e26622c725923130f5733d1a3c4013ef8c34d15a070fd75840f9218e5a569c5ace38b1bb81e1f1c0b2d7fea2fe7fb913fdd06d79906436103345347a81494b83f83bf43466b0cebdbbdcef15384f67c255e826c249336ce2c701d90102848204038205098202818200581c3542acb3a64d80c29302260d62c3b87a742ad14abf855ebc6733081e830300818200581cb5ae663aaea8e500157bdf4baafd6f5ba0ce5759f7cd4101fc132f5402d90102828458203d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c58406291d657deec24024827e69c3abe01a30ce548a284743a445e3680d7db5ac3ac18ff9b538d16f290ae67f760984dc6594a7c15e9716ed28dc027beceea1ec40a5820000000000000000000000000000000000000000000000000000000000000000041a08458203d4017c3e863895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c58406291d657deec24024827e69c3abe01a30ce548a284743a445e3680d7db5ac3ac18ff9b538d16f290ae67f760984dc6594a7c15e9716ed28dc027beceea1ec40a5820ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff41a003d9010284474601000022001047460100002200114746010000220012474601000022001304d90102833bffffffffffffffff3bffffffffffffffff3bffffffffffffffff05a482000082d8799f0102030405ff821b000086788ffc4e831b00015060e9e4645182010082d8799f0102030405ff821b000086788ffc4e831b00015060e9e4645182020082d8799f0102030405ff821b000086788ffc4e831b00015060e9e4645182030082d8799f0102030405ff821b000086788ffc4e831b00015060e9e4645106d90102844746010000220010474601000022001147460100002200124746010000220013' +); + const simpleWitnessCbor = HexBlob( 'a100838258204a352f53eb4311d552aa9e1c6f0125846a3b607011d691f0e774d893d940b8525840c4f13cc397a50193061ce899b3eda906ad1adf3f3d515b52248ea5aa142781cd9c2ccc52ac62b2e1b5226de890104ec530bda4c38a19b691946da9addb3213f5825820290c08454c58a8c7fad6351e65a652460bd4f80f485f1ccfc350ff6a4d5bd4de5840026f47bab2f24da9690746bdb0e55d53a5eef45a969e3dd2873a3e6bb8ef3316d9f80489bacfd2f543108e284a40847ae7ce33fa358fcfe439a37990ad3107e98258204d953d6a9d556da3f3e26622c725923130f5733d1a3c4013ef8c34d15a070fd75840f9218e5a569c5ace38b1bb81e1f1c0b2d7fea2fe7fb913fdd06d79906436103345347a81494b83f83bf43466b0cebdbbdcef15384f67c255e826c249336ce2c7' ); @@ -195,6 +199,11 @@ describe('TransactionWitnessSet', () => { expect(witness.toCore()).toEqual(core); }); + it('can encode TransactionWitnessSet with 6.248 tags to Core', () => { + const witness = TransactionWitnessSet.fromCbor(cborWithSets); + expect(witness.toCore()).toEqual(core); + }); + it('can encode simple TransactionWitnessSet to CBOR', () => { const witness = TransactionWitnessSet.fromCore(simpleCore); expect(witness.toCbor()).toEqual(simpleWitnessCbor); diff --git a/packages/web-extension/src/walletManager/util.ts b/packages/web-extension/src/walletManager/util.ts index ab70ae1df3b..efee2940dba 100644 --- a/packages/web-extension/src/walletManager/util.ts +++ b/packages/web-extension/src/walletManager/util.ts @@ -161,7 +161,7 @@ const requiresStakingWitness = ( networkId ); const withdrawals = body.withdrawals() ?? new Map(); - const certificates = (body.certs() ?? []).map((certificate) => certificate.toCore()); + const certificates = (body.certs()?.values() ?? []).map((certificate) => certificate.toCore()); if (withdrawals.size > 0 && withdrawals.has((key: Cardano.RewardAccount) => key === rewardAccount)) return true;