@silvana-one/nft 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/dist/node/contracts/collection.d.ts +6 -1
  2. package/dist/node/contracts/collection.js +6 -4
  3. package/dist/node/contracts/collection.js.map +1 -1
  4. package/dist/node/index.cjs +834 -590
  5. package/dist/node/index.d.ts +1 -0
  6. package/dist/node/index.js +1 -0
  7. package/dist/node/index.js.map +1 -1
  8. package/dist/node/interfaces/owner.d.ts +1 -1
  9. package/dist/node/interfaces/types.d.ts +2 -2
  10. package/dist/node/interfaces/types.js +2 -2
  11. package/dist/node/interfaces/types.js.map +1 -1
  12. package/dist/node/marketplace/auction.js +11 -2
  13. package/dist/node/marketplace/auction.js.map +1 -1
  14. package/dist/node/marketplace/nft-shares.js +6 -5
  15. package/dist/node/marketplace/nft-shares.js.map +1 -1
  16. package/dist/node/metadata/address.d.ts +38 -0
  17. package/dist/node/metadata/address.js +39 -0
  18. package/dist/node/metadata/address.js.map +1 -0
  19. package/dist/node/metadata/index.d.ts +1 -0
  20. package/dist/node/metadata/index.js +1 -0
  21. package/dist/node/metadata/index.js.map +1 -1
  22. package/dist/node/metadata/metadata.d.ts +37 -6
  23. package/dist/node/metadata/metadata.js +147 -4
  24. package/dist/node/metadata/metadata.js.map +1 -1
  25. package/dist/node/metadata/pin.d.ts +10 -0
  26. package/dist/node/metadata/pin.js +18 -0
  27. package/dist/node/metadata/pin.js.map +1 -0
  28. package/dist/node/metadata/tree.d.ts +1 -1
  29. package/dist/node/metadata/tree.js +2 -2
  30. package/dist/node/metadata/tree.js.map +1 -1
  31. package/dist/node/util/div.d.ts +62 -0
  32. package/dist/node/util/div.js +39 -0
  33. package/dist/node/util/div.js.map +1 -0
  34. package/dist/node/util/index.d.ts +1 -0
  35. package/dist/node/util/index.js +2 -0
  36. package/dist/node/util/index.js.map +1 -0
  37. package/dist/tsconfig.tsbuildinfo +1 -1
  38. package/dist/tsconfig.web.tsbuildinfo +1 -1
  39. package/dist/web/contracts/collection.d.ts +6 -1
  40. package/dist/web/contracts/collection.js +6 -4
  41. package/dist/web/contracts/collection.js.map +1 -1
  42. package/dist/web/index.d.ts +1 -0
  43. package/dist/web/index.js +1 -0
  44. package/dist/web/index.js.map +1 -1
  45. package/dist/web/interfaces/owner.d.ts +1 -1
  46. package/dist/web/interfaces/types.d.ts +2 -2
  47. package/dist/web/interfaces/types.js +2 -2
  48. package/dist/web/interfaces/types.js.map +1 -1
  49. package/dist/web/marketplace/auction.js +11 -2
  50. package/dist/web/marketplace/auction.js.map +1 -1
  51. package/dist/web/marketplace/nft-shares.js +6 -5
  52. package/dist/web/marketplace/nft-shares.js.map +1 -1
  53. package/dist/web/metadata/address.d.ts +38 -0
  54. package/dist/web/metadata/address.js +39 -0
  55. package/dist/web/metadata/address.js.map +1 -0
  56. package/dist/web/metadata/index.d.ts +1 -0
  57. package/dist/web/metadata/index.js +1 -0
  58. package/dist/web/metadata/index.js.map +1 -1
  59. package/dist/web/metadata/metadata.d.ts +37 -6
  60. package/dist/web/metadata/metadata.js +147 -4
  61. package/dist/web/metadata/metadata.js.map +1 -1
  62. package/dist/web/metadata/pin.d.ts +10 -0
  63. package/dist/web/metadata/pin.js +18 -0
  64. package/dist/web/metadata/pin.js.map +1 -0
  65. package/dist/web/metadata/tree.d.ts +1 -1
  66. package/dist/web/metadata/tree.js +2 -2
  67. package/dist/web/metadata/tree.js.map +1 -1
  68. package/dist/web/util/div.d.ts +62 -0
  69. package/dist/web/util/div.js +39 -0
  70. package/dist/web/util/div.js.map +1 -0
  71. package/dist/web/util/index.d.ts +1 -0
  72. package/dist/web/util/index.js +2 -0
  73. package/dist/web/util/index.js.map +1 -0
  74. package/package.json +8 -8
  75. package/src/contracts/collection.ts +6 -4
  76. package/src/index.ts +1 -0
  77. package/src/interfaces/owner.ts +1 -1
  78. package/src/interfaces/types.ts +4 -4
  79. package/src/marketplace/auction.ts +13 -2
  80. package/src/marketplace/nft-shares.ts +7 -8
  81. package/src/metadata/address.ts +50 -0
  82. package/src/metadata/index.ts +1 -0
  83. package/src/metadata/metadata.ts +236 -11
  84. package/src/metadata/pin.ts +30 -0
  85. package/src/metadata/tree.ts +4 -3
  86. package/src/util/div.ts +44 -0
  87. package/src/util/index.ts +1 -0
@@ -315,7 +315,7 @@ class NFTData extends Struct({
315
315
  owner: string | PublicKey;
316
316
  approved?: string | PublicKey;
317
317
  version?: number;
318
- id?: bigint;
318
+ id?: bigint | string;
319
319
  canChangeOwnerByProof?: boolean;
320
320
  canTransfer?: boolean;
321
321
  canApprove?: boolean;
@@ -351,7 +351,7 @@ class NFTData extends Struct({
351
351
  : approved
352
352
  : PublicKey.empty(),
353
353
  version: UInt32.from(version ?? 0),
354
- id: UInt64.from(id ?? 0),
354
+ id: UInt64.from(BigInt(id ?? 0)),
355
355
  canChangeOwnerByProof: Bool(canChangeOwnerByProof ?? false),
356
356
  canTransfer: Bool(canTransfer ?? true),
357
357
  canApprove: Bool(canApprove ?? true),
@@ -470,7 +470,7 @@ class CollectionData extends Struct({
470
470
  */
471
471
  static new(params: {
472
472
  royaltyFee?: number;
473
- transferFee?: number;
473
+ transferFee?: number | bigint | string;
474
474
  requireTransferApproval?: boolean;
475
475
  mintingIsLimited?: boolean;
476
476
  isPaused?: boolean;
@@ -484,7 +484,7 @@ class CollectionData extends Struct({
484
484
  } = params;
485
485
  return new CollectionData({
486
486
  royaltyFee: UInt32.from(royaltyFee ?? 0),
487
- transferFee: UInt64.from(transferFee ?? 0),
487
+ transferFee: UInt64.from(BigInt(transferFee ?? 0)),
488
488
  requireTransferApproval: Bool(requireTransferApproval ?? false),
489
489
  mintingIsLimited: Bool(mintingIsLimited ?? false),
490
490
  isPaused: Bool(isPaused ?? false),
@@ -25,6 +25,7 @@ import {
25
25
  TransferExtendedParams,
26
26
  TransferParams,
27
27
  } from "../interfaces/index.js";
28
+ import { mulDiv } from "../util/index.js";
28
29
 
29
30
  const MAX_SALE_FEE = 100000;
30
31
  const MIN_STEP = 10; // 1% to previous bid
@@ -252,7 +253,11 @@ export function AuctionFactory(params: {
252
253
  UInt32.from(MAX_SALE_FEE),
253
254
  "Sale fee is too high"
254
255
  );
255
- return price.div(MAX_SALE_FEE).mul(UInt64.from(saleFee));
256
+ return mulDiv({
257
+ value: price,
258
+ multiplier: UInt64.from(saleFee),
259
+ denominator: UInt64.from(MAX_SALE_FEE),
260
+ }).result;
256
261
  }
257
262
  // anyone can call this method to bid, paying the bid amount for the bidder
258
263
  @method.returns(Auction)
@@ -268,7 +273,13 @@ export function AuctionFactory(params: {
268
273
  "Bid should be greater or equal than the minimum price"
269
274
  );
270
275
  price.assertGreaterThan(
271
- bidAmount.add(bidAmount.div(1000).mul(UInt64.from(MIN_STEP))),
276
+ bidAmount.add(
277
+ mulDiv({
278
+ value: bidAmount,
279
+ multiplier: UInt64.from(MIN_STEP),
280
+ denominator: UInt64.from(1000),
281
+ }).result
282
+ ),
272
283
  "Bid should be greater than the existing bid plus the minimum step"
273
284
  );
274
285
  this.network.globalSlotSinceGenesis.requireBetween(
@@ -21,6 +21,7 @@ import {
21
21
  } from "@silvana-one/token";
22
22
  import { NFTOwnerBase, TransferExtendedParams } from "../interfaces/index.js";
23
23
  import { Auction, AuctionFactory } from "./auction.js";
24
+ import { mulDiv } from "../util/index.js";
24
25
 
25
26
  export interface NFTSharesAdminDeployProps
26
27
  extends Exclude<DeployArgs, undefined> {
@@ -275,14 +276,12 @@ export function NFTSharesFactory(params: {
275
276
  balance
276
277
  .equals(UInt64.zero)
277
278
  .assertFalse("Balance is zero, nothing to withdraw");
278
- const amountInMinaField = shares.value
279
- .mul(balance.value)
280
- .div(sharesOutstanding.value);
281
- amountInMinaField.assertLessThanOrEqual(
282
- balance.value,
283
- "Amount in Mina is greater than the balance"
284
- );
285
- const amountInMina = UInt64.Unsafe.fromField(amountInMinaField);
279
+ const amountInMina = mulDiv({
280
+ value: shares,
281
+ multiplier: balance,
282
+ denominator: sharesOutstanding,
283
+ }).result;
284
+
286
285
  const sender = this.sender.getUnconstrained();
287
286
  const senderUpdate = AccountUpdate.createSigned(sender);
288
287
  senderUpdate.balance.addInPlace(amountInMina);
@@ -0,0 +1,50 @@
1
+ import { Field, PublicKey, Poseidon } from "o1js";
2
+ export { MinaAddress };
3
+
4
+ /**
5
+ /**
6
+ * The `MinaAddress` class represents a Mina address in the form of a Merkle tree. The address is converted to its
7
+ * hash and stored as a leaf in the Merkle tree. The root of the tree can be used as a compact representation
8
+ * of the address data in cryptographic proofs.
9
+ */
10
+ class MinaAddress {
11
+ /**
12
+ * The original address.
13
+ */
14
+ readonly address: PublicKey;
15
+ /**
16
+ * The hash of the address.
17
+ */
18
+ readonly hash: Field;
19
+
20
+ /**
21
+ * Constructs a new `MinaAddress` instance by creating a Merkle tree from the given address.
22
+ * The address is converted to its hash and stored as a leaf in the tree.
23
+ *
24
+ * @param address - The address to be represented.
25
+ * @throws Will throw an error if the address is not a valid Mina address.
26
+ */
27
+ constructor(address: PublicKey | string) {
28
+ this.address =
29
+ typeof address === "string" ? PublicKey.fromBase58(address) : address;
30
+ this.hash = Poseidon.hashPacked(PublicKey, this.address);
31
+ }
32
+
33
+ /**
34
+ * Returns the original address.
35
+ *
36
+ * @returns The public key.
37
+ */
38
+ public toPublicKey(): PublicKey {
39
+ return this.address;
40
+ }
41
+
42
+ /**
43
+ * Returns the base58 representation of the address.
44
+ *
45
+ * @returns The base58 representation of the address.
46
+ */
47
+ public toString(): string {
48
+ return this.address.toBase58();
49
+ }
50
+ }
@@ -1,3 +1,4 @@
1
1
  export * from "./metadata.js";
2
2
  export * from "./tree.js";
3
3
  export * from "./text.js";
4
+ export * from "./pin.js";
@@ -1,6 +1,7 @@
1
- import { Field, Poseidon, Struct, Experimental } from "o1js";
1
+ import { Field, Poseidon, Struct, Experimental, PublicKey, UInt64 } from "o1js";
2
2
  import { fieldFromString } from "../interfaces/index.js";
3
3
  import { Text } from "./text.js";
4
+ import { MinaAddress } from "./address.js";
4
5
  import { MetadataTree } from "./tree.js";
5
6
  export {
6
7
  Metadata,
@@ -31,7 +32,9 @@ type MetadataFieldType =
31
32
  | "text"
32
33
  | "image"
33
34
  | "url"
34
- | "field"
35
+ | "field" // Field
36
+ | "number" // UInt64
37
+ | "address" // PublicKey
35
38
  | "map"
36
39
  | "tree";
37
40
 
@@ -50,7 +53,7 @@ class MetadataValue extends Struct({
50
53
  * @returns A new MetadataValue.
51
54
  */
52
55
  static new(params: {
53
- value: Field | Text | Metadata | MetadataTree;
56
+ value: Field | Text | Metadata | MetadataTree | PublicKey | UInt64;
54
57
  type: MetadataFieldType;
55
58
  }) {
56
59
  const { value, type } = params;
@@ -74,6 +77,18 @@ class MetadataValue extends Struct({
74
77
  if (!(value instanceof Field)) throw new Error(`Invalid value type`);
75
78
  valueField = value;
76
79
  break;
80
+ case "number":
81
+ if (!(value instanceof UInt64)) throw new Error(`Invalid value type`);
82
+ valueField = value.value;
83
+ break;
84
+ case "address":
85
+ if (!(value instanceof PublicKey))
86
+ throw new Error(`Invalid value type`);
87
+ const address = new MinaAddress(value);
88
+ valueField = address.hash;
89
+ length = Field(2);
90
+ height = Field(0);
91
+ break;
77
92
  case "map":
78
93
  if (!(value instanceof Metadata)) throw new Error(`Invalid value type`);
79
94
  valueField = value.map.root;
@@ -271,7 +286,14 @@ class Metadata {
271
286
  traits: {
272
287
  [key: string]: {
273
288
  type: string;
274
- value: string | Field | Metadata | MetadataTree | unknown;
289
+ value:
290
+ | string
291
+ | Field
292
+ | Metadata
293
+ | MetadataTree
294
+ | UInt64
295
+ | PublicKey
296
+ | unknown;
275
297
  isPrivate: boolean;
276
298
  };
277
299
  } = {};
@@ -328,7 +350,16 @@ class Metadata {
328
350
  addTrait(params: {
329
351
  key: string;
330
352
  type: string;
331
- value: string | Field | Metadata | MetadataTree | unknown;
353
+ value:
354
+ | string
355
+ | Field
356
+ | Metadata
357
+ | MetadataTree
358
+ | UInt64
359
+ | PublicKey
360
+ | bigint
361
+ | number
362
+ | unknown;
332
363
  isPrivate?: boolean;
333
364
  }): {
334
365
  key: Field;
@@ -340,7 +371,13 @@ class Metadata {
340
371
  let canonicalRepresentation: unknown = value;
341
372
 
342
373
  if (type in MetadataFieldTypeValues) {
343
- let valueObject: Field | Text | Metadata | MetadataTree;
374
+ let valueObject:
375
+ | Field
376
+ | Text
377
+ | Metadata
378
+ | MetadataTree
379
+ | UInt64
380
+ | PublicKey;
344
381
  switch (type) {
345
382
  case "string":
346
383
  if (typeof value !== "string")
@@ -355,9 +392,34 @@ class Metadata {
355
392
  valueObject = new Text(value);
356
393
  break;
357
394
  case "field":
358
- if (!(value instanceof Field))
395
+ if (
396
+ !(
397
+ value instanceof Field ||
398
+ typeof value === "bigint" ||
399
+ typeof value === "number" ||
400
+ typeof value === "string"
401
+ )
402
+ )
359
403
  throw new Error(`Invalid trait value type`);
360
- valueObject = value;
404
+ valueObject = Field(value);
405
+ break;
406
+ case "number":
407
+ if (
408
+ !(
409
+ value instanceof UInt64 ||
410
+ typeof value === "bigint" ||
411
+ typeof value === "number" ||
412
+ typeof value === "string"
413
+ )
414
+ )
415
+ throw new Error(`Invalid trait value type`);
416
+ valueObject = UInt64.from(value);
417
+ break;
418
+ case "address":
419
+ if (!(value instanceof PublicKey || typeof value === "string"))
420
+ throw new Error(`Invalid trait value type`);
421
+ valueObject =
422
+ typeof value === "string" ? PublicKey.fromBase58(value) : value;
361
423
  break;
362
424
  case "map":
363
425
  if (!(value instanceof Metadata))
@@ -431,6 +493,16 @@ class Metadata {
431
493
  throw new Error(`Invalid trait value type`);
432
494
  jsonValue = value.toJSON();
433
495
  break;
496
+ case "number":
497
+ if (!(value instanceof UInt64))
498
+ throw new Error(`Invalid trait value type`);
499
+ jsonValue = value.toJSON();
500
+ break;
501
+ case "address":
502
+ if (!(value instanceof PublicKey))
503
+ throw new Error(`Invalid trait value type`);
504
+ jsonValue = value.toBase58();
505
+ break;
434
506
  case "map":
435
507
  if (!(value instanceof Metadata))
436
508
  throw new Error(`Invalid trait value type`);
@@ -470,7 +542,7 @@ class Metadata {
470
542
  description?: string;
471
543
  banner?: string;
472
544
  metadataRoot: string;
473
- traits: {
545
+ traits?: {
474
546
  key: string;
475
547
  type: string;
476
548
  value: string | object;
@@ -481,7 +553,14 @@ class Metadata {
481
553
  plugins?: MetadataPlugin[];
482
554
  }): Metadata {
483
555
  const { json, checkRoot = false, plugins } = params;
484
- const { name, description, image, banner, metadataRoot, traits } = json;
556
+ const {
557
+ name,
558
+ description,
559
+ image,
560
+ banner,
561
+ metadataRoot,
562
+ traits = [],
563
+ } = json;
485
564
  if (!name) throw new Error(`Metadata name is required`);
486
565
  if (typeof name !== "string") throw new Error(`Invalid metadata name`);
487
566
  if (!image || typeof image !== "string")
@@ -511,7 +590,14 @@ class Metadata {
511
590
  plugins,
512
591
  });
513
592
  for (const { key, type, value, isPrivate } of traits) {
514
- let valueField: string | Field | Metadata | MetadataTree | unknown;
593
+ let valueField:
594
+ | string
595
+ | Field
596
+ | Metadata
597
+ | MetadataTree
598
+ | UInt64
599
+ | PublicKey
600
+ | unknown;
515
601
  switch (type) {
516
602
  case "string":
517
603
  case "text":
@@ -526,6 +612,16 @@ class Metadata {
526
612
  throw new Error(`Invalid trait value type`);
527
613
  valueField = Field.fromJSON(value);
528
614
  break;
615
+ case "number":
616
+ if (typeof value !== "string")
617
+ throw new Error(`Invalid trait value type`);
618
+ valueField = UInt64.fromJSON(value);
619
+ break;
620
+ case "address":
621
+ if (typeof value !== "string")
622
+ throw new Error(`Invalid trait value type`);
623
+ valueField = PublicKey.fromBase58(value);
624
+ break;
529
625
  case "map":
530
626
  if (typeof value !== "object")
531
627
  throw new Error(`Invalid trait value type`);
@@ -587,6 +683,133 @@ class Metadata {
587
683
 
588
684
  return metadata;
589
685
  }
686
+
687
+ /**
688
+ * Constructs a Metadata instance from OpenAPI JSON data (without calculated root).
689
+ * @param params - The parameters including json data, checkRoot flag, and plugins.
690
+ * @returns A new Metadata instance.
691
+ */
692
+ static fromOpenApiJSON(params: {
693
+ json: {
694
+ name: string;
695
+ image: string;
696
+ description?: string;
697
+ banner?: string;
698
+ traits?: {
699
+ key: string;
700
+ type: string;
701
+ value: string | object;
702
+ isPrivate?: boolean;
703
+ }[];
704
+ };
705
+ plugins?: MetadataPlugin[];
706
+ }): Metadata {
707
+ const { json, plugins } = params;
708
+ const { name, description, image, banner, traits = [] } = json;
709
+ if (!name) throw new Error(`Metadata name is required`);
710
+ if (typeof name !== "string") throw new Error(`Invalid metadata name`);
711
+ if (!image || typeof image !== "string")
712
+ throw new Error(`Invalid metadata image`);
713
+ if (description && typeof description !== "string")
714
+ throw new Error(`Invalid metadata description`);
715
+ if (banner && typeof banner !== "string")
716
+ throw new Error(`Invalid metadata banner`);
717
+ if (!traits || !Array.isArray(traits))
718
+ throw new Error(`Metadata traits are required`);
719
+ for (const { key, type, value, isPrivate } of traits) {
720
+ if (!key || typeof key !== "string") throw new Error(`Invalid trait key`);
721
+ if (!type || typeof type !== "string")
722
+ throw new Error(`Invalid trait type`);
723
+ if (!value || (typeof value !== "string" && typeof value !== "object"))
724
+ throw new Error(`Invalid trait value`);
725
+ if (isPrivate && typeof isPrivate !== "boolean")
726
+ throw new Error(`Invalid trait isPrivate`);
727
+ }
728
+ const metadata = new Metadata({
729
+ name,
730
+ description,
731
+ image,
732
+ banner,
733
+ plugins,
734
+ });
735
+ for (const { key, type, value, isPrivate } of traits) {
736
+ let valueField:
737
+ | string
738
+ | Field
739
+ | Metadata
740
+ | MetadataTree
741
+ | UInt64
742
+ | PublicKey
743
+ | unknown;
744
+ switch (type) {
745
+ case "string":
746
+ case "text":
747
+ case "image":
748
+ case "url":
749
+ if (typeof value !== "string")
750
+ throw new Error(`Invalid trait value type`);
751
+ valueField = value;
752
+ break;
753
+ case "field":
754
+ if (typeof value !== "string")
755
+ throw new Error(`Invalid trait value type`);
756
+ valueField = Field.fromJSON(value);
757
+ break;
758
+ case "number":
759
+ if (typeof value !== "string")
760
+ throw new Error(`Invalid trait value type`);
761
+ valueField = UInt64.fromJSON(value);
762
+ break;
763
+ case "address":
764
+ if (typeof value !== "string")
765
+ throw new Error(`Invalid trait value type`);
766
+ valueField = PublicKey.fromBase58(value);
767
+ break;
768
+ case "map":
769
+ if (typeof value !== "object")
770
+ throw new Error(`Invalid trait value type`);
771
+ valueField = Metadata.fromOpenApiJSON({
772
+ json: value as unknown as {
773
+ name: string;
774
+ image: string;
775
+ description?: string;
776
+ traits: {
777
+ key: string;
778
+ type: string;
779
+ value: string | object;
780
+ isPrivate?: boolean;
781
+ }[];
782
+ },
783
+ });
784
+ break;
785
+ case "tree":
786
+ if (typeof value !== "object")
787
+ throw new Error(`Invalid trait value type`);
788
+ valueField = MetadataTree.fromJSON(
789
+ value as unknown as {
790
+ height: number;
791
+ root: string;
792
+ values: { key: string; value: string }[];
793
+ }
794
+ );
795
+ break;
796
+ default:
797
+ const plugin = metadata.plugins.find(
798
+ (plugin) => plugin.name === type
799
+ );
800
+ if (!plugin) throw new Error(`Unknown trait type`);
801
+ valueField = plugin.fromJSON(value);
802
+ }
803
+ metadata.addTrait({
804
+ key,
805
+ type,
806
+ value: valueField,
807
+ isPrivate: isPrivate ?? false,
808
+ });
809
+ }
810
+
811
+ return metadata;
812
+ }
590
813
  }
591
814
 
592
815
  /**
@@ -600,4 +823,6 @@ const MetadataFieldTypeValues = {
600
823
  field: { code: 5n, inputType: Field, storedType: Field }, // Field
601
824
  map: { code: 6n, inputType: Metadata, storedType: Metadata }, // Metadata
602
825
  tree: { code: 7n, inputType: MetadataTree, storedType: MetadataTree }, // MetadataTree
826
+ number: { code: 8n, inputType: UInt64, storedType: UInt64 }, // UInt64
827
+ address: { code: 9n, inputType: PublicKey, storedType: MinaAddress }, // MinaAddress
603
828
  } as const;
@@ -0,0 +1,30 @@
1
+ import { Metadata } from "./metadata.js";
2
+ import {
3
+ pinJSON,
4
+ serializeIndexedMap,
5
+ IndexedMapSerialized,
6
+ } from "@silvana-one/storage";
7
+ import { Field } from "o1js";
8
+
9
+ export async function pinMetadata(metadata: Metadata): Promise<{
10
+ name: string;
11
+ ipfsHash: string;
12
+ metadataRoot: Field;
13
+ privateMetadata: string;
14
+ serializedMap: IndexedMapSerialized;
15
+ }> {
16
+ const privateMetadata = JSON.stringify(metadata.toJSON(true), null, 2);
17
+ const ipfsHash: string | undefined = await pinJSON({
18
+ data: metadata.toJSON(false),
19
+ name: "nft-metadata",
20
+ });
21
+ if (!ipfsHash) throw new Error("Failed to pin metadata");
22
+
23
+ return {
24
+ name: metadata.name,
25
+ ipfsHash,
26
+ metadataRoot: metadata.map.root,
27
+ privateMetadata,
28
+ serializedMap: serializeIndexedMap(metadata.map),
29
+ };
30
+ }
@@ -94,7 +94,7 @@ export class MetadataTree {
94
94
  */
95
95
  static fromJSON(json: {
96
96
  height: number;
97
- root: string;
97
+ root?: string;
98
98
  values: { key: string; value: string }[];
99
99
  }): MetadataTree {
100
100
  const { height, values, root } = json;
@@ -102,7 +102,7 @@ export class MetadataTree {
102
102
  if (typeof height !== "number" || height < 1 || height > 254)
103
103
  throw new Error(`Invalid tree height`);
104
104
 
105
- if (!root || typeof root !== "string") throw new Error(`Invalid tree root`);
105
+ if (root && typeof root !== "string") throw new Error(`Invalid tree root`);
106
106
 
107
107
  if (!values || !Array.isArray(values))
108
108
  throw new Error(`Tree values are required`);
@@ -121,7 +121,8 @@ export class MetadataTree {
121
121
  }))
122
122
  );
123
123
 
124
- if (tree.root.toJSON() !== root) throw new Error("Invalid tree json");
124
+ if (root && tree.root.toJSON() !== root)
125
+ throw new Error("Invalid tree json");
125
126
 
126
127
  return tree;
127
128
  }
@@ -0,0 +1,44 @@
1
+ import { Field, Provable, UInt64, Gadgets, Struct } from "o1js";
2
+
3
+ export class MulDivResult extends Struct({
4
+ result: UInt64,
5
+ remainder: UInt64,
6
+ }) {}
7
+
8
+ class MulDivResultInternal extends Struct({
9
+ result: Field,
10
+ remainder: Field,
11
+ }) {}
12
+
13
+ export function mulDiv(params: {
14
+ value: UInt64;
15
+ multiplier: UInt64;
16
+ denominator: UInt64;
17
+ }): MulDivResult {
18
+ const { value, multiplier, denominator } = params;
19
+ denominator.equals(UInt64.zero).assertFalse("division by zero"); // should fail in case the denominator is zero
20
+ const fields = Provable.witness(MulDivResultInternal, () => {
21
+ const valueBigInt = value.toBigInt();
22
+ const multiplierBigInt = multiplier.toBigInt();
23
+ const denominatorBigInt = denominator.toBigInt();
24
+ // handle division by zero for first pass of the prover that can pass zero instead of the real value
25
+ if (denominatorBigInt === 0n) {
26
+ return { result: Field.from(0n), remainder: Field.from(0n) };
27
+ }
28
+ const result = (valueBigInt * multiplierBigInt) / denominatorBigInt;
29
+ const remainder =
30
+ valueBigInt * multiplierBigInt - result * denominatorBigInt;
31
+ return { result: Field.from(result), remainder: Field.from(remainder) };
32
+ });
33
+ Gadgets.rangeCheck64(fields.result);
34
+ Gadgets.rangeCheck64(fields.remainder);
35
+ fields.remainder.assertLessThan(denominator.value); // should fail in case the denominator is zero
36
+ fields.result
37
+ .mul(denominator.value)
38
+ .add(fields.remainder)
39
+ .assertEquals(value.value.mul(multiplier.value)); // should fail in case the denominator is zero
40
+ return {
41
+ result: UInt64.Unsafe.fromField(fields.result),
42
+ remainder: UInt64.Unsafe.fromField(fields.remainder),
43
+ };
44
+ }
@@ -0,0 +1 @@
1
+ export * from "./div.js";