@silvana-one/nft 0.1.0

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 (236) hide show
  1. package/README.md +1400 -0
  2. package/dist/node/admin/advanced.d.ts +469 -0
  3. package/dist/node/admin/advanced.js +525 -0
  4. package/dist/node/admin/advanced.js.map +1 -0
  5. package/dist/node/admin/index.d.ts +1 -0
  6. package/dist/node/admin/index.js +2 -0
  7. package/dist/node/admin/index.js.map +1 -0
  8. package/dist/node/contracts/admin.d.ts +140 -0
  9. package/dist/node/contracts/admin.js +336 -0
  10. package/dist/node/contracts/admin.js.map +1 -0
  11. package/dist/node/contracts/collection.d.ts +551 -0
  12. package/dist/node/contracts/collection.js +1049 -0
  13. package/dist/node/contracts/collection.js.map +1 -0
  14. package/dist/node/contracts/index.d.ts +3 -0
  15. package/dist/node/contracts/index.js +4 -0
  16. package/dist/node/contracts/index.js.map +1 -0
  17. package/dist/node/contracts/nft.d.ts +76 -0
  18. package/dist/node/contracts/nft.js +329 -0
  19. package/dist/node/contracts/nft.js.map +1 -0
  20. package/dist/node/contracts.d.ts +709 -0
  21. package/dist/node/contracts.js +61 -0
  22. package/dist/node/contracts.js.map +1 -0
  23. package/dist/node/index.cjs +5032 -0
  24. package/dist/node/index.d.ts +8 -0
  25. package/dist/node/index.js +9 -0
  26. package/dist/node/index.js.map +1 -0
  27. package/dist/node/interfaces/admin.d.ts +102 -0
  28. package/dist/node/interfaces/admin.js +2 -0
  29. package/dist/node/interfaces/admin.js.map +1 -0
  30. package/dist/node/interfaces/approval.d.ts +57 -0
  31. package/dist/node/interfaces/approval.js +62 -0
  32. package/dist/node/interfaces/approval.js.map +1 -0
  33. package/dist/node/interfaces/collection.d.ts +57 -0
  34. package/dist/node/interfaces/collection.js +2 -0
  35. package/dist/node/interfaces/collection.js.map +1 -0
  36. package/dist/node/interfaces/encoding.d.ts +24 -0
  37. package/dist/node/interfaces/encoding.js +32 -0
  38. package/dist/node/interfaces/encoding.js.map +1 -0
  39. package/dist/node/interfaces/events.d.ts +833 -0
  40. package/dist/node/interfaces/events.js +106 -0
  41. package/dist/node/interfaces/events.js.map +1 -0
  42. package/dist/node/interfaces/index.d.ts +10 -0
  43. package/dist/node/interfaces/index.js +11 -0
  44. package/dist/node/interfaces/index.js.map +1 -0
  45. package/dist/node/interfaces/ownable.d.ts +94 -0
  46. package/dist/node/interfaces/ownable.js +12 -0
  47. package/dist/node/interfaces/ownable.js.map +1 -0
  48. package/dist/node/interfaces/owner.d.ts +61 -0
  49. package/dist/node/interfaces/owner.js +101 -0
  50. package/dist/node/interfaces/owner.js.map +1 -0
  51. package/dist/node/interfaces/pausable.d.ts +74 -0
  52. package/dist/node/interfaces/pausable.js +14 -0
  53. package/dist/node/interfaces/pausable.js.map +1 -0
  54. package/dist/node/interfaces/types.d.ts +2297 -0
  55. package/dist/node/interfaces/types.js +507 -0
  56. package/dist/node/interfaces/types.js.map +1 -0
  57. package/dist/node/interfaces/update.d.ts +53 -0
  58. package/dist/node/interfaces/update.js +58 -0
  59. package/dist/node/interfaces/update.js.map +1 -0
  60. package/dist/node/marketplace/auction.d.ts +775 -0
  61. package/dist/node/marketplace/auction.js +430 -0
  62. package/dist/node/marketplace/auction.js.map +1 -0
  63. package/dist/node/marketplace/bid.d.ts +254 -0
  64. package/dist/node/marketplace/bid.js +260 -0
  65. package/dist/node/marketplace/bid.js.map +1 -0
  66. package/dist/node/marketplace/index.d.ts +5 -0
  67. package/dist/node/marketplace/index.js +6 -0
  68. package/dist/node/marketplace/index.js.map +1 -0
  69. package/dist/node/marketplace/nft-shares.d.ts +1083 -0
  70. package/dist/node/marketplace/nft-shares.js +398 -0
  71. package/dist/node/marketplace/nft-shares.js.map +1 -0
  72. package/dist/node/marketplace/offer.d.ts +192 -0
  73. package/dist/node/marketplace/offer.js +132 -0
  74. package/dist/node/marketplace/offer.js.map +1 -0
  75. package/dist/node/marketplace/types.d.ts +374 -0
  76. package/dist/node/marketplace/types.js +33 -0
  77. package/dist/node/marketplace/types.js.map +1 -0
  78. package/dist/node/metadata/index.d.ts +3 -0
  79. package/dist/node/metadata/index.js +4 -0
  80. package/dist/node/metadata/index.js.map +1 -0
  81. package/dist/node/metadata/metadata.d.ts +337 -0
  82. package/dist/node/metadata/metadata.js +439 -0
  83. package/dist/node/metadata/metadata.js.map +1 -0
  84. package/dist/node/metadata/text.d.ts +44 -0
  85. package/dist/node/metadata/text.js +42 -0
  86. package/dist/node/metadata/text.js.map +1 -0
  87. package/dist/node/metadata/tree.d.ts +75 -0
  88. package/dist/node/metadata/tree.js +85 -0
  89. package/dist/node/metadata/tree.js.map +1 -0
  90. package/dist/node/vk.d.ts +42 -0
  91. package/dist/node/vk.js +45 -0
  92. package/dist/node/vk.js.map +1 -0
  93. package/dist/node/zkprogram-example/game.d.ts +76 -0
  94. package/dist/node/zkprogram-example/game.js +108 -0
  95. package/dist/node/zkprogram-example/game.js.map +1 -0
  96. package/dist/node/zkprogram-example/index.d.ts +2 -0
  97. package/dist/node/zkprogram-example/index.js +3 -0
  98. package/dist/node/zkprogram-example/index.js.map +1 -0
  99. package/dist/node/zkprogram-example/update.d.ts +76 -0
  100. package/dist/node/zkprogram-example/update.js +85 -0
  101. package/dist/node/zkprogram-example/update.js.map +1 -0
  102. package/dist/tsconfig.tsbuildinfo +1 -0
  103. package/dist/tsconfig.web.tsbuildinfo +1 -0
  104. package/dist/web/admin/advanced.d.ts +469 -0
  105. package/dist/web/admin/advanced.js +525 -0
  106. package/dist/web/admin/advanced.js.map +1 -0
  107. package/dist/web/admin/index.d.ts +1 -0
  108. package/dist/web/admin/index.js +2 -0
  109. package/dist/web/admin/index.js.map +1 -0
  110. package/dist/web/contracts/admin.d.ts +140 -0
  111. package/dist/web/contracts/admin.js +336 -0
  112. package/dist/web/contracts/admin.js.map +1 -0
  113. package/dist/web/contracts/collection.d.ts +551 -0
  114. package/dist/web/contracts/collection.js +1049 -0
  115. package/dist/web/contracts/collection.js.map +1 -0
  116. package/dist/web/contracts/index.d.ts +3 -0
  117. package/dist/web/contracts/index.js +4 -0
  118. package/dist/web/contracts/index.js.map +1 -0
  119. package/dist/web/contracts/nft.d.ts +76 -0
  120. package/dist/web/contracts/nft.js +329 -0
  121. package/dist/web/contracts/nft.js.map +1 -0
  122. package/dist/web/contracts.d.ts +709 -0
  123. package/dist/web/contracts.js +61 -0
  124. package/dist/web/contracts.js.map +1 -0
  125. package/dist/web/index.d.ts +8 -0
  126. package/dist/web/index.js +9 -0
  127. package/dist/web/index.js.map +1 -0
  128. package/dist/web/interfaces/admin.d.ts +102 -0
  129. package/dist/web/interfaces/admin.js +2 -0
  130. package/dist/web/interfaces/admin.js.map +1 -0
  131. package/dist/web/interfaces/approval.d.ts +57 -0
  132. package/dist/web/interfaces/approval.js +62 -0
  133. package/dist/web/interfaces/approval.js.map +1 -0
  134. package/dist/web/interfaces/collection.d.ts +57 -0
  135. package/dist/web/interfaces/collection.js +2 -0
  136. package/dist/web/interfaces/collection.js.map +1 -0
  137. package/dist/web/interfaces/encoding.d.ts +24 -0
  138. package/dist/web/interfaces/encoding.js +32 -0
  139. package/dist/web/interfaces/encoding.js.map +1 -0
  140. package/dist/web/interfaces/events.d.ts +833 -0
  141. package/dist/web/interfaces/events.js +106 -0
  142. package/dist/web/interfaces/events.js.map +1 -0
  143. package/dist/web/interfaces/index.d.ts +10 -0
  144. package/dist/web/interfaces/index.js +11 -0
  145. package/dist/web/interfaces/index.js.map +1 -0
  146. package/dist/web/interfaces/ownable.d.ts +94 -0
  147. package/dist/web/interfaces/ownable.js +12 -0
  148. package/dist/web/interfaces/ownable.js.map +1 -0
  149. package/dist/web/interfaces/owner.d.ts +61 -0
  150. package/dist/web/interfaces/owner.js +101 -0
  151. package/dist/web/interfaces/owner.js.map +1 -0
  152. package/dist/web/interfaces/pausable.d.ts +74 -0
  153. package/dist/web/interfaces/pausable.js +14 -0
  154. package/dist/web/interfaces/pausable.js.map +1 -0
  155. package/dist/web/interfaces/types.d.ts +2297 -0
  156. package/dist/web/interfaces/types.js +507 -0
  157. package/dist/web/interfaces/types.js.map +1 -0
  158. package/dist/web/interfaces/update.d.ts +53 -0
  159. package/dist/web/interfaces/update.js +58 -0
  160. package/dist/web/interfaces/update.js.map +1 -0
  161. package/dist/web/marketplace/auction.d.ts +775 -0
  162. package/dist/web/marketplace/auction.js +430 -0
  163. package/dist/web/marketplace/auction.js.map +1 -0
  164. package/dist/web/marketplace/bid.d.ts +254 -0
  165. package/dist/web/marketplace/bid.js +260 -0
  166. package/dist/web/marketplace/bid.js.map +1 -0
  167. package/dist/web/marketplace/index.d.ts +5 -0
  168. package/dist/web/marketplace/index.js +6 -0
  169. package/dist/web/marketplace/index.js.map +1 -0
  170. package/dist/web/marketplace/nft-shares.d.ts +1083 -0
  171. package/dist/web/marketplace/nft-shares.js +398 -0
  172. package/dist/web/marketplace/nft-shares.js.map +1 -0
  173. package/dist/web/marketplace/offer.d.ts +192 -0
  174. package/dist/web/marketplace/offer.js +132 -0
  175. package/dist/web/marketplace/offer.js.map +1 -0
  176. package/dist/web/marketplace/types.d.ts +374 -0
  177. package/dist/web/marketplace/types.js +33 -0
  178. package/dist/web/marketplace/types.js.map +1 -0
  179. package/dist/web/metadata/index.d.ts +3 -0
  180. package/dist/web/metadata/index.js +4 -0
  181. package/dist/web/metadata/index.js.map +1 -0
  182. package/dist/web/metadata/metadata.d.ts +337 -0
  183. package/dist/web/metadata/metadata.js +439 -0
  184. package/dist/web/metadata/metadata.js.map +1 -0
  185. package/dist/web/metadata/text.d.ts +44 -0
  186. package/dist/web/metadata/text.js +42 -0
  187. package/dist/web/metadata/text.js.map +1 -0
  188. package/dist/web/metadata/tree.d.ts +75 -0
  189. package/dist/web/metadata/tree.js +85 -0
  190. package/dist/web/metadata/tree.js.map +1 -0
  191. package/dist/web/vk.d.ts +42 -0
  192. package/dist/web/vk.js +45 -0
  193. package/dist/web/vk.js.map +1 -0
  194. package/dist/web/zkprogram-example/game.d.ts +76 -0
  195. package/dist/web/zkprogram-example/game.js +108 -0
  196. package/dist/web/zkprogram-example/game.js.map +1 -0
  197. package/dist/web/zkprogram-example/index.d.ts +2 -0
  198. package/dist/web/zkprogram-example/index.js +3 -0
  199. package/dist/web/zkprogram-example/index.js.map +1 -0
  200. package/dist/web/zkprogram-example/update.d.ts +76 -0
  201. package/dist/web/zkprogram-example/update.js +85 -0
  202. package/dist/web/zkprogram-example/update.js.map +1 -0
  203. package/package.json +65 -0
  204. package/src/admin/advanced.ts +601 -0
  205. package/src/admin/index.ts +1 -0
  206. package/src/contracts/admin.ts +301 -0
  207. package/src/contracts/collection.ts +1172 -0
  208. package/src/contracts/index.ts +3 -0
  209. package/src/contracts/nft.ts +344 -0
  210. package/src/contracts.ts +107 -0
  211. package/src/index.ts +8 -0
  212. package/src/interfaces/admin.ts +127 -0
  213. package/src/interfaces/approval.ts +99 -0
  214. package/src/interfaces/collection.ts +68 -0
  215. package/src/interfaces/encoding.ts +32 -0
  216. package/src/interfaces/events.ts +115 -0
  217. package/src/interfaces/index.ts +10 -0
  218. package/src/interfaces/ownable.ts +32 -0
  219. package/src/interfaces/owner.ts +143 -0
  220. package/src/interfaces/pausable.ts +41 -0
  221. package/src/interfaces/types.ts +623 -0
  222. package/src/interfaces/update.ts +104 -0
  223. package/src/marketplace/auction.ts +527 -0
  224. package/src/marketplace/bid.ts +294 -0
  225. package/src/marketplace/index.ts +5 -0
  226. package/src/marketplace/nft-shares.ts +388 -0
  227. package/src/marketplace/offer.ts +153 -0
  228. package/src/marketplace/types.ts +33 -0
  229. package/src/metadata/index.ts +3 -0
  230. package/src/metadata/metadata.ts +603 -0
  231. package/src/metadata/text.ts +60 -0
  232. package/src/metadata/tree.ts +128 -0
  233. package/src/vk.ts +64 -0
  234. package/src/zkprogram-example/game.ts +136 -0
  235. package/src/zkprogram-example/index.ts +2 -0
  236. package/src/zkprogram-example/update.ts +98 -0
@@ -0,0 +1,104 @@
1
+ import {
2
+ AccountUpdate,
3
+ Bool,
4
+ method,
5
+ PublicKey,
6
+ SmartContract,
7
+ state,
8
+ State,
9
+ Permissions,
10
+ DeployArgs,
11
+ } from "o1js";
12
+ import { NFTCollectionContractConstructor } from "./collection.js";
13
+ import { NFTState } from "./types.js";
14
+ export {
15
+ NFTUpdateBase,
16
+ NFTUpdateContractConstructor,
17
+ NFTStandardUpdate,
18
+ NFTUpdateDeployProps,
19
+ DefineUpdateFactory,
20
+ };
21
+ type DefineUpdateFactory = (params: {
22
+ collectionContract: () => NFTCollectionContractConstructor;
23
+ }) => NFTUpdateContractConstructor;
24
+
25
+ /**
26
+ * The `NFTUpdateBase` interface defines the update functionalities required for managing an NFT update
27
+ */
28
+ type NFTUpdateBase = SmartContract & {
29
+ /**
30
+ * Checks if an NFT can be updated from its current state (`input`) to a new state (`output`).
31
+ *
32
+ * @param collectionAddress - The public key of the NFT collection address.
33
+ * @param nftAddress - The public key of the NFT.
34
+ * @param input - The current state of the NFT.
35
+ * @param output - The desired new state of the NFT.
36
+ * @returns A `Promise` resolving to a `Bool` indicating whether the update is permitted.
37
+ */
38
+ canUpdate(
39
+ collectionAddress: PublicKey,
40
+ nftAddress: PublicKey,
41
+ input: NFTState,
42
+ output: NFTState
43
+ ): Promise<Bool>;
44
+ };
45
+
46
+ /**
47
+ * Defines a constructor for contracts implementing `NFTUpdateBase`, accepting an `address` public key and returning an instance of `NFTUpdateBase`.
48
+ *
49
+ * @param address - The public key of the contract's owner.
50
+ * @returns An instance of `NFTUpdateBase`.
51
+ */
52
+ type NFTUpdateContractConstructor = new (address: PublicKey) => NFTUpdateBase;
53
+
54
+ interface NFTUpdateDeployProps extends Exclude<DeployArgs, undefined> {
55
+ admin: PublicKey;
56
+ uri: string;
57
+ }
58
+
59
+ /**
60
+ * The **NFTStandardUpdate** contract is the default implementation of the `NFTUpdateBase` interface.
61
+ */
62
+ class NFTStandardUpdate extends SmartContract implements NFTUpdateBase {
63
+ /**
64
+ * The public key of the contract's administrator.
65
+ */
66
+ @state(PublicKey) admin = State<PublicKey>();
67
+
68
+ /**
69
+ * Deploys the contract with initial settings.
70
+ * @param props - Deployment properties including admin, upgradeAuthority, uri, canPause, and isPaused.
71
+ */
72
+ async deploy(props: NFTUpdateDeployProps) {
73
+ await super.deploy(props);
74
+ this.admin.set(props.admin);
75
+ this.account.zkappUri.set(props.uri);
76
+ this.account.permissions.set({
77
+ ...Permissions.default(),
78
+ setVerificationKey: Permissions.VerificationKey.signature(),
79
+ setPermissions: Permissions.impossible(),
80
+ });
81
+ }
82
+
83
+ /**
84
+ * Ensures that the transaction is authorized by the contract owner.
85
+ * @returns A signed `AccountUpdate` from the admin.
86
+ */
87
+ async ensureOwnerSignature(): Promise<AccountUpdate> {
88
+ const admin = this.admin.getAndRequireEquals();
89
+ const adminUpdate = AccountUpdate.createSigned(admin);
90
+ adminUpdate.body.useFullCommitment = Bool(true); // Prevent memo and fee change
91
+ return adminUpdate;
92
+ }
93
+
94
+ @method.returns(Bool)
95
+ async canUpdate(
96
+ collectionAddress: PublicKey,
97
+ nftAddress: PublicKey,
98
+ input: NFTState,
99
+ output: NFTState
100
+ ): Promise<Bool> {
101
+ await this.ensureOwnerSignature();
102
+ return Bool(true);
103
+ }
104
+ }
@@ -0,0 +1,527 @@
1
+ import {
2
+ AccountUpdate,
3
+ DeployArgs,
4
+ method,
5
+ Permissions,
6
+ PublicKey,
7
+ State,
8
+ state,
9
+ UInt64,
10
+ SmartContract,
11
+ Bool,
12
+ UInt32,
13
+ Field,
14
+ Struct,
15
+ assert,
16
+ Provable,
17
+ } from "o1js";
18
+ import {
19
+ UInt64Option,
20
+ TransferEvent,
21
+ NFTCollectionContractConstructor,
22
+ NFTApprovalBase,
23
+ NFTCollectionBase,
24
+ NFTTransactionContext,
25
+ TransferExtendedParams,
26
+ TransferParams,
27
+ } from "../interfaces/index.js";
28
+
29
+ const MAX_SALE_FEE = 100000;
30
+ const MIN_STEP = 10; // 1% to previous bid
31
+
32
+ export class AuctionPacked extends Struct({
33
+ ownerX: Field,
34
+ collectionX: Field,
35
+ nftX: Field,
36
+ auctioneerX: Field,
37
+ bidderX: Field,
38
+ data: Field,
39
+ }) {}
40
+
41
+ export class Auction extends Struct({
42
+ owner: PublicKey,
43
+ collection: PublicKey,
44
+ nft: PublicKey,
45
+ auctioneer: PublicKey,
46
+ bidder: PublicKey,
47
+ minimumPrice: UInt64,
48
+ transferFee: UInt64,
49
+ /** The sale fee percentage (e.g., 1000 = 1%, 100 = 0.1%, 10000 = 10%, 100000 = 100%). */
50
+ saleFee: UInt32,
51
+ auctionEndTime: UInt32,
52
+ withdrawPeriod: UInt32, // in slots
53
+ isOwnerPaid: Bool,
54
+ isNFTtransferred: Bool,
55
+ isNFTwithdrawn: Bool,
56
+ }) {
57
+ pack(): AuctionPacked {
58
+ const data = Field.fromBits([
59
+ ...this.minimumPrice.value.toBits(64),
60
+ ...this.transferFee.value.toBits(64),
61
+ ...this.saleFee.value.toBits(32),
62
+ ...this.auctionEndTime.value.toBits(32),
63
+ ...this.withdrawPeriod.value.toBits(32),
64
+ this.owner.isOdd,
65
+ this.collection.isOdd,
66
+ this.nft.isOdd,
67
+ this.auctioneer.isOdd,
68
+ this.bidder.isOdd,
69
+ this.isOwnerPaid,
70
+ this.isNFTtransferred,
71
+ this.isNFTwithdrawn,
72
+ ]);
73
+ return new AuctionPacked({
74
+ ownerX: this.owner.x,
75
+ collectionX: this.collection.x,
76
+ nftX: this.nft.x,
77
+ auctioneerX: this.auctioneer.x,
78
+ bidderX: this.bidder.x,
79
+ data,
80
+ });
81
+ }
82
+ static unpack(packed: AuctionPacked): Auction {
83
+ const bits = packed.data.toBits(64 + 64 + 32 + 32 + 32 + 8);
84
+ const ownerX = packed.ownerX;
85
+ const collectionX = packed.collectionX;
86
+ const nftX = packed.nftX;
87
+ const auctioneerX = packed.auctioneerX;
88
+ const bidderX = packed.bidderX;
89
+ const ownerIsOdd = bits[64 + 64 + 32 + 32 + 32];
90
+ const collectionIsOdd = bits[64 + 64 + 32 + 32 + 32 + 1];
91
+ const nftIsOdd = bits[64 + 64 + 32 + 32 + 32 + 2];
92
+ const auctioneerIsOdd = bits[64 + 64 + 32 + 32 + 32 + 3];
93
+ const bidderIsOdd = bits[64 + 64 + 32 + 32 + 32 + 4];
94
+ const isOwnerPaid = bits[64 + 64 + 32 + 32 + 32 + 5];
95
+ const isNFTtransferred = bits[64 + 64 + 32 + 32 + 32 + 6];
96
+ const isNFTwithdrawn = bits[64 + 64 + 32 + 32 + 32 + 7];
97
+ const owner = PublicKey.from({ x: ownerX, isOdd: ownerIsOdd });
98
+ const collection = PublicKey.from({
99
+ x: collectionX,
100
+ isOdd: collectionIsOdd,
101
+ });
102
+ const nft = PublicKey.from({ x: nftX, isOdd: nftIsOdd });
103
+ const auctioneer = PublicKey.from({
104
+ x: auctioneerX,
105
+ isOdd: auctioneerIsOdd,
106
+ });
107
+ const bidder = PublicKey.from({
108
+ x: bidderX,
109
+ isOdd: bidderIsOdd,
110
+ });
111
+ const minimumPrice = UInt64.Unsafe.fromField(
112
+ Field.fromBits(bits.slice(0, 64))
113
+ );
114
+ const transferFee = UInt64.Unsafe.fromField(
115
+ Field.fromBits(bits.slice(64, 64 + 64))
116
+ );
117
+ const saleFee = UInt32.Unsafe.fromField(
118
+ Field.fromBits(bits.slice(64 + 64, 64 + 64 + 32))
119
+ );
120
+ const auctionEndTime = UInt32.Unsafe.fromField(
121
+ Field.fromBits(bits.slice(64 + 64 + 32, 64 + 64 + 32 + 32))
122
+ );
123
+ const withdrawPeriod = UInt32.Unsafe.fromField(
124
+ Field.fromBits(bits.slice(64 + 64 + 32 + 32, 64 + 64 + 32 + 32 + 32))
125
+ );
126
+ return new Auction({
127
+ owner,
128
+ collection,
129
+ nft,
130
+ auctioneer,
131
+ bidder,
132
+ minimumPrice,
133
+ transferFee,
134
+ saleFee,
135
+ auctionEndTime,
136
+ withdrawPeriod,
137
+ isOwnerPaid,
138
+ isNFTtransferred,
139
+ isNFTwithdrawn,
140
+ });
141
+ }
142
+ }
143
+
144
+ export class AuctionState extends Struct({
145
+ bidAmount: UInt64,
146
+ auction: Auction,
147
+ settled: Bool,
148
+ }) {}
149
+
150
+ export interface NonFungibleTokenAuctionContractDeployProps
151
+ extends Exclude<DeployArgs, undefined> {
152
+ /** The minimum price. */
153
+ minimumPrice: UInt64;
154
+ /** The auction end time. */
155
+ auctionEndTime: UInt32;
156
+ /** The collection of the NFT. */
157
+ collection: PublicKey;
158
+ /** The address of the NFT. */
159
+ nft: PublicKey;
160
+ /** The owner of the NFT. */
161
+ owner: PublicKey;
162
+ /** The auctioneer of the NFT. */
163
+ auctioneer: PublicKey;
164
+ /** The transfer fee. */
165
+ transferFee: UInt64;
166
+ /** The sale fee. */
167
+ saleFee: UInt32;
168
+ /** The withdraw period. */
169
+ withdrawPeriod: UInt32;
170
+ }
171
+
172
+ export class AuctionBidEvent extends Struct({
173
+ bidder: PublicKey,
174
+ price: UInt64,
175
+ }) {}
176
+
177
+ /**
178
+ * Creates a new NFT Collection Contract class.
179
+ *
180
+ * @param params - Constructor parameters including admin and upgrade contracts, and network ID.
181
+ * @returns The Collection class extending TokenContract and implementing required interfaces.
182
+ */
183
+
184
+ export function AuctionFactory(params: {
185
+ collectionContract: () => NFTCollectionContractConstructor;
186
+ }) {
187
+ const { collectionContract } = params;
188
+
189
+ class NonFungibleTokenAuctionContract
190
+ extends SmartContract
191
+ implements NFTApprovalBase
192
+ {
193
+ @state(AuctionPacked) auctionData = State<AuctionPacked>();
194
+ @state(UInt64) bidAmount = State<UInt64>(UInt64.zero);
195
+ @state(Bool) settled = State<Bool>(Bool(false));
196
+
197
+ async deploy(args: NonFungibleTokenAuctionContractDeployProps) {
198
+ await super.deploy(args);
199
+ assert(
200
+ args.saleFee.lessThanOrEqual(UInt32.from(MAX_SALE_FEE)),
201
+ "Sale fee is too high"
202
+ );
203
+ this.auctionData.set(
204
+ new Auction({
205
+ owner: args.owner,
206
+ collection: args.collection,
207
+ nft: args.nft,
208
+ auctioneer: args.auctioneer,
209
+ minimumPrice: args.minimumPrice,
210
+ transferFee: args.transferFee,
211
+ saleFee: args.saleFee,
212
+ auctionEndTime: args.auctionEndTime,
213
+ withdrawPeriod: args.withdrawPeriod,
214
+ bidder: PublicKey.empty(),
215
+ isOwnerPaid: Bool(false),
216
+ isNFTtransferred: Bool(false),
217
+ isNFTwithdrawn: Bool(false),
218
+ }).pack()
219
+ );
220
+ this.settled.set(Bool(false));
221
+ this.bidAmount.set(UInt64.zero);
222
+ this.account.permissions.set({
223
+ ...Permissions.default(),
224
+ send: Permissions.proof(),
225
+ setVerificationKey:
226
+ Permissions.VerificationKey.impossibleDuringCurrentVersion(),
227
+ setPermissions: Permissions.impossible(),
228
+ });
229
+ }
230
+
231
+ events = {
232
+ bid: AuctionBidEvent,
233
+ settleAuction: TransferParams,
234
+ canTransfer: TransferEvent,
235
+ settlePayment: UInt64,
236
+ settleAuctioneerPayment: UInt64,
237
+ withdraw: UInt64,
238
+ };
239
+
240
+ getCollectionContract(address: PublicKey): NFTCollectionBase {
241
+ const CollectionContract = collectionContract();
242
+ return new CollectionContract(address);
243
+ }
244
+
245
+ calculateSaleFee(params: {
246
+ price: UInt64;
247
+ saleFee: UInt32;
248
+ transferFee: UInt64;
249
+ }): UInt64 {
250
+ const { price, saleFee, transferFee } = params;
251
+ saleFee.assertLessThanOrEqual(
252
+ UInt32.from(MAX_SALE_FEE),
253
+ "Sale fee is too high"
254
+ );
255
+ return price.div(MAX_SALE_FEE).mul(UInt64.from(saleFee));
256
+ }
257
+ // anyone can call this method to bid, paying the bid amount for the bidder
258
+ @method.returns(Auction)
259
+ async bid(price: UInt64, bidder: PublicKey): Promise<Auction> {
260
+ const settled = this.settled.getAndRequireEquals();
261
+ settled.assertFalse("Auction already finished");
262
+
263
+ const bidAmount = this.bidAmount.getAndRequireEquals();
264
+ this.account.balance.requireBetween(bidAmount, UInt64.MAXINT());
265
+ const auction = Auction.unpack(this.auctionData.getAndRequireEquals());
266
+ price.assertGreaterThanOrEqual(
267
+ auction.minimumPrice,
268
+ "Bid should be greater or equal than the minimum price"
269
+ );
270
+ price.assertGreaterThan(
271
+ bidAmount.add(bidAmount.div(1000).mul(UInt64.from(MIN_STEP))),
272
+ "Bid should be greater than the existing bid plus the minimum step"
273
+ );
274
+ this.network.globalSlotSinceGenesis.requireBetween(
275
+ UInt32.from(0),
276
+ auction.auctionEndTime
277
+ );
278
+ const sender = this.sender.getUnconstrained();
279
+ const senderUpdate = AccountUpdate.createSigned(sender);
280
+ // if there is no bidder, this AccountUpdate will be ignored, similar to AccountUpdate.createIf()
281
+ const returnUpdate = AccountUpdate.create(auction.bidder);
282
+ senderUpdate.body.useFullCommitment = Bool(true);
283
+ returnUpdate.body.useFullCommitment = Bool(true);
284
+ // return the previous bidder's bid
285
+ this.balance.subInPlace(bidAmount);
286
+ returnUpdate.balance.addInPlace(bidAmount);
287
+ // get the new bid deposit
288
+ senderUpdate.balance.subInPlace(price);
289
+ this.balance.addInPlace(price);
290
+ this.bidAmount.set(price);
291
+ auction.bidder = bidder;
292
+ this.auctionData.set(auction.pack());
293
+ this.emitEvent("bid", new AuctionBidEvent({ bidder, price }));
294
+ return auction;
295
+ }
296
+
297
+ @method.returns(AuctionState)
298
+ async getAuctionState(): Promise<AuctionState> {
299
+ return new AuctionState({
300
+ auction: Auction.unpack(this.auctionData.getAndRequireEquals()),
301
+ bidAmount: this.bidAmount.getAndRequireEquals(),
302
+ settled: this.settled.getAndRequireEquals(),
303
+ });
304
+ }
305
+
306
+ // anyone can call this method to settle the auction
307
+ // but it is intended to be called by the auctioneer
308
+ // because the auctioneer is the one who will get the auction commission
309
+ // and pay the royalty to NFT creator
310
+ // This method is atomic, so it will settle the auction
311
+ @method async settleAuction() {
312
+ const settled = this.settled.getAndRequireEquals();
313
+ settled.assertFalse("Auction already settled");
314
+ this.settled.set(Bool(true));
315
+ const auction = Auction.unpack(this.auctionData.getAndRequireEquals());
316
+ this.network.globalSlotSinceGenesis.requireBetween(
317
+ auction.auctionEndTime.add(1),
318
+ UInt32.MAXINT()
319
+ );
320
+ const nftAddress = auction.nft;
321
+
322
+ const bidAmount = this.bidAmount.getAndRequireEquals();
323
+ auction.bidder.equals(PublicKey.empty()).assertFalse("No bidder");
324
+ bidAmount.assertGreaterThanOrEqual(
325
+ auction.minimumPrice,
326
+ "Bidder does not have enough balance"
327
+ );
328
+ const collection = this.getCollectionContract(auction.collection);
329
+ const transferParams = new TransferParams({
330
+ address: nftAddress,
331
+ from: this.address,
332
+ to: auction.bidder,
333
+ price: UInt64Option.fromValue(bidAmount),
334
+ context: new NFTTransactionContext({
335
+ custom: [Field(1), Field(0), Field(0)],
336
+ }),
337
+ });
338
+ await collection.transferByProof(transferParams);
339
+ this.emitEvent("settleAuction", transferParams);
340
+ }
341
+
342
+ // and pay the royalty to NFT creator
343
+ // This method is atomic, so it will settle the auction
344
+ @method async withdrawNFT() {
345
+ const settled = this.settled.getAndRequireEquals();
346
+ settled.assertFalse("Auction already settled");
347
+ this.settled.set(Bool(true));
348
+ const auction = Auction.unpack(this.auctionData.getAndRequireEquals());
349
+ auction.isNFTwithdrawn.assertFalse("NFT already withdrawn");
350
+ auction.isNFTtransferred.assertFalse("NFT already transferred");
351
+ this.network.globalSlotSinceGenesis.requireBetween(
352
+ auction.auctionEndTime.add(auction.withdrawPeriod),
353
+ UInt32.MAXINT()
354
+ );
355
+ const nftAddress = auction.nft;
356
+
357
+ const collection = this.getCollectionContract(auction.collection);
358
+ const transferParams = new TransferParams({
359
+ address: nftAddress,
360
+ from: this.address,
361
+ to: auction.owner,
362
+ price: UInt64Option.none(),
363
+ context: new NFTTransactionContext({
364
+ custom: [Field(2), Field(0), Field(0)],
365
+ }),
366
+ });
367
+ await collection.transferByProof(transferParams);
368
+ this.emitEvent("settleAuction", transferParams);
369
+ }
370
+
371
+ @method.returns(Bool)
372
+ async canTransfer(params: TransferExtendedParams): Promise<Bool> {
373
+ this.settled.requireEquals(Bool(true));
374
+ const isSale = params.context.custom[0].equals(Field(1));
375
+ const isWithdraw = params.context.custom[0].equals(Field(2));
376
+ isSale.or(isWithdraw).assertTrue("Invalid context");
377
+
378
+ const auction = Auction.unpack(this.auctionData.getAndRequireEquals());
379
+ auction.isNFTtransferred.assertFalse("NFT already transferred");
380
+ auction.isNFTwithdrawn.assertFalse("NFT already withdrawn");
381
+ const collectionAddress = auction.collection;
382
+ const nftAddress = auction.nft;
383
+ const owner = auction.owner;
384
+ const bidder = auction.bidder;
385
+ const bidAmount = this.bidAmount.getAndRequireEquals();
386
+ this.network.globalSlotSinceGenesis.requireBetween(
387
+ auction.auctionEndTime.add(
388
+ Provable.if(isSale, UInt32.from(1), auction.withdrawPeriod)
389
+ ),
390
+ UInt32.MAXINT()
391
+ );
392
+
393
+ params.collection.assertEquals(collectionAddress);
394
+ params.nft.assertEquals(nftAddress);
395
+ params.from
396
+ .equals(owner)
397
+ .and(params.approved.equals(this.address))
398
+ .or(
399
+ params.from
400
+ .equals(this.address)
401
+ .and(params.approved.equals(PublicKey.empty()))
402
+ )
403
+ .assertTrue("Only owner or auction can transfer");
404
+ params.price.isSome.assertEquals(isSale);
405
+ params.price
406
+ .orElse(UInt64.zero)
407
+ .assertEquals(Provable.if(isSale, bidAmount, UInt64.zero));
408
+ params.price
409
+ .orElse(UInt64.MAXINT())
410
+ .assertGreaterThanOrEqual(
411
+ auction.minimumPrice,
412
+ "Bid should be greater or equal than the minimum price"
413
+ );
414
+ params.to.assertEquals(Provable.if(isSale, bidder, auction.owner));
415
+ const fee = params.fee.orElse(UInt64.zero);
416
+ fee.assertLessThanOrEqual(
417
+ Provable.if(isSale, bidAmount, UInt64.MAXINT()),
418
+ "Fee is higher than the bid"
419
+ );
420
+ const saleFee = this.calculateSaleFee({
421
+ price: bidAmount,
422
+ saleFee: auction.saleFee,
423
+ transferFee: auction.transferFee,
424
+ });
425
+ fee.assertLessThanOrEqual(
426
+ Provable.if(isSale, saleFee, UInt64.MAXINT()),
427
+ "Fee is higher than the sale fee"
428
+ );
429
+ auction.isNFTtransferred = isSale;
430
+ auction.isNFTwithdrawn = isWithdraw;
431
+ this.auctionData.set(auction.pack());
432
+
433
+ this.emitEvent(
434
+ "canTransfer",
435
+ new TransferEvent({
436
+ ...params,
437
+ })
438
+ );
439
+ return Bool(true);
440
+ }
441
+
442
+ @method
443
+ async settlePayment(): Promise<void> {
444
+ this.settled.getAndRequireEquals().assertTrue("Auction not settled");
445
+ const auction = Auction.unpack(this.auctionData.getAndRequireEquals());
446
+ auction.isOwnerPaid.assertFalse("Owner is not paid yet");
447
+ auction.isNFTtransferred.assertTrue("NFT not transferred");
448
+ const bidAmount = this.bidAmount.getAndRequireEquals();
449
+ this.network.globalSlotSinceGenesis.requireBetween(
450
+ auction.auctionEndTime.add(1),
451
+ UInt32.MAXINT()
452
+ );
453
+
454
+ const payment = bidAmount.sub(
455
+ this.calculateSaleFee({
456
+ price: bidAmount,
457
+ saleFee: auction.saleFee,
458
+ transferFee: auction.transferFee,
459
+ })
460
+ );
461
+
462
+ this.account.balance.requireBetween(payment, UInt64.MAXINT());
463
+ const ownerUpdate = AccountUpdate.create(auction.owner);
464
+ ownerUpdate.balance.addInPlace(payment);
465
+ this.balance.subInPlace(payment);
466
+ ownerUpdate.body.useFullCommitment = Bool(true);
467
+
468
+ auction.isOwnerPaid = Bool(true);
469
+ this.auctionData.set(auction.pack());
470
+
471
+ this.emitEvent("settlePayment", payment);
472
+ }
473
+
474
+ /*
475
+ const balance = this.account.balance.getAndRequireEquals();
476
+ is not stable and sometimes gives 0 on devnet during proving, so we put the amount as a parameter
477
+ This method can be called many times by anyone, allowing the auctioneer to use the hardware wallet and bots
478
+ */
479
+ @method
480
+ async settleAuctioneerPayment(amount: UInt64): Promise<void> {
481
+ this.settled.getAndRequireEquals().assertTrue("Auction not settled");
482
+ const auction = Auction.unpack(this.auctionData.getAndRequireEquals());
483
+ auction.isOwnerPaid.assertTrue(
484
+ "Owner is not paid yet, first call settlePayment"
485
+ );
486
+ this.network.globalSlotSinceGenesis.requireBetween(
487
+ auction.auctionEndTime.add(1),
488
+ UInt32.MAXINT()
489
+ );
490
+
491
+ this.account.balance.requireBetween(amount, UInt64.MAXINT());
492
+
493
+ const auctioneerUpdate = AccountUpdate.create(auction.auctioneer);
494
+ auctioneerUpdate.balance.addInPlace(amount);
495
+ this.balance.subInPlace(amount);
496
+ auctioneerUpdate.body.useFullCommitment = Bool(true);
497
+
498
+ this.emitEvent("settleAuctioneerPayment", amount);
499
+ }
500
+
501
+ /**
502
+ * Withdraw the deposit from the auction
503
+ * in case the auction is not settled during the WITHDRAW_PERIOD
504
+ * for any reason
505
+ * Anybody can call this method to allow the use of bots by the auctioneer or bidder
506
+ */
507
+ @method
508
+ async withdraw(): Promise<void> {
509
+ const auction = Auction.unpack(this.auctionData.getAndRequireEquals());
510
+ auction.isNFTtransferred.assertFalse("NFT already transferred");
511
+ this.network.globalSlotSinceGenesis.requireBetween(
512
+ auction.auctionEndTime.add(auction.withdrawPeriod),
513
+ UInt32.MAXINT()
514
+ );
515
+ const bidAmount = this.bidAmount.getAndRequireEquals();
516
+ const bidderUpdate = AccountUpdate.create(auction.bidder);
517
+ bidderUpdate.balance.addInPlace(bidAmount);
518
+ this.balance.subInPlace(bidAmount);
519
+ bidderUpdate.body.useFullCommitment = Bool(true);
520
+ this.settled.set(Bool(true));
521
+
522
+ this.emitEvent("withdraw", bidAmount);
523
+ }
524
+ }
525
+
526
+ return NonFungibleTokenAuctionContract;
527
+ }