@silvana-one/nft 0.3.0 → 1.0.1

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/README.md +12 -0
  2. package/dist/node/admin/advanced.d.ts +5 -1
  3. package/dist/node/contracts/admin.d.ts +100 -10
  4. package/dist/node/contracts/admin.js +130 -29
  5. package/dist/node/contracts/admin.js.map +1 -1
  6. package/dist/node/contracts/collection.d.ts +56 -35
  7. package/dist/node/contracts/collection.js +162 -71
  8. package/dist/node/contracts/collection.js.map +1 -1
  9. package/dist/node/contracts/nft.js +3 -0
  10. package/dist/node/contracts/nft.js.map +1 -1
  11. package/dist/node/contracts.d.ts +51 -33
  12. package/dist/node/index.cjs +447 -182
  13. package/dist/node/interfaces/collection.d.ts +5 -5
  14. package/dist/node/interfaces/events.d.ts +306 -16
  15. package/dist/node/interfaces/events.js +42 -4
  16. package/dist/node/interfaces/events.js.map +1 -1
  17. package/dist/node/interfaces/ownable.d.ts +7 -7
  18. package/dist/node/interfaces/ownable.js.map +1 -1
  19. package/dist/node/interfaces/pausable.d.ts +3 -3
  20. package/dist/node/interfaces/pausable.js.map +1 -1
  21. package/dist/node/interfaces/types.d.ts +182 -27
  22. package/dist/node/interfaces/types.js +120 -71
  23. package/dist/node/interfaces/types.js.map +1 -1
  24. package/dist/node/marketplace/auction.d.ts +7 -3
  25. package/dist/node/marketplace/auction.js +4 -4
  26. package/dist/node/marketplace/auction.js.map +1 -1
  27. package/dist/node/marketplace/bid.d.ts +5 -1
  28. package/dist/node/marketplace/bid.js +3 -5
  29. package/dist/node/marketplace/bid.js.map +1 -1
  30. package/dist/node/marketplace/nft-shares.d.ts +17 -5
  31. package/dist/node/marketplace/offer.d.ts +5 -1
  32. package/dist/node/util/div.js +10 -5
  33. package/dist/node/util/div.js.map +1 -1
  34. package/dist/node/vk.js +6 -6
  35. package/dist/node/vk.js.map +1 -1
  36. package/dist/node/zkprogram-example/game.d.ts +6 -17
  37. package/dist/node/zkprogram-example/update.d.ts +6 -17
  38. package/dist/tsconfig.node.tsbuildinfo +1 -1
  39. package/dist/tsconfig.web.tsbuildinfo +1 -1
  40. package/dist/web/admin/advanced.d.ts +5 -1
  41. package/dist/web/contracts/admin.d.ts +100 -10
  42. package/dist/web/contracts/admin.js +130 -29
  43. package/dist/web/contracts/admin.js.map +1 -1
  44. package/dist/web/contracts/collection.d.ts +56 -35
  45. package/dist/web/contracts/collection.js +162 -71
  46. package/dist/web/contracts/collection.js.map +1 -1
  47. package/dist/web/contracts/nft.js +3 -0
  48. package/dist/web/contracts/nft.js.map +1 -1
  49. package/dist/web/contracts.d.ts +51 -33
  50. package/dist/web/interfaces/collection.d.ts +5 -5
  51. package/dist/web/interfaces/events.d.ts +306 -16
  52. package/dist/web/interfaces/events.js +42 -4
  53. package/dist/web/interfaces/events.js.map +1 -1
  54. package/dist/web/interfaces/ownable.d.ts +7 -7
  55. package/dist/web/interfaces/ownable.js.map +1 -1
  56. package/dist/web/interfaces/pausable.d.ts +3 -3
  57. package/dist/web/interfaces/pausable.js.map +1 -1
  58. package/dist/web/interfaces/types.d.ts +182 -27
  59. package/dist/web/interfaces/types.js +120 -71
  60. package/dist/web/interfaces/types.js.map +1 -1
  61. package/dist/web/marketplace/auction.d.ts +7 -3
  62. package/dist/web/marketplace/auction.js +4 -4
  63. package/dist/web/marketplace/auction.js.map +1 -1
  64. package/dist/web/marketplace/bid.d.ts +5 -1
  65. package/dist/web/marketplace/bid.js +3 -5
  66. package/dist/web/marketplace/bid.js.map +1 -1
  67. package/dist/web/marketplace/nft-shares.d.ts +17 -5
  68. package/dist/web/marketplace/offer.d.ts +5 -1
  69. package/dist/web/util/div.js +10 -5
  70. package/dist/web/util/div.js.map +1 -1
  71. package/dist/web/vk.js +6 -6
  72. package/dist/web/vk.js.map +1 -1
  73. package/dist/web/zkprogram-example/game.d.ts +6 -17
  74. package/dist/web/zkprogram-example/update.d.ts +6 -17
  75. package/package.json +13 -13
  76. package/src/contracts/admin.ts +137 -24
  77. package/src/contracts/collection.ts +188 -96
  78. package/src/contracts/nft.ts +3 -0
  79. package/src/interfaces/collection.ts +11 -5
  80. package/src/interfaces/events.ts +47 -3
  81. package/src/interfaces/ownable.ts +1 -1
  82. package/src/interfaces/pausable.ts +1 -1
  83. package/src/interfaces/types.ts +152 -78
  84. package/src/marketplace/auction.ts +5 -4
  85. package/src/marketplace/bid.ts +4 -6
  86. package/src/util/div.ts +12 -5
  87. package/src/vk.ts +6 -6
@@ -1,5 +1,9 @@
1
1
  import { PublicKey, TokenContract } from "o1js";
2
- import { TransferParams, NFTStateStruct } from "./types.js";
2
+ import {
3
+ TransferBySignatureParams,
4
+ TransferByProofParams,
5
+ NFTStateStruct,
6
+ } from "./types.js";
3
7
  import { NFTOwnerContractConstructor } from "./owner.js";
4
8
  import { NFTApprovalContractConstructor } from "./approval.js";
5
9
  import { NFTUpdateContractConstructor } from "./update.js";
@@ -20,26 +24,28 @@ type NFTCollectionBase = TokenContract & {
20
24
  *
21
25
  * @param params - The transfer details.
22
26
  */
23
- transferByProof(params: TransferParams): Promise<void>;
27
+ transferByProof(params: TransferByProofParams): Promise<void>;
24
28
  /**
25
29
  * Transfers ownership of an NFT from contract without admin approval.
26
30
  *
27
31
  * @param params - The transfer details.
28
32
  */
29
- transferBySignature(params: TransferParams): Promise<void>;
33
+ transferBySignature(params: TransferBySignatureParams): Promise<void>;
30
34
 
31
35
  /**
32
36
  * Transfers ownership of an NFT from contract without admin approval using a proof.
33
37
  *
34
38
  * @param params - The transfer details.
35
39
  */
36
- approvedTransferByProof(params: TransferParams): Promise<void>;
40
+ adminApprovedTransferByProof(params: TransferByProofParams): Promise<void>;
37
41
  /**
38
42
  * Transfers ownership of an NFT from contract without admin approval.
39
43
  *
40
44
  * @param params - The transfer details.
41
45
  */
42
- approvedTransferBySignature(params: TransferParams): Promise<void>;
46
+ adminApprovedTransferBySignature(
47
+ params: TransferBySignatureParams
48
+ ): Promise<void>;
43
49
 
44
50
  /**
45
51
  * Returns the state of an NFT.
@@ -1,9 +1,10 @@
1
- import { PublicKey, Struct, UInt32, Field, Bool } from "o1js";
1
+ import { PublicKey, Struct, UInt32, Field, Bool, UInt64 } from "o1js";
2
2
  import { Storage } from "@silvana-one/storage";
3
3
  import { NFTStateStruct, UInt64Option } from "./types.js";
4
4
 
5
5
  export {
6
6
  MintEvent,
7
+ NFTUpdateEvent,
7
8
  UpdateEvent,
8
9
  TransferEvent,
9
10
  UpgradeVerificationKeyEvent,
@@ -11,6 +12,11 @@ export {
11
12
  LimitMintingEvent,
12
13
  PauseNFTEvent,
13
14
  ApproveEvent,
15
+ SetNameEvent,
16
+ SetBaseURLEvent,
17
+ SetRoyaltyFeeEvent,
18
+ SetTransferFeeEvent,
19
+ SetAdminEvent,
14
20
  };
15
21
 
16
22
  /**
@@ -21,6 +27,14 @@ class MintEvent extends Struct({
21
27
  initialState: NFTStateStruct,
22
28
  /** The public key address of the minted NFT. */
23
29
  address: PublicKey,
30
+ /** The token ID of the minted NFT. */
31
+ tokenId: Field,
32
+ /** The fee paid for the minting.
33
+ * This fee is controlled by the admin contract
34
+ * and is not checked by the Collection contract
35
+ * Please check the admin contract code before using this fee
36
+ */
37
+ fee: UInt64,
24
38
  }) {}
25
39
 
26
40
  /**
@@ -38,7 +52,7 @@ class UpdateEvent extends Struct({
38
52
  /** The approved address of the NFT after the update. */
39
53
  approved: PublicKey,
40
54
  /** The version number of the NFT state. */
41
- version: UInt32,
55
+ version: UInt64,
42
56
  /** Indicates whether the NFT is paused after the update. */
43
57
  isPaused: Bool,
44
58
  /** The hash of the verification key used for metadata proofs. */
@@ -95,7 +109,7 @@ class UpgradeVerificationKeyEvent extends Struct({
95
109
  verificationKeyHash: Field,
96
110
  /** The public key address of the NFT whose verification key is upgraded. */
97
111
  address: PublicKey,
98
- /** The version number of the NFT state after the upgrade. */
112
+ /** The tokenId of the upgraded contract */
99
113
  tokenId: Field,
100
114
  }) {}
101
115
 
@@ -113,3 +127,33 @@ class LimitMintingEvent extends Struct({
113
127
  /** Indicates whether minting is limited (`true`) or not (`false`). */
114
128
  mintingLimited: Bool,
115
129
  }) {}
130
+
131
+ class NFTUpdateEvent extends Struct({
132
+ /** The public key address of the NFT. */
133
+ address: PublicKey,
134
+ }) {}
135
+
136
+ class SetNameEvent extends Struct({
137
+ /** The updated name of the Collection. */
138
+ name: Field,
139
+ }) {}
140
+
141
+ class SetBaseURLEvent extends Struct({
142
+ /** The updated base URL of the Collection. */
143
+ baseURL: Field,
144
+ }) {}
145
+
146
+ class SetRoyaltyFeeEvent extends Struct({
147
+ /** The updated royalty fee of the Collection. */
148
+ royaltyFee: UInt32,
149
+ }) {}
150
+
151
+ class SetTransferFeeEvent extends Struct({
152
+ /** The updated transfer fee of the Collection. */
153
+ transferFee: UInt64,
154
+ }) {}
155
+
156
+ class SetAdminEvent extends Struct({
157
+ /** The updated admin contract of the Collection. */
158
+ admin: PublicKey,
159
+ }) {}
@@ -1,4 +1,4 @@
1
- import { PublicKey, SmartContract, Field, Struct, Bool } from "o1js";
1
+ import { PublicKey, SmartContract, Struct } from "o1js";
2
2
 
3
3
  /**
4
4
  * Interface representing ownable functionality for smart contracts.
@@ -1,4 +1,4 @@
1
- import { SmartContract, Field, Struct, Bool } from "o1js";
1
+ import { SmartContract, Struct, Bool } from "o1js";
2
2
  export { PausableContract, PauseEvent };
3
3
 
4
4
  /**
@@ -10,6 +10,7 @@ import {
10
10
  FeatureFlags,
11
11
  Option,
12
12
  Account,
13
+ Gadgets,
13
14
  } from "o1js";
14
15
  import { Storage } from "@silvana-one/storage";
15
16
  export {
@@ -24,7 +25,8 @@ export {
24
25
  NFTUpdateProof,
25
26
  NFTStateStruct,
26
27
  UInt64Option,
27
- TransferParams,
28
+ TransferBySignatureParams,
29
+ TransferByProofParams,
28
30
  MAX_ROYALTY_FEE,
29
31
  NFTTransactionContext,
30
32
  TransferExtendedParams,
@@ -109,7 +111,10 @@ class NFTImmutableState extends Struct({
109
111
  address: PublicKey, // readonly
110
112
  /** The token ID associated with the NFT (readonly). */
111
113
  tokenId: Field, // readonly
112
- /** The unique identifier of the NFT within the collection (readonly). */
114
+ /** The identifier of the NFT within the collection to be used off-chain(readonly).
115
+ * It can be set to any value chosen by the creator for the new NFTs
116
+ * and by default is set to 0. To uniquely identify the NFT, use the pair (NFT address, tokenId) or (collection address, NFT address)
117
+ */
113
118
  id: UInt64, // readonly
114
119
  }) {
115
120
  /**
@@ -193,7 +198,7 @@ class NFTState extends Struct({
193
198
  /** The off-chain storage information (e.g., IPFS hash). */
194
199
  storage: Storage,
195
200
  /** The version number of the NFT state. */
196
- version: UInt32,
201
+ version: UInt64,
197
202
  /** Indicates whether the NFT contract is currently paused. */
198
203
  isPaused: Bool,
199
204
  /** The hash of the verification key used for metadata proofs. */
@@ -223,6 +228,7 @@ class NFTState extends Struct({
223
228
  a.metadataVerificationKeyHash.assertEquals(b.metadataVerificationKeyHash);
224
229
  a.creator.assertEquals(b.creator);
225
230
  NFTTransactionContext.assertEqual(a.context, b.context);
231
+ a.oracleAddress.assertEquals(b.oracleAddress);
226
232
  }
227
233
 
228
234
  /**
@@ -282,14 +288,22 @@ class NFTData extends Struct({
282
288
  /** The approved address of the NFT. */
283
289
  approved: PublicKey,
284
290
  /** The version number of the NFT state. */
285
- version: UInt32,
291
+ version: UInt64,
286
292
  /** The unique identifier of the NFT within the collection. */
287
293
  id: UInt64,
288
- /** Determines whether the NFT's ownership can be changed via a zero-knowledge proof (readonly). */
294
+ /** Determines whether the NFT's ownership can be changed via a zero-knowledge proof (readonly).
295
+ *
296
+ * It can be used only with update() and updateWithOracle() methods and
297
+ * in this case overrides both canTransfer and canApprove flags used in the transfer methods
298
+ */
289
299
  canChangeOwnerByProof: Bool, // readonly
290
- /** Specifies if the NFT's ownership can be transferred (readonly). */
300
+ /** Specifies if the NFT's ownership can be transferred (readonly). Applies
301
+ * to transfer methods and can be bypassed by the update() and updateWithOracle() methods
302
+ */
291
303
  canTransfer: Bool, // readonly
292
- /** Specifies if the NFT's approved address can be changed (readonly). */
304
+ /** Specifies if the NFT's approved address can be changed (readonly). Transfer methods reset approved address to PublicKey.empty()
305
+ * on transfer independently from the canApprove flag value
306
+ */
293
307
  canApprove: Bool, // readonly
294
308
  /** Indicates whether the NFT's metadata can be updated (readonly). */
295
309
  canChangeMetadata: Bool, // readonly
@@ -314,7 +328,7 @@ class NFTData extends Struct({
314
328
  static new(params: {
315
329
  owner: string | PublicKey;
316
330
  approved?: string | PublicKey;
317
- version?: number;
331
+ version?: number | bigint | string;
318
332
  id?: bigint | string;
319
333
  canChangeOwnerByProof?: boolean;
320
334
  canTransfer?: boolean;
@@ -350,7 +364,7 @@ class NFTData extends Struct({
350
364
  ? PublicKey.fromBase58(approved)
351
365
  : approved
352
366
  : PublicKey.empty(),
353
- version: UInt32.from(version ?? 0),
367
+ version: UInt64.from(BigInt(version ?? 0)),
354
368
  id: UInt64.from(BigInt(id ?? 0)),
355
369
  canChangeOwnerByProof: Bool(canChangeOwnerByProof ?? false),
356
370
  canTransfer: Bool(canTransfer ?? true),
@@ -374,14 +388,10 @@ class NFTData extends Struct({
374
388
  * @returns The packed Field representation of the NFTData.
375
389
  */
376
390
  pack(): NFTDataPacked {
377
- const id = this.id.value.toBits(64);
378
- const version = this.version.value.toBits(32);
379
391
  return new NFTDataPacked({
380
392
  ownerX: this.owner.x,
381
393
  approvedX: this.approved.x,
382
394
  data: Field.fromBits([
383
- ...id,
384
- ...version,
385
395
  this.canChangeOwnerByProof,
386
396
  this.canTransfer,
387
397
  this.canApprove,
@@ -394,7 +404,9 @@ class NFTData extends Struct({
394
404
  this.requireOwnerAuthorizationToUpgrade,
395
405
  this.owner.isOdd,
396
406
  this.approved.isOdd,
397
- ]),
407
+ ])
408
+ .add(Field(this.id.value).mul(Field(2 ** 12)))
409
+ .add(Field(this.version.value).mul(Field(2 ** (12 + 64)))),
398
410
  });
399
411
  }
400
412
 
@@ -404,45 +416,70 @@ class NFTData extends Struct({
404
416
  * @returns A new NFTData instance.
405
417
  */
406
418
  static unpack(packed: NFTDataPacked): NFTData {
407
- const bits = packed.data.toBits(64 + 32 + 12);
408
- const id = UInt64.Unsafe.fromField(Field.fromBits(bits.slice(0, 64)));
409
- const version = UInt32.Unsafe.fromField(
410
- Field.fromBits(bits.slice(64, 64 + 32))
411
- );
419
+ const unpacked = Provable.witness(NFTData, () => {
420
+ const bits = Gadgets.and(packed.data, Field(0xfffn), 12 + 64 + 64).toBits(
421
+ 12
422
+ );
423
+ const idField = Gadgets.and(
424
+ packed.data,
425
+ Field(0xffffffffffffffff000n),
426
+ 12 + 64 + 64
427
+ );
428
+ const idBits = idField.toBits(64 + 12);
429
+ // the next line relies on the constants 0xffffffffffffffff000n and 12 + 64 + 64 above
430
+ const id = UInt64.Unsafe.fromField(
431
+ Field.fromBits(idBits.slice(12, 64 + 12))
432
+ );
433
+ id.value.mul(Field(2 ** 12)).assertEquals(idField);
412
434
 
413
- const canChangeOwnerByProof = bits[64 + 32 + 0];
414
- const canTransfer = bits[64 + 32 + 1];
415
- const canApprove = bits[64 + 32 + 2];
416
- const canChangeMetadata = bits[64 + 32 + 3];
417
- const canChangeStorage = bits[64 + 32 + 4];
418
- const canChangeName = bits[64 + 32 + 5];
419
- const canChangeMetadataVerificationKeyHash = bits[64 + 32 + 6];
420
- const canPause = bits[64 + 32 + 7];
421
- const isPaused = bits[64 + 32 + 8];
422
- const requireOwnerAuthorizationToUpgrade = bits[64 + 32 + 9];
423
- const ownerIsOdd = bits[64 + 32 + 10];
424
- const approvedIsOdd = bits[64 + 32 + 11];
425
- const owner = PublicKey.from({ x: packed.ownerX, isOdd: ownerIsOdd });
426
- const approved = PublicKey.from({
427
- x: packed.approvedX,
428
- isOdd: approvedIsOdd,
429
- });
430
- return new NFTData({
431
- owner,
432
- approved,
433
- id,
434
- version,
435
- canChangeOwnerByProof,
436
- canTransfer,
437
- canApprove,
438
- canChangeMetadata,
439
- canChangeStorage,
440
- canChangeName,
441
- canChangeMetadataVerificationKeyHash,
442
- canPause,
443
- isPaused,
444
- requireOwnerAuthorizationToUpgrade,
435
+ const versionField = Gadgets.and(
436
+ packed.data,
437
+ Field(0xffffffffffffffff0000000000000000000n),
438
+ 64 + 64 + 12
439
+ );
440
+ const versionBits = versionField.toBits(12 + 64 + 64);
441
+ // the next line relies on the constants 0xffffffffffffffff0000000000000000000n and 12 + 64 + 64 above
442
+ const version = UInt64.Unsafe.fromField(
443
+ Field.fromBits(versionBits.slice(12 + 64, 12 + 64 + 64))
444
+ );
445
+ version.value.mul(Field(2 ** (12 + 64))).assertEquals(versionField);
446
+
447
+ const canChangeOwnerByProof = bits[0];
448
+ const canTransfer = bits[1];
449
+ const canApprove = bits[2];
450
+ const canChangeMetadata = bits[3];
451
+ const canChangeStorage = bits[4];
452
+ const canChangeName = bits[5];
453
+ const canChangeMetadataVerificationKeyHash = bits[6];
454
+ const canPause = bits[7];
455
+ const isPaused = bits[8];
456
+ const requireOwnerAuthorizationToUpgrade = bits[9];
457
+ const ownerIsOdd = bits[10];
458
+ const approvedIsOdd = bits[11];
459
+ const owner = PublicKey.from({ x: packed.ownerX, isOdd: ownerIsOdd });
460
+ const approved = PublicKey.from({
461
+ x: packed.approvedX,
462
+ isOdd: approvedIsOdd,
463
+ });
464
+ return new NFTData({
465
+ owner,
466
+ approved,
467
+ id,
468
+ version,
469
+ canChangeOwnerByProof,
470
+ canTransfer,
471
+ canApprove,
472
+ canChangeMetadata,
473
+ canChangeStorage,
474
+ canChangeName,
475
+ canChangeMetadataVerificationKeyHash,
476
+ canPause,
477
+ isPaused,
478
+ requireOwnerAuthorizationToUpgrade,
479
+ });
445
480
  });
481
+ NFTDataPacked.assertEqual(unpacked.pack(), packed);
482
+ return unpacked;
446
483
  }
447
484
  }
448
485
 
@@ -462,6 +499,8 @@ class CollectionData extends Struct({
462
499
  mintingIsLimited: Bool,
463
500
  /** Indicates whether the collection is currently paused. */
464
501
  isPaused: Bool,
502
+ /** The public key part (isOdd) of the pending creator. The x field is written to the contract state as pendingCreatorX */
503
+ pendingCreatorIsOdd: Bool,
465
504
  }) {
466
505
  /**
467
506
  * Creates a new CollectionData instance with specified parameters.
@@ -488,6 +527,7 @@ class CollectionData extends Struct({
488
527
  requireTransferApproval: Bool(requireTransferApproval ?? false),
489
528
  mintingIsLimited: Bool(mintingIsLimited ?? false),
490
529
  isPaused: Bool(isPaused ?? false),
530
+ pendingCreatorIsOdd: Bool(PublicKey.empty().isOdd),
491
531
  });
492
532
  }
493
533
 
@@ -500,9 +540,10 @@ class CollectionData extends Struct({
500
540
  this.isPaused,
501
541
  this.requireTransferApproval,
502
542
  this.mintingIsLimited,
503
- ...this.royaltyFee.value.toBits(32),
504
- ...this.transferFee.value.toBits(64),
505
- ]);
543
+ this.pendingCreatorIsOdd,
544
+ ])
545
+ .add(Field(this.royaltyFee.value).mul(Field(2 ** 4)))
546
+ .add(Field(this.transferFee.value).mul(Field(2 ** (4 + 32))));
506
547
  }
507
548
 
508
549
  /**
@@ -511,36 +552,55 @@ class CollectionData extends Struct({
511
552
  * @returns A new CollectionData instance.
512
553
  */
513
554
  static unpack(packed: Field) {
514
- const bits = packed.toBits(3 + 32 + 64);
515
- const royaltyFee = UInt32.Unsafe.fromField(
516
- Field.fromBits(bits.slice(3, 3 + 32))
517
- );
518
- const transferFee = UInt64.Unsafe.fromField(
519
- Field.fromBits(bits.slice(3 + 32, 3 + 32 + 64))
520
- );
555
+ const unpacked = Provable.witness(CollectionData, () => {
556
+ const bits = Gadgets.and(packed, Field(0xfn), 4 + 32 + 64).toBits(4);
521
557
 
522
- return new CollectionData({
523
- isPaused: bits[0],
524
- requireTransferApproval: bits[1],
525
- mintingIsLimited: bits[2],
526
- royaltyFee,
527
- transferFee,
558
+ const royaltyFeeField = Gadgets.and(
559
+ packed,
560
+ Field(0xffffffff0n),
561
+ 4 + 32 + 64
562
+ );
563
+
564
+ const royaltyFeeBits = royaltyFeeField.toBits(4 + 32);
565
+ // The next line relies on the constants 0xffffffff0n and 4 + 32 + 64 above
566
+ const royaltyFee = UInt32.Unsafe.fromField(
567
+ Field.fromBits(royaltyFeeBits.slice(4, 4 + 32))
568
+ );
569
+ royaltyFee.value.mul(Field(2 ** 4)).assertEquals(royaltyFeeField);
570
+
571
+ const transferFeeField = Gadgets.and(
572
+ packed,
573
+ Field(0xffffffffffffffff000000000n),
574
+ 4 + 32 + 64
575
+ );
576
+ const transferFeeBits = transferFeeField.toBits(4 + 32 + 64);
577
+ // The next line relies on the constants 0xffffffffffffffff000000000n and 4 + 32 + 64 above
578
+ const transferFee = UInt64.Unsafe.fromField(
579
+ Field.fromBits(transferFeeBits.slice(4 + 32, 4 + 32 + 64))
580
+ );
581
+ transferFee.value
582
+ .mul(Field(2 ** (4 + 32)))
583
+ .assertEquals(transferFeeField);
584
+
585
+ return new CollectionData({
586
+ isPaused: bits[0],
587
+ requireTransferApproval: bits[1],
588
+ mintingIsLimited: bits[2],
589
+ pendingCreatorIsOdd: bits[3],
590
+ royaltyFee,
591
+ transferFee,
592
+ });
528
593
  });
594
+ unpacked.pack().assertEquals(packed);
595
+ return unpacked;
529
596
  }
530
597
 
531
598
  static isPaused(packed: Field) {
532
- return packed.toBits(3 + 32 + 64)[0];
599
+ return packed.toBits(4 + 32 + 64)[0];
533
600
  }
534
601
 
535
602
  static requireTransferApproval(packed: Field) {
536
- return packed.toBits(3 + 32 + 64)[1];
537
- }
538
-
539
- static mintingIsLimited(packed: Field) {
540
- const bits = packed.toBits(3 + 32 + 64);
541
- const isPaused = bits[0];
542
- const mintingIsLimited = bits[2];
543
- return isPaused.or(mintingIsLimited);
603
+ return packed.toBits(4 + 32 + 64)[1];
544
604
  }
545
605
  }
546
606
 
@@ -586,9 +646,23 @@ class MintRequest extends Struct({
586
646
  }) {}
587
647
 
588
648
  /**
589
- * Represents the parameters required for transferring an NFT.
649
+ * Represents the parameters required for transferring an NFT using a signature.
650
+ */
651
+ class TransferBySignatureParams extends Struct({
652
+ /** The address of the NFT contract. */
653
+ address: PublicKey,
654
+ /** The receiver's public key. */
655
+ to: PublicKey,
656
+ /** Optional price for the transfer. */
657
+ price: UInt64Option,
658
+ /** Custom value that can be interpreted by the owner or approved contract. */
659
+ context: NFTTransactionContext,
660
+ }) {}
661
+
662
+ /**
663
+ * Represents the parameters required for transferring an NFT using a proof.
590
664
  */
591
- class TransferParams extends Struct({
665
+ class TransferByProofParams extends Struct({
592
666
  /** The address of the NFT contract. */
593
667
  address: PublicKey,
594
668
  /** The sender's public key. */
@@ -23,7 +23,8 @@ import {
23
23
  NFTCollectionBase,
24
24
  NFTTransactionContext,
25
25
  TransferExtendedParams,
26
- TransferParams,
26
+ TransferBySignatureParams,
27
+ TransferByProofParams,
27
28
  } from "../interfaces/index.js";
28
29
  import { mulDiv } from "../util/index.js";
29
30
 
@@ -231,7 +232,7 @@ export function AuctionFactory(params: {
231
232
 
232
233
  events = {
233
234
  bid: AuctionBidEvent,
234
- settleAuction: TransferParams,
235
+ settleAuction: TransferByProofParams,
235
236
  canTransfer: TransferEvent,
236
237
  settlePayment: UInt64,
237
238
  settleAuctioneerPayment: UInt64,
@@ -337,7 +338,7 @@ export function AuctionFactory(params: {
337
338
  "Bidder does not have enough balance"
338
339
  );
339
340
  const collection = this.getCollectionContract(auction.collection);
340
- const transferParams = new TransferParams({
341
+ const transferParams = new TransferByProofParams({
341
342
  address: nftAddress,
342
343
  from: this.address,
343
344
  to: auction.bidder,
@@ -366,7 +367,7 @@ export function AuctionFactory(params: {
366
367
  const nftAddress = auction.nft;
367
368
 
368
369
  const collection = this.getCollectionContract(auction.collection);
369
- const transferParams = new TransferParams({
370
+ const transferParams = new TransferByProofParams({
370
371
  address: nftAddress,
371
372
  from: this.address,
372
373
  to: auction.owner,
@@ -25,7 +25,7 @@ import {
25
25
  import {
26
26
  NFTCollectionBase,
27
27
  NFTCollectionContractConstructor,
28
- TransferParams,
28
+ TransferBySignatureParams,
29
29
  UInt64Option,
30
30
  NFTTransactionContext,
31
31
  } from "../interfaces/index.js";
@@ -178,9 +178,8 @@ export function BidFactory(params: {
178
178
  const Collection = collectionContract();
179
179
  const collection = new Collection(nftAddress.collection);
180
180
  await collection.transferBySignature(
181
- new TransferParams({
181
+ new TransferBySignatureParams({
182
182
  address: nftAddress.nft,
183
- from: PublicKey.empty(),
184
183
  to: buyer,
185
184
  price: UInt64Option.fromValue(price),
186
185
  context: new NFTTransactionContext({
@@ -195,10 +194,9 @@ export function BidFactory(params: {
195
194
  const buyer = this.buyer.getAndRequireEquals();
196
195
  const Collection = collectionContract();
197
196
  const collection = new Collection(nftAddress.collection);
198
- await collection.approvedTransferBySignature(
199
- new TransferParams({
197
+ await collection.adminApprovedTransferBySignature(
198
+ new TransferBySignatureParams({
200
199
  address: nftAddress.nft,
201
- from: PublicKey.empty(),
202
200
  to: buyer,
203
201
  price: UInt64Option.fromValue(price),
204
202
  context: new NFTTransactionContext({
package/src/util/div.ts CHANGED
@@ -30,15 +30,22 @@ export function mulDiv(params: {
30
30
  valueBigInt * multiplierBigInt - result * denominatorBigInt;
31
31
  return { result: Field.from(result), remainder: Field.from(remainder) };
32
32
  });
33
+ // We check that the result and remainder are in the correct range using Gadgets.rangeCheck64 before using Unsafe methods
34
+ // The next four lines should always be used together and cannot be separated
33
35
  Gadgets.rangeCheck64(fields.result);
36
+ const result = UInt64.Unsafe.fromField(fields.result);
34
37
  Gadgets.rangeCheck64(fields.remainder);
35
- fields.remainder.assertLessThan(denominator.value); // should fail in case the denominator is zero
36
- fields.result
38
+ const remainder = UInt64.Unsafe.fromField(fields.remainder);
39
+
40
+ remainder.assertLessThan(denominator); // should fail in case the denominator is zero
41
+
42
+ // We use the Field representations of the values to avoid overflows
43
+ result.value
37
44
  .mul(denominator.value)
38
- .add(fields.remainder)
45
+ .add(remainder.value)
39
46
  .assertEquals(value.value.mul(multiplier.value)); // should fail in case the denominator is zero
40
47
  return {
41
- result: UInt64.Unsafe.fromField(fields.result),
42
- remainder: UInt64.Unsafe.fromField(fields.remainder),
48
+ result,
49
+ remainder,
43
50
  };
44
51
  }
package/src/vk.ts CHANGED
@@ -42,21 +42,21 @@ export const nftVerificationKeys: {
42
42
  };
43
43
  } = {
44
44
  devnet: {
45
- o1js: "2.2.0",
45
+ o1js: "2.3.0",
46
46
  vk: {
47
47
  NFT: {
48
- hash: "11840382732064931640435917684245815329181717734233274982467687213333743677377",
49
- data: "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",
48
+ hash: "9783798445384315170525620826037823720996093317060506623212107011216804106668",
49
+ data: "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",
50
50
  type: "nft",
51
51
  },
52
52
  },
53
53
  },
54
54
  mainnet: {
55
- o1js: "2.2.0",
55
+ o1js: "2.3.0",
56
56
  vk: {
57
57
  NFT: {
58
- hash: "11510318025893859422482952918693907155880273225165466507725691048640041393360",
59
- data: "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",
58
+ hash: "22175359608429605539570936386638550990144108869927626059283446793366639887120",
59
+ data: "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",
60
60
  type: "nft",
61
61
  },
62
62
  },