diff --git a/apps/playground/src/pages/api/donate-mint-mesh.ts b/apps/playground/src/pages/api/donate-mint-mesh.ts
index 2c3409340..76f2d4800 100644
--- a/apps/playground/src/pages/api/donate-mint-mesh.ts
+++ b/apps/playground/src/pages/api/donate-mint-mesh.ts
@@ -94,7 +94,7 @@ export default async function handler(
.selectUtxosFrom(utxos)
.mint("1", policyId, stringToHex(assetName))
.mintingScript(forgingScript)
- .metadataValue("721", fullAssetMetadata)
+ .metadataValue(721, fullAssetMetadata)
.txOut(donateAddress, [
{ unit: "lovelace", quantity: costLovelace.toString() },
])
diff --git a/apps/playground/src/pages/apis/transaction/basics/cip20.tsx b/apps/playground/src/pages/apis/transaction/basics/cip20.tsx
index 2fc46c5e2..11ec8f601 100644
--- a/apps/playground/src/pages/apis/transaction/basics/cip20.tsx
+++ b/apps/playground/src/pages/apis/transaction/basics/cip20.tsx
@@ -34,7 +34,7 @@ function Left() {
The specification for the individual strings follow the general design
specification for JSON metadata, which is already implemented and in
operation on the cardano blockchain. The used metadatum label is{" "}
- 674
:, this number was choosen because it is the T9 encoding
+ 674
:, this number was chosen because it is the T9 encoding
of the string
msg
. The message content has the key msg
: and
consists of an array of individual message-strings. The number of theses
diff --git a/apps/playground/src/pages/apis/txbuilder/basics/cip20.tsx b/apps/playground/src/pages/apis/txbuilder/basics/cip20.tsx
index 3d20ced5a..8d0903519 100644
--- a/apps/playground/src/pages/apis/txbuilder/basics/cip20.tsx
+++ b/apps/playground/src/pages/apis/txbuilder/basics/cip20.tsx
@@ -22,7 +22,7 @@ export default function TxbuilderCip20() {
function Left() {
let code = `txBuilder\n`;
- code += ` .metadataValue(tag, metadata)\n`;
+ code += ` .metadataValue(label, metadata)\n`;
return (
<>
@@ -36,7 +36,7 @@ function Left() {
The specification for the individual strings follow the general design
specification for JSON metadata, which is already implemented and in
operation on the cardano blockchain. The used metadatum label is{" "}
- 674
: this number was choosen because it is the T9 encoding
+ 674
: this number was chosen because it is the T9 encoding
of the string
msg
. The message content has the key msg
: and
consists of an array of individual message-strings. The number of theses
@@ -60,14 +60,14 @@ function Right() {
const changeAddress = await wallet.getChangeAddress();
const txBuilder = getTxBuilder();
- const tag = "674";
+ const label = 674;
const metadata = {
msg: message.split("\n"),
};
const unsignedTx = await txBuilder
.changeAddress(changeAddress)
- .metadataValue(tag.toString(), metadata)
+ .metadataValue(label, metadata)
.selectUtxosFrom(utxos)
.complete();
@@ -82,7 +82,7 @@ function Right() {
codeSnippet += `const changeAddress = await wallet.getChangeAddress();\n`;
codeSnippet += `const txBuilder = getTxBuilder();\n`;
codeSnippet += `\n`;
- codeSnippet += `const tag = "674";\n`;
+ codeSnippet += `const label = 674;\n`;
codeSnippet += `const metadata = {\n`;
codeSnippet += ` msg: [\n`;
for (let line of message.split("\n")) {
@@ -92,7 +92,7 @@ function Right() {
codeSnippet += `});\n\n`;
codeSnippet += `const unsignedTx = await txBuilder\n`;
codeSnippet += ` .changeAddress(changeAddress)\n`;
- codeSnippet += ` .metadataValue(tag, metadata)\n`;
+ codeSnippet += ` .metadataValue(label, metadata)\n`;
codeSnippet += ` .selectUtxosFrom(utxos)\n`;
codeSnippet += ` .complete();\n`;
codeSnippet += `\n`;
diff --git a/apps/playground/src/pages/apis/txbuilder/basics/multisig.tsx b/apps/playground/src/pages/apis/txbuilder/basics/multisig.tsx
index f8297619a..9e209ef01 100644
--- a/apps/playground/src/pages/apis/txbuilder/basics/multisig.tsx
+++ b/apps/playground/src/pages/apis/txbuilder/basics/multisig.tsx
@@ -29,7 +29,7 @@ function Left() {
codeTx += `const unsignedTx = await txBuilder\n`;
codeTx += ` .mint("1", policyId, stringToHex("MeshToken"))\n`;
codeTx += ` .mintingScript(forgingScript)\n`;
- codeTx += ` .metadataValue("721", { [policyId]: { [assetName]: demoAssetMetadata } })\n`;
+ codeTx += ` .metadataValue(721, { [policyId]: { [assetName]: demoAssetMetadata } })\n`;
codeTx += ` .changeAddress(address)\n`;
codeTx += ` .selectUtxosFrom(utxos)\n`;
codeTx += ` .complete();\n`;
@@ -88,7 +88,7 @@ function Right() {
const unsignedTx = await txBuilder
.mint("1", policyId, stringToHex("MeshToken"))
.mintingScript(forgingScript)
- .metadataValue("721", { [policyId]: { [assetName]: demoAssetMetadata } })
+ .metadataValue(721, { [policyId]: { [assetName]: demoAssetMetadata } })
.changeAddress(address)
.selectUtxosFrom(utxos)
.complete();
@@ -124,7 +124,7 @@ function Right() {
codeSnippet += `const unsignedTx = await txBuilder\n`;
codeSnippet += ` .mint("1", policyId, stringToHex("MeshToken"))\n`;
codeSnippet += ` .mintingScript(forgingScript)\n`;
- codeSnippet += ` .metadataValue("721", { [policyId]: { [assetName]: demoAssetMetadata } })\n`;
+ codeSnippet += ` .metadataValue(721, { [policyId]: { [assetName]: demoAssetMetadata } })\n`;
codeSnippet += ` .changeAddress(address)\n`;
codeSnippet += ` .selectUtxosFrom(utxos)\n`;
codeSnippet += ` .complete();\n`;
diff --git a/apps/playground/src/pages/apis/txbuilder/basics/set-metadata.tsx b/apps/playground/src/pages/apis/txbuilder/basics/set-metadata.tsx
index ae9f7bda8..9dda03c70 100644
--- a/apps/playground/src/pages/apis/txbuilder/basics/set-metadata.tsx
+++ b/apps/playground/src/pages/apis/txbuilder/basics/set-metadata.tsx
@@ -22,7 +22,7 @@ export default function TxbuilderSetMetadata() {
function Left() {
let code = `txBuilder\n`;
- code += ` .metadataValue(tag, metadata)\n`;
+ code += ` .metadataValue(label, metadata)\n`;
return (
<>
@@ -47,12 +47,12 @@ function Right() {
const changeAddress = await wallet.getChangeAddress();
const txBuilder = getTxBuilder();
- const tag = "0";
+ const label = 0;
const metadata = "This is a message from the Mesh SDK";
const unsignedTx = await txBuilder
.changeAddress(changeAddress)
- .metadataValue(tag.toString(), metadata)
+ .metadataValue(label, metadata)
.selectUtxosFrom(utxos)
.complete();
@@ -66,11 +66,11 @@ function Right() {
codeSnippet += `const address = await wallet.getChangeAddress();\n`;
codeSnippet += `const txBuilder = getTxBuilder();\n`;
codeSnippet += `\n`;
- codeSnippet += `const tag = "0";\n`;
+ codeSnippet += `const label = 0;\n`;
codeSnippet += `const metadata = "This is a message from the Mesh SDK";\n\n`;
codeSnippet += `const unsignedTx = await txBuilder\n`;
codeSnippet += ` .changeAddress(address)\n`;
- codeSnippet += ` .metadataValue(tag, metadata)\n`;
+ codeSnippet += ` .metadataValue(label, metadata)\n`;
codeSnippet += ` .selectUtxosFrom(utxos)\n`;
codeSnippet += ` .complete();\n`;
codeSnippet += `\n`;
diff --git a/apps/playground/src/pages/apis/txbuilder/minting/minting-native-script.tsx b/apps/playground/src/pages/apis/txbuilder/minting/minting-native-script.tsx
index f8526b1a6..a369af6c7 100644
--- a/apps/playground/src/pages/apis/txbuilder/minting/minting-native-script.tsx
+++ b/apps/playground/src/pages/apis/txbuilder/minting/minting-native-script.tsx
@@ -84,7 +84,7 @@ function Right() {
const unsignedTx = await txBuilder
.mint("1", policyId, tokenNameHex)
.mintingScript(forgingScript)
- .metadataValue("721", metadata)
+ .metadataValue(721, metadata)
.changeAddress(changeAddress)
.invalidHereafter(99999999)
.selectUtxosFrom(utxos)
@@ -125,7 +125,7 @@ const txBuilder = getTxBuilder();
const unsignedTx = await txBuilder
.mint("1", policyId, tokenNameHex)
.mintingScript(forgingScript)
- .metadataValue("721", metadata)
+ .metadataValue(721, metadata)
.changeAddress(changeAddress)
.invalidHereafter(99999999)
.selectUtxosFrom(utxos)
diff --git a/apps/playground/src/pages/apis/txbuilder/minting/minting-one-signature.tsx b/apps/playground/src/pages/apis/txbuilder/minting/minting-one-signature.tsx
index 956184cd8..4c2bbfe24 100644
--- a/apps/playground/src/pages/apis/txbuilder/minting/minting-one-signature.tsx
+++ b/apps/playground/src/pages/apis/txbuilder/minting/minting-one-signature.tsx
@@ -91,7 +91,7 @@ function Right() {
const unsignedTx = await txBuilder
.mint("1", policyId, tokenNameHex)
.mintingScript(forgingScript)
- .metadataValue("721", metadata)
+ .metadataValue(721, metadata)
.changeAddress(changeAddress)
.selectUtxosFrom(utxos)
.complete();
@@ -124,7 +124,7 @@ function Right() {
codeSnippet += `const unsignedTx = await txBuilder\n`;
codeSnippet += ` .mint("1", policyId, tokenNameHex)\n`;
codeSnippet += ` .mintingScript(forgingScript)\n`;
- codeSnippet += ` .metadataValue("721", metadata)\n`;
+ codeSnippet += ` .metadataValue(721, metadata)\n`;
codeSnippet += ` .changeAddress(changeAddress)\n`;
codeSnippet += ` .selectUtxosFrom(utxos)\n`;
codeSnippet += ` .complete();\n`;
diff --git a/apps/playground/src/pages/apis/txbuilder/minting/minting-plutus-script.tsx b/apps/playground/src/pages/apis/txbuilder/minting/minting-plutus-script.tsx
index b2acc3287..7f18f0441 100644
--- a/apps/playground/src/pages/apis/txbuilder/minting/minting-plutus-script.tsx
+++ b/apps/playground/src/pages/apis/txbuilder/minting/minting-plutus-script.tsx
@@ -42,7 +42,7 @@ function Left() {
codeSnippet3 += ` .mint("1", policyId, tokenNameHex)\n`;
codeSnippet3 += ` .mintingScript(demoPlutusMintingScript)\n`;
codeSnippet3 += ` .mintRedeemerValue(mConStr0([userInput]))\n`;
- codeSnippet3 += ` .metadataValue("721", metadata)\n`;
+ codeSnippet3 += ` .metadataValue(721, metadata)\n`;
codeSnippet3 += ` .changeAddress(changeAddress)\n`;
codeSnippet3 += ` .selectUtxosFrom(utxos)\n`;
codeSnippet3 += ` .txInCollateral(\n`;
@@ -125,7 +125,7 @@ function Right() {
.mint("1", policyId, tokenNameHex)
.mintingScript(demoPlutusMintingScript)
.mintRedeemerValue(mConStr0([userInput]))
- .metadataValue("721", metadata)
+ .metadataValue(721, metadata)
.changeAddress(changeAddress)
.selectUtxosFrom(utxos)
.txInCollateral(
@@ -159,7 +159,7 @@ function Right() {
code += ` .mint("1", policyId, tokenNameHex)\n`;
code += ` .mintingScript(demoPlutusMintingScript)\n`;
code += ` .mintRedeemerValue(mConStr0(['${userInput}']))\n`;
- code += ` .metadataValue("721", metadata)\n`;
+ code += ` .metadataValue(721, metadata)\n`;
code += ` .changeAddress(changeAddress)\n`;
code += ` .selectUtxosFrom(utxos)\n`;
code += ` .txInCollateral(\n`;
diff --git a/apps/playground/src/pages/apis/txbuilder/minting/minting-royalty-token.tsx b/apps/playground/src/pages/apis/txbuilder/minting/minting-royalty-token.tsx
index c8d591a4c..d768e46d1 100644
--- a/apps/playground/src/pages/apis/txbuilder/minting/minting-royalty-token.tsx
+++ b/apps/playground/src/pages/apis/txbuilder/minting/minting-royalty-token.tsx
@@ -81,7 +81,7 @@ function Right() {
const unsignedTx = await txBuilder
.mint("1", policyId, "")
.mintingScript(forgingScript)
- .metadataValue("777", assetMetadata)
+ .metadataValue(777, assetMetadata)
.changeAddress(address)
.selectUtxosFrom(utxos)
.complete();
@@ -114,7 +114,7 @@ function Right() {
code += `const unsignedTx = await txBuilder\n`;
code += ` .mint("1", policyId, "")\n`;
code += ` .mintingScript(forgingScript)\n`;
- code += ` .metadataValue("777", assetMetadata)\n`;
+ code += ` .metadataValue(777, assetMetadata)\n`;
code += ` .changeAddress(address)\n`;
code += ` .selectUtxosFrom(utxos)\n`;
code += ` .complete();\n`;
diff --git a/apps/playground/src/pages/apis/txbuilder/minting/multiple-assets.tsx b/apps/playground/src/pages/apis/txbuilder/minting/multiple-assets.tsx
index 6a872b5a1..75835d2fd 100644
--- a/apps/playground/src/pages/apis/txbuilder/minting/multiple-assets.tsx
+++ b/apps/playground/src/pages/apis/txbuilder/minting/multiple-assets.tsx
@@ -35,7 +35,7 @@ function Left() {
let codeSnippet2 = ``;
codeSnippet2 += `txBuilder\n`;
- codeSnippet2 += ` .metadataValue("721", metadata)\n`;
+ codeSnippet2 += ` .metadataValue(721, metadata)\n`;
codeSnippet2 += ` .changeAddress(changeAddress)\n`;
codeSnippet2 += ` .selectUtxosFrom(utxos);\n`;
codeSnippet2 += `\n`;
@@ -88,7 +88,7 @@ function Right() {
}
txBuilder
- .metadataValue("721", metadata)
+ .metadataValue(721, metadata)
.changeAddress(changeAddress)
.selectUtxosFrom(utxos);
@@ -125,7 +125,7 @@ function Right() {
codeSnippet += `}\n`;
codeSnippet += `\n`;
codeSnippet += `txBuilder\n`;
- codeSnippet += ` .metadataValue("721", metadata)\n`;
+ codeSnippet += ` .metadataValue(721, metadata)\n`;
codeSnippet += ` .changeAddress(changeAddress)\n`;
codeSnippet += ` .selectUtxosFrom(utxos);\n`;
codeSnippet += `\n`;
diff --git a/packages/mesh-common/src/types/transaction-builder/index.ts b/packages/mesh-common/src/types/transaction-builder/index.ts
index f3a8e37a6..495e43fb5 100644
--- a/packages/mesh-common/src/types/transaction-builder/index.ts
+++ b/packages/mesh-common/src/types/transaction-builder/index.ts
@@ -25,7 +25,7 @@ export type MeshTxBuilderBody = {
referenceInputs: RefTxIn[];
mints: MintItem[];
changeAddress: string;
- metadata: Metadata[];
+ metadata: TxMetadata;
validityRange: ValidityRange;
certificates: Certificate[];
withdrawals: Withdrawal[];
@@ -50,7 +50,7 @@ export const emptyTxBuilderBody = (): MeshTxBuilderBody => ({
referenceInputs: [],
mints: [],
changeAddress: "",
- metadata: [],
+ metadata: new Map(),
validityRange: {},
certificates: [],
withdrawals: [],
@@ -73,6 +73,13 @@ export type ValidityRange = {
// Mint Types
+// Transaction Metadata
+
+export type MetadatumMap = Map;
+export type Metadatum = bigint | number | string | Uint8Array | MetadatumMap | Metadatum[];
+export type TxMetadata = Map;
+
+// to be used for serialization
export type Metadata = {
tag: string;
metadata: string;
diff --git a/packages/mesh-contract/src/content-ownership/offchain/offchain.ts b/packages/mesh-contract/src/content-ownership/offchain/offchain.ts
index ec14ac921..e821502c4 100644
--- a/packages/mesh-contract/src/content-ownership/offchain/offchain.ts
+++ b/packages/mesh-contract/src/content-ownership/offchain/offchain.ts
@@ -525,7 +525,7 @@ export class MeshContentOwnershipContract extends MeshTxInitiator {
const txHex = await this.mesh
.mint("1", policyId, tokenNameHex)
.mintingScript(forgingScript)
- .metadataValue("721", metadata)
+ .metadataValue(721, metadata, 2)
.changeAddress(walletAddress)
.selectUtxosFrom(utxos)
.complete();
diff --git a/packages/mesh-contract/src/plutus-nft/offchain.ts b/packages/mesh-contract/src/plutus-nft/offchain.ts
index e12bb7b02..6aa6c007e 100644
--- a/packages/mesh-contract/src/plutus-nft/offchain.ts
+++ b/packages/mesh-contract/src/plutus-nft/offchain.ts
@@ -200,7 +200,7 @@ export class MeshPlutusNFTContract extends MeshTxInitiator {
if (assetMetadata) {
const metadata = { [policyId]: { [tokenName]: { ...assetMetadata } } };
- tx.metadataValue("721", metadata);
+ tx.metadataValue(721, metadata, 2);
}
tx.mintRedeemerValue(mConStr0([]))
diff --git a/packages/mesh-core-csl/src/core/adaptor/index.ts b/packages/mesh-core-csl/src/core/adaptor/index.ts
index 1169f94a3..9fec4a2f3 100644
--- a/packages/mesh-core-csl/src/core/adaptor/index.ts
+++ b/packages/mesh-core-csl/src/core/adaptor/index.ts
@@ -4,6 +4,7 @@ import { certificateToObj } from "./certificate";
import { mintItemToObj } from "./mint";
import { networkToObj } from "./network";
import { outputToObj } from "./output";
+import { txMetadataToObj } from "./metadata";
import { collateralTxInToObj, txInToObj } from "./txIn";
import { voteToObj } from "./vote";
import { withdrawalToObj } from "./withdrawal";
@@ -33,7 +34,7 @@ export const meshTxBuilderBodyToObj = ({
referenceInputs: referenceInputs,
mints: mints.map((mint) => mintItemToObj(mint)),
changeAddress,
- metadata: metadata,
+ metadata: txMetadataToObj(metadata),
validityRange: validityRangeToObj(validityRange),
certificates: certificates.map(certificateToObj),
signingKey: signingKey,
diff --git a/packages/mesh-core-csl/src/core/adaptor/metadata.ts b/packages/mesh-core-csl/src/core/adaptor/metadata.ts
new file mode 100644
index 000000000..fac16864f
--- /dev/null
+++ b/packages/mesh-core-csl/src/core/adaptor/metadata.ts
@@ -0,0 +1,35 @@
+import type { Metadatum, TxMetadata } from "@meshsdk/common";
+
+export const txMetadataToObj = (metadata: TxMetadata): object => {
+ const result: Record = {};
+ metadata.forEach((value: Metadatum, key: bigint) => {
+ result[key.toString()] = metadatumToObj(value);
+ });
+ return result;
+};
+
+const metadatumToObj = (metadatum: Metadatum): any => {
+ if (typeof metadatum === "number" || typeof metadatum === "string") {
+ return metadatum;
+ } else if (typeof metadatum === "bigint") {
+ return metadatum.toString();
+ } else if (metadatum instanceof Uint8Array) {
+ return uint8ArrayToHex(metadatum);
+ } else if (metadatum instanceof Map) {
+ const result: Record = {};
+ metadatum.forEach((value, key) => {
+ result[metadatumToObj(key)] = metadatumToObj(value);
+ });
+ return result;
+ } else if (Array.isArray(metadatum)) {
+ return metadatum.map(metadatumToObj);
+ } else {
+ throw new Error("metadatumToObj: Unsupported Metadatum type");
+ }
+};
+
+const uint8ArrayToHex = (bytes: Uint8Array): string => {
+ return Array.from(bytes)
+ .map(byte => byte.toString(16).padStart(2, "0"))
+ .join("");
+};
diff --git a/packages/mesh-core-csl/test/core/builder.test.ts b/packages/mesh-core-csl/test/core/builder.test.ts
index bc690b184..64cb0c499 100644
--- a/packages/mesh-core-csl/test/core/builder.test.ts
+++ b/packages/mesh-core-csl/test/core/builder.test.ts
@@ -85,7 +85,7 @@ describe("Builder", () => {
mints: [],
changeAddress:
"addr_test1qq0yavv5uve45rwvfaw96qynrqt8ckpmkwcg08vlwxxdncxk82f5wz75mzaesmqzl79xqsmedwgucwtuav5str6untqqmykcpn",
- metadata: [],
+ metadata: new Map(),
validityRange: {},
certificates: [],
withdrawals: [],
diff --git a/packages/mesh-transaction/src/mesh-tx-builder/tx-builder-core.ts b/packages/mesh-transaction/src/mesh-tx-builder/tx-builder-core.ts
index 8c02608e8..23a51c10d 100644
--- a/packages/mesh-transaction/src/mesh-tx-builder/tx-builder-core.ts
+++ b/packages/mesh-transaction/src/mesh-tx-builder/tx-builder-core.ts
@@ -35,7 +35,7 @@ import {
Withdrawal,
} from "@meshsdk/common";
-import { MetadataMergeLevel, mergeAllMetadataByTag } from "../utils";
+import { MetadataMergeLevel, metadataObjToMap, setAndMergeTxMetadata } from "../utils";
export class MeshTxBuilderCore {
txEvaluationMultiplier = 1.1;
@@ -1414,18 +1414,16 @@ export class MeshTxBuilderCore {
/**
* Add metadata to the transaction
- * @param tag The tag of the metadata
+ * @param label The label of the metadata, preferably number
* @param metadata The metadata in any format
- * @param mergeExistingMetadataByTag Whether to merge the new metadata
- * under a tag with the existing metadata with the same tag
+ * @param mergeExistingMetadataByLabel Whether to merge the new metadata
+ * with any existing metadata under the same label, and upto what level
* @returns The MeshTxBuilder instance
*/
- metadataValue = (tag: string, metadata: any, mergeExistingMetadataByTag: MetadataMergeLevel = false) => {
- const metadataString = JSONBig.stringify(metadata);
- this.meshTxBuilderBody.metadata.push({ tag, metadata: metadataString });
- if (mergeExistingMetadataByTag) {
- this.meshTxBuilderBody.metadata = mergeAllMetadataByTag(this.meshTxBuilderBody.metadata, tag, mergeExistingMetadataByTag);
- }
+ metadataValue = (label: number | bigint | string, metadata: any, mergeExistingMetadataByLabel: MetadataMergeLevel = false) => {
+ label = BigInt(label);
+ metadata = metadataObjToMap(metadata);
+ setAndMergeTxMetadata(this.meshTxBuilderBody.metadata, label, metadata, mergeExistingMetadataByLabel);
return this;
};
diff --git a/packages/mesh-transaction/src/transaction/index.ts b/packages/mesh-transaction/src/transaction/index.ts
index fb3eecfef..7838301e6 100644
--- a/packages/mesh-transaction/src/transaction/index.ts
+++ b/packages/mesh-transaction/src/transaction/index.ts
@@ -586,15 +586,15 @@ export class Transaction {
/**
* Add a JSON metadata entry to the transaction.
*
- * @param {number} key The key to use for the metadata entry.
- * @param {unknown} value The value to use for the metadata entry.
- * @param {MetadataMergeLevel} mergeExistingMetadataByTag Whether to merge the new metadata
- * under a tag (key) with the existing metadata with the same tag
+ * @param {number} label The label to use for the metadata entry.
+ * @param {unknown} metadata The value to use for the metadata entry.
+ * @param {MetadataMergeLevel} mergeExistingMetadataByLabel Whether to merge the new metadata
+ * with any existing metadata under the same label, and upto what level
* @returns {Transaction} The Transaction object.
* @see {@link https://meshjs.dev/apis/transaction#setMetadata}
*/
- setMetadata(key: number, value: unknown, mergeExistingMetadataByTag: MetadataMergeLevel = false): Transaction {
- this.txBuilder.metadataValue(key.toString(), value as object, mergeExistingMetadataByTag);
+ setMetadata(label: number, metadata: unknown, mergeExistingMetadataByLabel: MetadataMergeLevel = false): Transaction {
+ this.txBuilder.metadataValue(label, metadata as object, mergeExistingMetadataByLabel);
return this;
}
diff --git a/packages/mesh-transaction/src/transaction/transaction-v2.ts b/packages/mesh-transaction/src/transaction/transaction-v2.ts
index 0fc7151db..184f3a819 100644
--- a/packages/mesh-transaction/src/transaction/transaction-v2.ts
+++ b/packages/mesh-transaction/src/transaction/transaction-v2.ts
@@ -12,6 +12,8 @@ import {
UTxO,
} from "@meshsdk/common";
+import type { MetadataMergeLevel } from "../utils/metadata";
+
export interface TransactionV2 {
sendAssets(
receiver: string,
@@ -47,7 +49,11 @@ export interface TransactionV2 {
setRequiredSigners(addresses: string[]): this;
setTimeToExpire(slot: string): this;
setTimeToStart(slot: string): this;
- setMetadata(key: number, value: unknown): this;
+ setMetadata(
+ label: number,
+ metadata: unknown,
+ mergeExistingMetadataByLabel: MetadataMergeLevel
+ ): this;
withdrawRewards(rewardAddress: string, lovelace: string): this;
delegateStake(rewardAddress: string, poolId: string): this;
deregisterStake(rewardAddress: string): this;
diff --git a/packages/mesh-transaction/src/utils/metadata.ts b/packages/mesh-transaction/src/utils/metadata.ts
index e345ce0b2..e2d1f150b 100644
--- a/packages/mesh-transaction/src/utils/metadata.ts
+++ b/packages/mesh-transaction/src/utils/metadata.ts
@@ -1,34 +1,64 @@
import JSONBig from "json-bigint";
-import { Metadata } from "@meshsdk/common";
-
-type ValueType = "array" | "object" | "primitive" | "nullish";
+import type { TxMetadata, Metadatum, MetadatumMap } from "@meshsdk/common";
export type MetadataMergeLevel = boolean | number;
-const getMergeDepth = (mergeOption: MetadataMergeLevel): number => {
- return typeof mergeOption === "number"
- ? mergeOption
- : mergeOption === true
- ? 1
- : 0;
+export const metadataObjToMap = (metadata: any): Metadatum => {
+ if (typeof metadata === "bigint") {
+ return metadata;
+ } else if (typeof metadata === "string") {
+ return metadata;
+ } else if (typeof metadata === "number") {
+ return metadata;
+ } else if (metadata instanceof Uint8Array) {
+ return metadata;
+ } else if (Array.isArray(metadata)) {
+ // Recursively process each element in the array
+ return metadata.map(metadataObjToMap);
+ } else if (metadata && typeof metadata === "object") {
+ // Convert object to MetadatumMap
+ const map: MetadatumMap = new Map();
+ Object.entries(metadata).forEach(([key, value]) => {
+ map.set(metadataObjToMap(key), metadataObjToMap(value));
+ });
+ return map;
+ } else {
+ throw new Error("Metadata map conversion: Unsupported metadata type");
+ }
}
-const getType = (value: unknown): ValueType => {
- if (Array.isArray(value))
- return "array";
- if (value !== null && typeof value === "object")
- return "object";
- if (value === null || value === undefined)
- return "nullish";
- return "primitive";
+/**
+ * Insert new metadata under a label into the transaction's metadata section
+ * and optionally merge with the existing metadata under the same label recursively
+ * upto a specified depth.
+ *
+ * @param txMetadata metadata map of meshTxBuilderBody, updated implicitly
+ * @param label label that the new metadata corresponds to
+ * @param metadata the new metadata
+ * @param mergeOption the effective depth till which the merge should happen,
+ * beyond this depth, the newer element would replace the older one.
+ * If false or 0, the new metadata overwrites any existing metadata
+ * under the same label
+ * @returns updated metadata map for meshTxBuilderBody
+ */
+export const setAndMergeTxMetadata = (txMetadata: TxMetadata, label: bigint, metadata: Metadatum, mergeOption: MetadataMergeLevel): TxMetadata => {
+ const mergeDepth = getMergeDepth(mergeOption);
+
+ if (txMetadata.has(label)) {
+ txMetadata.set(label, mergeContents(txMetadata.get(label) as Metadatum, metadata, mergeDepth));
+ } else {
+ txMetadata.set(label, metadata);
+ }
+
+ return txMetadata;
}
/**
- * Recursively merge two items. Returns the 2nd item if the maximum allowed
+ * Recursively merge two metadata. Returns the 2nd item if the maximum allowed
* merge depth has passed.
*
- * Merging objects ({ key: value }):
- * Two objects are merged by recursively including the (key, value) pairs from both the objects.
+ * Merging maps ({ key: value }):
+ * Two maps are merged by recursively including the (key, value) pairs from both the maps.
* When further merge isn't allowed (by currentDepth), the 2nd item is preferred,
* replacing the 1st item.
*
@@ -46,88 +76,71 @@ const getType = (value: unknown): ValueType => {
* @param currentDepth the current merge depth; decreases in a recursive call
* @returns merged item or a preferred item, chosen according to currentDepth
*/
-const mergeContents = (a: any, b: any, currentDepth: number): any => {
- const type_a = getType(a);
- const type_b = getType(b);
-
- if (currentDepth <= 0 || type_a === "nullish" || type_b === "nullish") {
- // Tend to return the 2nd item, which is supposed to be the updated one
- // If both are nullish, 2nd item is returned
- return b ?? a ?? b;
+const mergeContents = (a: Metadatum, b: Metadatum, currentDepth: number): Metadatum => {
+ // Handle no merge
+ if (currentDepth <= 0) {
+ return b;
}
-
- if (type_a === "primitive" && type_b === "primitive") {
- if (a === b) {
- return b;
- } else {
- throw new Error(`Tx metadata merge error: cannot merge ${a} with ${b}`);
- }
+ // Handle merging of maps
+ if (a instanceof Map && b instanceof Map) {
+ b.forEach((value: Metadatum, key: Metadatum) => {
+ if (a.has(key)) {
+ a.set(key, mergeContents(a.get(key) as Metadatum, value, currentDepth - 1));
+ } else {
+ a.set(key, value);
+ }
+ });
+ return a;
}
-
- else if (type_a === "array" && type_b === "array") {
+ // Handle merging of arrays
+ else if (Array.isArray(a) && Array.isArray(b)) {
return [...a, ...b];
}
-
- else if (type_a === "object" && type_b === "object") {
- for (const key in b) {
- Object.assign(a, { [key]: mergeContents(a[key], b[key], currentDepth - 1) });
+ // Handle merging of primitive types
+ if (
+ (typeof a === "number" || typeof a === "bigint" || typeof a === "string" || a instanceof Uint8Array) &&
+ (typeof b === "number" || typeof b === "bigint" || typeof b === "string" || b instanceof Uint8Array)
+ ) {
+ if (typeof a === typeof b) {
+ if (a === b) {
+ // Equal primitive types (string, number or bigint)
+ return b;
+ }
+ if (a instanceof Uint8Array && b instanceof Uint8Array && areUint8ArraysEqual(a, b)) {
+ // Equal Uint8Array values
+ return b;
+ }
}
- return a;
+ // If values are not equal or types are mismatched
+ throw new Error(`Tx metadata merge error: cannot merge ${JSONBig.stringify(a)} with ${JSONBig.stringify(b)}`);
}
- throw new Error(`Tx metadata merge error: cannot merge ${type_a} type with ${type_b} type`);
+ // Unsupported or mismatched types
+ throw new Error(`Tx metadata merge error: cannot merge ${getMetadatumType(a)} type with ${getMetadatumType(b)} type`);
}
-const mergeChosenMetadata = (metadataArr: string[], tag: string, mergeDepth: number): Metadata[] => {
- if (!metadataArr.length)
- return [];
-
- // Assuming all the elements are JSON stringified, parse them first
- for (let i = 0; i < metadataArr.length; i++) {
- try {
- metadataArr[i] = JSONBig.parse(metadataArr[i]!);
- } catch (e) {
- throw new Error(`Tx metadata merge error: cannot parse metadata value: ${e}`);
- }
- }
+const getMergeDepth = (mergeOption: MetadataMergeLevel): number => {
+ return typeof mergeOption === "number"
+ ? mergeOption
+ : mergeOption === true
+ ? 1
+ : 0;
+}
- let mergedSoFar = metadataArr[0];
+const getMetadatumType = (a: Metadatum): string => {
+ if (a instanceof Map) return "map";
+ if (Array.isArray(a)) return "array";
+ return "primitive";
+}
- for (let i = 1; i < metadataArr.length; i++) {
- mergedSoFar = mergeContents(mergedSoFar, metadataArr[i], mergeDepth);
+const areUint8ArraysEqual = (a: Uint8Array, b: Uint8Array): boolean => {
+ if (a.length !== b.length) {
+ return false;
}
-
- return [{ tag, metadata: JSONBig.stringify(mergedSoFar) }];
-};
-
-/**
- * Merges multiple metadata entries in an array of metadata that belong to the same tag.
- * Can merge objects upto a defined depth.
- *
- * @param metadataList metadata array of meshTxBuilderBody
- * @param tag tag value to group all the metadata belonging to that same tag
- * @param mergeOption the effective depth till which the merge will happen,
- * beyond this depth, the newer element would replace the older one.
- * If false or 0, the latest metadata entry with the specified tag is preserved
- * and the earlier ones are discarded
- * @returns metadata array for meshTxBuilderBody; with all the metadata entries not belonging
- * to the specified tag are preserved
- */
-export const mergeAllMetadataByTag = (metadataList: Metadata[], tag: string, mergeOption: MetadataMergeLevel): Metadata[] => {
- const mergeDepth = getMergeDepth(mergeOption);
-
- const chosenElementsMetadata = [];
- const restElements = [];
-
- for (const metadata of metadataList) {
- if (metadata.tag == tag) { // Number can also match here
- chosenElementsMetadata.push(metadata.metadata);
- } else {
- restElements.push(metadata);
+ for (let i = 0; i < a.length; i++) {
+ if (a[i] !== b[i]) {
+ return false;
}
}
-
- const mergedItem = mergeChosenMetadata(chosenElementsMetadata, tag, mergeDepth);
-
- return [...restElements, ...mergedItem];
+ return true;
}
diff --git a/packages/mesh-transaction/test/transaction/txMetadata.test.ts b/packages/mesh-transaction/test/transaction/txMetadata.test.ts
index a0cbd8765..67d10799b 100644
--- a/packages/mesh-transaction/test/transaction/txMetadata.test.ts
+++ b/packages/mesh-transaction/test/transaction/txMetadata.test.ts
@@ -1,205 +1,199 @@
-import JSONBig from "json-bigint";
-import { Metadata } from "@meshsdk/common";
-import { mergeAllMetadataByTag } from "@meshsdk/transaction";
+import { metadataObjToMap, setAndMergeTxMetadata } from "@meshsdk/transaction";
describe("Transaction Metadata Merge", () => {
-
- const createMetadataArray = (arr: { tag: string, metadata: any }[]): Metadata[] => {
- for (const elem of arr) {
- elem.metadata = JSONBig.stringify(elem.metadata);
- }
- return arr;
- };
-
it("should merge two identical number metadata entries", () => {
- const input = createMetadataArray([
- { tag: "0", metadata: 42 },
- { tag: "0", metadata: 42 },
+ const txMetadata = new Map([
+ [0n, 42]
]);
- const expectedOutput = createMetadataArray([
- { tag: "0", metadata: 42 },
+ const label = 0n;
+ const metadata = 42;
+ const expectedOutput = new Map([
+ [0n, 42]
]);
- const output = mergeAllMetadataByTag(input, "0", true);
- expect(output).toEqual(expectedOutput);
+ setAndMergeTxMetadata(txMetadata, label, metadata, true);
+ expect(txMetadata).toEqual(expectedOutput);
});
it("should merge two identical string metadata entries", () => {
- const input = createMetadataArray([
- { tag: "1", metadata: "42" },
- { tag: "1", metadata: "42" },
+ const txMetadata = new Map([
+ [1n, "Hey!"]
]);
- const expectedOutput = createMetadataArray([
- { tag: "1", metadata: "42" },
+ const label = 1n;
+ const metadata = "Hey!";
+ const expectedOutput = new Map([
+ [1n, "Hey!"]
]);
- const output = mergeAllMetadataByTag(input, "1", true);
- expect(output).toEqual(expectedOutput);
+ setAndMergeTxMetadata(txMetadata, label, metadata, true);
+ expect(txMetadata).toEqual(expectedOutput);
});
it("should not merge two different numbers", () => {
- const input = createMetadataArray([
- { tag: "1", metadata: 42 },
- { tag: "1", metadata: 43 },
+ const txMetadata = new Map([
+ [1n, 42]
]);
- expect(() => mergeAllMetadataByTag(input, "1", true)).toThrow("cannot merge 42 with 43");
+ const label = 1n;
+ const metadata = 43;
+ expect(() => setAndMergeTxMetadata(txMetadata, label, metadata, true)).toThrow("cannot merge 42 with 43");
});
it("should not merge two different strings", () => {
- const input = createMetadataArray([
- { tag: "0", metadata: "Alice" },
- { tag: "0", metadata: "Bob" },
+ const txMetadata = new Map([
+ [0n, "Alice"]
]);
- expect(() => mergeAllMetadataByTag(input, "0", true)).toThrow("cannot merge Alice with Bob");
+ const label = 0n;
+ const metadata = "Bob";
+ expect(() => setAndMergeTxMetadata(txMetadata, label, metadata, true)).toThrow("cannot merge Alice with Bob");
});
it("should not merge two same values of different types", () => {
- const input = createMetadataArray([
- { tag: "0", metadata: 42 },
- { tag: "0", metadata: "42" },
+ const txMetadata = new Map([
+ [0n, 42]
]);
- expect(() => mergeAllMetadataByTag(input, "0", true)).toThrow("cannot merge 42 with 42");
+ const label = 0n;
+ const metadata = "42";
+ expect(() => setAndMergeTxMetadata(txMetadata, label, metadata, true)).toThrow("cannot merge 42 with 42");
});
it("should replace with the latest item if there is no merge", () => {
- const input = createMetadataArray([
- { tag: "1", metadata: 42 },
- { tag: "1", metadata: 43 },
+ const txMetadata = new Map([
+ [1n, 42]
]);
- const expectedOutput = createMetadataArray([
- { tag: "1", metadata: 43 },
+ const label = 1n;
+ const metadata = 43;
+ const expectedOutput = new Map([
+ [1n, 43]
]);
- expect(mergeAllMetadataByTag(input, "1", false)).toEqual(expectedOutput);
+ setAndMergeTxMetadata(txMetadata, label, metadata, false);
+ expect(txMetadata).toEqual(expectedOutput);
});
it("should not merge two different values of the same object key", () => {
- const input = createMetadataArray([
- { tag: "721", metadata: { version: 1 } },
- { tag: "721", metadata: { version: 2 } },
+ const txMetadata = new Map([
+ [721n, metadataObjToMap({ version: 1 })]
]);
- expect(() => mergeAllMetadataByTag(input, "721", 2)).toThrow("cannot merge 1 with 2");
+ const label = 721n;
+ const metadata = metadataObjToMap({ version: 2 });
+ expect(() => setAndMergeTxMetadata(txMetadata, label, metadata, 2)).toThrow("cannot merge 1 with 2");
});
it("should replace with the latest value of the same object key if values are not merged", () => {
- const input = createMetadataArray([
- { tag: "721", metadata: { version: 1 } },
- { tag: "721", metadata: { version: 2 } },
+ const txMetadata = new Map([
+ [721n, metadataObjToMap({ version: 1 })]
]);
- const expectedOutput = createMetadataArray([
- { tag: "721", metadata: { version: 2 } },
+ const label = 721n;
+ const metadata = metadataObjToMap({ version: 2 });
+ const expectedOutput = new Map([
+ [721n, metadataObjToMap({ version: 2 })]
]);
- expect(mergeAllMetadataByTag(input, "721", 1)).toEqual(expectedOutput);
- expect(mergeAllMetadataByTag(input, "721", true)).toEqual(expectedOutput);
+ setAndMergeTxMetadata(txMetadata, label, metadata, 1);
+ expect(txMetadata).toEqual(expectedOutput);
});
it("should not merge different types", () => {
- expect(() => mergeAllMetadataByTag(
- createMetadataArray([
- { tag: "0", metadata: 0 },
- { tag: "0", metadata: [] }
- ]),
- "0",
+ expect(() => setAndMergeTxMetadata(
+ new Map([[0n, 0]]),
+ 0n, // label
+ [], // metadata
true
)).toThrow("cannot merge primitive type with array type");
- expect(() => mergeAllMetadataByTag(
- createMetadataArray([
- { tag: "0", metadata: {} },
- { tag: "0", metadata: "" }
- ]),
- "0",
+ expect(() => setAndMergeTxMetadata(
+ new Map([[0n, metadataObjToMap({})]]),
+ 0n, // label
+ "", // metadata
true
- )).toThrow("cannot merge object type with primitive type");
- expect(() => mergeAllMetadataByTag(
- createMetadataArray([
- { tag: "0", metadata: {} },
- { tag: "0", metadata: [] }
- ]),
- "0",
+ )).toThrow("cannot merge map type with primitive type");
+ expect(() => setAndMergeTxMetadata(
+ new Map([[0n, metadataObjToMap({})]]),
+ 0n, // label
+ [], // metadata
true
- )).toThrow("cannot merge object type with array type");
+ )).toThrow("cannot merge map type with array type");
});
- it("should preserve object key and value if merged with a nullish value", () => {
- expect(mergeAllMetadataByTag(
- createMetadataArray([
- { tag: "0", metadata: { value: 1 } },
- { tag: "0", metadata: { value: null } }
- ]),
- "0",
- 2
- )).toEqual(createMetadataArray([
- { tag: "0", metadata: { value: 1 } }
- ]));
- expect(mergeAllMetadataByTag(
- createMetadataArray([
- { tag: "0", metadata: { value: 1 } },
- { tag: "0", metadata: { value: undefined } }
- ]),
- "0",
- true
- )).toEqual(createMetadataArray([
- { tag: "0", metadata: { value: 1 } }
- ]));
+ it("map conversion should not allow nullish values", () => {
+ expect(() => metadataObjToMap({ "value": null })).toThrow("Unsupported metadata type");
+ });
+ it("should not allow merging with nullish values", () => {
+ const txMetadata = new Map([
+ [1n, metadataObjToMap({ "value": "some" })]
+ ]);
+ const label = 1n;
+ const metadata = new Map([["value", null]]);
+ expect(() => setAndMergeTxMetadata(txMetadata, label, metadata, 1)).toThrow();
});
it("should replace 674 standard msg array for default merge depth", () => {
- const input = createMetadataArray([
- { tag: "674", metadata: { msg: ["A", "B", "C"] } },
- { tag: "674", metadata: { msg: ["D", "E", "F"] } },
- { tag: "674", metadata: { msg2: ["X", "Y", "Z"] } },
+ const txMetadata = new Map([
+ [
+ 674n,
+ metadataObjToMap({
+ msg: ["A", "B", "C"],
+ msg2: ["X", "Y", "Z"]
+ })
+ ]
]);
-
- const expectedOutput = createMetadataArray([
- {
- tag: "674", metadata: {
+ const label = 674n;
+ const metadata = metadataObjToMap({
+ msg: ["D", "E", "F"]
+ });
+ const expectedOutput = new Map([
+ [
+ 674n,
+ metadataObjToMap({
msg: ["D", "E", "F"],
msg2: ["X", "Y", "Z"]
- }
- }
+ })
+ ]
]);
-
- expect(mergeAllMetadataByTag(input, "674", 1)).toEqual(expectedOutput);
- expect(mergeAllMetadataByTag(input, "674", true)).toEqual(expectedOutput);
+ setAndMergeTxMetadata(txMetadata, label, metadata, true);
+ expect(txMetadata).toEqual(expectedOutput);
});
it("should concatenate 674 standard msg arrays for merge depth 2", () => {
- const input = createMetadataArray([
- { tag: "674", metadata: { msg: ["A", "B", "C"] } },
- { tag: "674", metadata: { msg: ["D", "E", "F"] } },
- { tag: "674", metadata: { msg2: ["X", "Y", "Z"] } },
+ const txMetadata = new Map([
+ [
+ 674n,
+ metadataObjToMap({
+ msg: ["A", "B", "C"],
+ msg2: ["X", "Y", "Z"]
+ })
+ ]
]);
-
- const expectedOutput = createMetadataArray([
- {
- tag: "674", metadata: {
+ const label = 674n;
+ const metadata = metadataObjToMap({
+ msg: ["D", "E", "F"]
+ });
+ const expectedOutput = new Map([
+ [
+ 674n,
+ metadataObjToMap({
msg: ["A", "B", "C", "D", "E", "F"],
msg2: ["X", "Y", "Z"]
- }
- }
+ })
+ ]
]);
-
- expect(mergeAllMetadataByTag(input, "674", 2)).toEqual(expectedOutput);
+ setAndMergeTxMetadata(txMetadata, label, metadata, 2);
+ expect(txMetadata).toEqual(expectedOutput);
});
it("should merge multiple CIP-25 NFTs metadata under the same policy id", () => {
- const input: Metadata[] = createMetadataArray([
- {
- tag: "721",
- metadata: {
+ const txMetadata = new Map([
+ [
+ 721n,
+ metadataObjToMap({
"policyId1": {
"My NFT 1": {
"name": "My NFT 1"
}
}
- }
- },
- {
- tag: "721",
- metadata: {
- "policyId1": {
- "My NFT 2": {
- "name": "My NFT 2",
- "description": "My second NFT"
- }
- }
+ })
+ ]
+ ]);
+ const label = 721n;
+ const metadata = metadataObjToMap({
+ "policyId1": {
+ "My NFT 2": {
+ "name": "My NFT 2",
+ "description": "My second NFT"
}
}
- ]);
-
- const expectedOutput: Metadata[] = createMetadataArray([
- {
- tag: "721",
- metadata: {
+ });
+ const expectedOutput = new Map([
+ [
+ 721n,
+ metadataObjToMap({
"policyId1": {
"My NFT 1": {
"name": "My NFT 1"
@@ -209,18 +203,18 @@ describe("Transaction Metadata Merge", () => {
"description": "My second NFT"
}
}
- }
- }
+ })
+ ]
]);
-
- expect(mergeAllMetadataByTag(input, "721", 2)).toEqual(expectedOutput);
+ setAndMergeTxMetadata(txMetadata, label, metadata, 2);
+ expect(txMetadata).toEqual(expectedOutput);
});
it("should merge multiple CIP-25 NFTs metadata under different policy ids", () => {
- const input = createMetadataArray([
- {
- tag: "721",
- metadata: {
+ const txMetadata = new Map([
+ [
+ 721n,
+ metadataObjToMap({
"policyId1": {
"My NFT 1": {
"name": "My NFT 1",
@@ -229,40 +223,60 @@ describe("Transaction Metadata Merge", () => {
]
}
}
+ })
+ ]
+ ]);
+ const label = 721n;
+ const metadata1 = metadataObjToMap({
+ "policyId2": {
+ "My NFT 1": {
+ "name": "My NFT 1 Policy 2",
+ "files": [
+ { name: "NFT 1 P 2", src: "abc", mediaType: "image/png" }
+ ]
}
- },
- {
- tag: "721",
- metadata: {
- "policyId2": {
+ }
+ });
+ const expectedOutput1 = new Map([
+ [
+ 721n,
+ metadataObjToMap({
+ "policyId1": {
"My NFT 1": {
- "name": "My NFT 1 Policy 2",
+ "name": "My NFT 1",
"files": [
- { name: "NFT 1 P 2", src: "abc", mediaType: "image/png" }
+ { name: "NFT 1 Image", src: "xyz", mediaType: "image/jpeg" }
]
}
- }
- }
- },
- {
- tag: "721",
- metadata: {
- "policyId1": {
- "My NFT 2": {
- "name": "My NFT 2",
+ },
+ "policyId2": {
+ "My NFT 1": {
+ "name": "My NFT 1 Policy 2",
"files": [
- { name: "NFT 2 Image", src: "pqr", mediaType: "image/jpeg" }
+ { name: "NFT 1 P 2", src: "abc", mediaType: "image/png" }
]
}
}
+ })
+ ]
+ ]);
+ setAndMergeTxMetadata(txMetadata, label, metadata1, 2);
+ expect(txMetadata).toEqual(expectedOutput1);
+ // Merge more NFT metadata
+ const metadata2 = metadataObjToMap({
+ "policyId1": {
+ "My NFT 2": {
+ "name": "My NFT 2",
+ "files": [
+ { name: "NFT 2 Image", src: "pqr", mediaType: "image/jpeg" }
+ ]
}
}
- ]);
-
- const expectedOutput = createMetadataArray([
- {
- tag: "721",
- metadata: {
+ });
+ const expectedOutput2 = new Map([
+ [
+ 721n,
+ metadataObjToMap({
"policyId1": {
"My NFT 1": {
"name": "My NFT 1",
@@ -285,133 +299,90 @@ describe("Transaction Metadata Merge", () => {
]
}
}
- }
- }
+ })
+ ]
]);
-
- expect(mergeAllMetadataByTag(input, "721", 2)).toEqual(expectedOutput);
+ setAndMergeTxMetadata(txMetadata, label, metadata2, 2);
+ expect(txMetadata).toEqual(expectedOutput2);
});
it("should replace with the latest CIP-25 NFT metadata of the same policy and asset id", () => {
- const input = createMetadataArray([
- {
- tag: "721",
- metadata: {
- "policyId1": {
- "My NFT 1": { name: "NFT 1 Name", files: [{ name: "NFT Image" }] } // old metadata here
- }
- }
- },
- {
- tag: "721",
- metadata: {
+ const txMetadata = new Map([
+ [
+ 721n,
+ metadataObjToMap({
"policyId1": {
+ "My NFT 1": { name: "NFT 1 Name", files: [{ name: "NFT Image" }] }, // old metadata here
"My NFT 2": { name: "NFT 2 Name" }
}
- }
- },
- {
- tag: "721",
- metadata: {
- "policyId1": {
- "My NFT 1": { name: "Latest NFT 1", image: "xyz", description: "Latest NFT here" }
- }
- }
- }
+ })
+ ]
]);
-
- const expectedOutput = createMetadataArray([
- {
- tag: "721",
- metadata: {
+ const label = 721n;
+ const metadata = metadataObjToMap({
+ "policyId1": {
+ "My NFT 1": { name: "Latest NFT 1", image: "xyz", description: "Latest NFT here" }
+ }
+ });
+ const expectedOutput = new Map([
+ [
+ 721n,
+ metadataObjToMap({
"policyId1": {
"My NFT 1": { name: "Latest NFT 1", image: "xyz", description: "Latest NFT here" },
"My NFT 2": { name: "NFT 2 Name" }
}
- }
- }
+ })
+ ]
]);
-
- expect(mergeAllMetadataByTag(input, "721", 2)).toEqual(expectedOutput);
+ setAndMergeTxMetadata(txMetadata, label, metadata, 2);
+ expect(txMetadata).toEqual(expectedOutput);
});
it("should attach version to CIP-25 metadata", () => {
- const input = createMetadataArray([
- {
- tag: "721",
- metadata: {
- "policyId1": { "My NFT 1": { name: "My NFT 1" } }
- }
- },
- {
- tag: "721",
- metadata: {
- "policyId1": { "My NFT 2": { name: "My NFT 2" } }
- }
- },
- {
- tag: "721",
- metadata: {
- version: "1.0"
- }
- },
- {
- tag: "721",
- metadata: {
+ const txMetadata = new Map([
+ [
+ 721n,
+ metadataObjToMap({
+ "policyId1": { "My NFT 1": { name: "My NFT 1" } },
"policyId2": { "My NFT 1": { name: "My NFT 1 Policy 2" } }
- }
- }
+ })
+ ]
]);
-
- const expectedOutput = createMetadataArray([
- {
- tag: "721",
- metadata: {
- "policyId1": {
- "My NFT 1": { name: "My NFT 1" },
- "My NFT 2": { name: "My NFT 2" }
- },
- "version": "1.0", // version inserted in an ordered manner
- "policyId2": {
- "My NFT 1": { name: "My NFT 1 Policy 2" }
- }
- }
- }
+ const label = 721n;
+ const metadata = metadataObjToMap({
+ version: 1
+ });
+ const expectedOutput = new Map([
+ [
+ 721n,
+ metadataObjToMap({
+ "policyId1": { "My NFT 1": { name: "My NFT 1" } },
+ "policyId2": { "My NFT 1": { name: "My NFT 1 Policy 2" } },
+ "version": 1
+ })
+ ]
]);
-
- expect(mergeAllMetadataByTag(input, "721", 2)).toEqual(expectedOutput);
+ setAndMergeTxMetadata(txMetadata, label, metadata, 2);
+ expect(txMetadata).toEqual(expectedOutput);
});
it("should preserve metadata entries with other tags in the original order", () => {
- const input = createMetadataArray([
- { tag: "0", metadata: "line 1" },
- { tag: "0", metadata: "line 2" },
- { tag: "674", metadata: { msg: ["line 3"] } },
- { tag: "721", metadata: { policyId: { NFT: { name: "NFT" } } } },
- { tag: "674", metadata: { msg: ["line 5"] } },
- { tag: "721", metadata: { policyId: { NFT2: { name: "NFT 2" } } } },
- { tag: "1", metadata: "line 7" },
+ const txMetadata = new Map([
+ [0n, metadataObjToMap("line 1")],
+ [674n, metadataObjToMap({ msg: "line 2" })],
+ [721n, metadataObjToMap({ policyId1: { NFT1: { name: "line 3" } } })],
+ [1n, metadataObjToMap("line 4")]
]);
-
- const expectedOutput1 = createMetadataArray([
- { tag: "0", metadata: "line 1" },
- { tag: "0", metadata: "line 2" },
- { tag: "674", metadata: { msg: ["line 3"] } },
- { tag: "674", metadata: { msg: ["line 5"] } },
- { tag: "1", metadata: "line 7" },
- { tag: "721", metadata: { policyId: { NFT: { name: "NFT" }, NFT2: { name: "NFT 2" } } } },
+ const label = 721n;
+ const metadata = metadataObjToMap({ policyId1: { NFT2: { name: "line 5" } } });
+ const expectedOutput = new Map([
+ [0n, metadataObjToMap("line 1")],
+ [674n, metadataObjToMap({ msg: "line 2" })],
+ [721n, metadataObjToMap({ policyId1: { NFT1: { name: "line 3" }, NFT2: { name: "line 5" } } })],
+ [1n, metadataObjToMap("line 4")]
]);
-
- expect(mergeAllMetadataByTag(input, "721", 2)).toEqual(expectedOutput1);
-
- const expectedOutput2 = createMetadataArray([
- { tag: "0", metadata: "line 1" },
- { tag: "0", metadata: "line 2" },
- { tag: "1", metadata: "line 7" },
- { tag: "721", metadata: { policyId: { NFT: { name: "NFT" }, NFT2: { name: "NFT 2" } } } },
- { tag: "674", metadata: { msg: ["line 5"] } },
- ]);
-
- expect(mergeAllMetadataByTag(expectedOutput1, "674", true)).toEqual(expectedOutput2);
+ setAndMergeTxMetadata(txMetadata, label, metadata, 2);
+ expect(txMetadata).toEqual(expectedOutput);
});
});