From 4efcd8e830830f4619e4e2774e368324ff87d441 Mon Sep 17 00:00:00 2001 From: Austin Kline Date: Mon, 23 Sep 2024 16:50:04 -0700 Subject: [PATCH] add paymentTokenTypes to DropDetails struct --- contracts/DropFactory.cdc | 4 +- contracts/DropTypes.cdc | 35 ++++++----- contracts/FlowtyDrops.cdc | 60 +++++++++++-------- scripts/get_drop_summaries.cdc | 7 ++- scripts/get_drop_summary.cdc | 8 ++- .../factory/create_open_edition_drop.cdc | 3 +- 6 files changed, 71 insertions(+), 46 deletions(-) diff --git a/contracts/DropFactory.cdc b/contracts/DropFactory.cdc index 0bf25fa..0c7c3ee 100644 --- a/contracts/DropFactory.cdc +++ b/contracts/DropFactory.cdc @@ -35,7 +35,7 @@ access(all) contract DropFactory { let nftType = CompositeType(nftTypeIdentifier) ?? panic("invalid nft type identifier") - let dropDetails = FlowtyDrops.DropDetails(display: dropDisplay, medias: nil, commissionRate: 0.05, nftType: nftTypeIdentifier) + let dropDetails = FlowtyDrops.DropDetails(display: dropDisplay, medias: nil, commissionRate: 0.05, nftType: nftTypeIdentifier, paymentTokenTypes: {paymentTokenType.identifier: true}) let drop <- FlowtyDrops.createDrop(details: dropDetails, minterCap: minterCap, phases: <- [<-phase]) return <- drop @@ -67,7 +67,7 @@ access(all) contract DropFactory { let phase <- FlowtyDrops.createPhase(details: phaseDetails) let nftType = CompositeType(nftTypeIdentifier) ?? panic("invalid nft type identifier") - let dropDetails = FlowtyDrops.DropDetails(display: dropDisplay, medias: nil, commissionRate: 0.05, nftType: nftTypeIdentifier) + let dropDetails = FlowtyDrops.DropDetails(display: dropDisplay, medias: nil, commissionRate: 0.05, nftType: nftTypeIdentifier, paymentTokenTypes: {paymentTokenType.identifier: true}) let drop <- FlowtyDrops.createDrop(details: dropDetails, minterCap: minterCap, phases: <- [<-phase]) return <- drop diff --git a/contracts/DropTypes.cdc b/contracts/DropTypes.cdc index 73cdd92..6807585 100644 --- a/contracts/DropTypes.cdc +++ b/contracts/DropTypes.cdc @@ -36,6 +36,7 @@ access(all) contract DropTypes { access(all) let commissionRate: UFix64 access(all) let nftType: String access(all) let creator: Address? + access(all) let paymentTokenTypes: {String: Bool} access(all) let address: Address? access(all) let mintedByAddress: Int? @@ -58,7 +59,8 @@ access(all) contract DropTypes { address: Address?, phases: [PhaseSummary], royaltyRate: UFix64, - creator: Address? + creator: Address?, + paymentTokenTypes: {String: Bool} ) { self.id = id self.display = Display(display) @@ -82,6 +84,7 @@ access(all) contract DropTypes { self.blockHeight = b.height self.blockTimestamp = UInt64(b.timestamp) self.royaltyRate = royaltyRate + self.paymentTokenTypes = paymentTokenTypes } } @@ -118,7 +121,7 @@ access(all) contract DropTypes { access(all) let remainingForAddress: Int? access(all) let maxPerMint: Int? - access(all) let quote: Quote? + access(all) let quotes: {String: Quote} init( index: Int, @@ -127,7 +130,7 @@ access(all) contract DropTypes { totalMinted: Int?, minter: Address?, quantity: Int?, - paymentIdentifier: String? + paymentIdentifiers: [String] ) { self.index = index self.id = phase.uuid @@ -155,19 +158,17 @@ access(all) contract DropTypes { self.remainingForAddress = nil } - self.maxPerMint = d.addressVerifier.getMaxPerMint(addr: self.address, totalMinted: totalMinted ?? 0, data: {} as {String: AnyStruct}) + self.maxPerMint = d.addressVerifier.getMaxPerMint(addr: self.address, totalMinted: totalMinted ?? 0, data: {}) + self.quotes = {} - if paymentIdentifier != nil && quantity != nil { - let price = d.pricer.getPrice(num: quantity!, paymentTokenType: CompositeType(paymentIdentifier!)!, minter: minter) - - self.quote = Quote(price: price, quantity: quantity!, paymentIdentifier: paymentIdentifier!, minter: minter) - } else { - self.quote = nil + for paymentIdentifier in paymentIdentifiers { + let price = d.pricer.getPrice(num: quantity!, paymentTokenType: CompositeType(paymentIdentifier)!, minter: minter) + self.quotes[paymentIdentifier] = Quote(price: price, quantity: quantity!, paymentIdentifier: paymentIdentifier, minter: minter) } } } - access(all) fun getDropSummary(nftTypeIdentifier: String, dropID: UInt64, minter: Address?, quantity: Int?, paymentIdentifier: String?): DropSummary? { + access(all) fun getDropSummary(nftTypeIdentifier: String, dropID: UInt64, minter: Address?, quantity: Int?, paymentIdentifiers: [String]): DropSummary? { let nftType = CompositeType(nftTypeIdentifier) ?? panic("invalid nft type identifier") let segments = nftTypeIdentifier.split(separator: ".") let contractAddress = AddressUtils.parseAddress(nftType)! @@ -206,7 +207,7 @@ access(all) contract DropTypes { totalMinted: minter != nil ? dropDetails.minters[minter!] : nil, minter: minter, quantity: quantity, - paymentIdentifier: paymentIdentifier + paymentIdentifiers: paymentIdentifiers ) phaseSummaries.append(summary) } @@ -231,13 +232,14 @@ access(all) contract DropTypes { address: minter, phases: phaseSummaries, royaltyRate: royaltyRate, - creator: creator + creator: creator, + paymentTokenTypes: dropDetails.paymentTokenTypes ) return dropSummary } - access(all) fun getAllDropSummaries(nftTypeIdentifier: String, minter: Address?, quantity: Int?, paymentIdentifier: String?): [DropSummary] { + access(all) fun getAllDropSummaries(nftTypeIdentifier: String, minter: Address?, quantity: Int?, paymentIdentifiers: [String]): [DropSummary] { let nftType = CompositeType(nftTypeIdentifier) ?? panic("invalid nft type identifier") let segments = nftTypeIdentifier.split(separator: ".") let contractAddress = AddressUtils.parseAddress(nftType)! @@ -278,7 +280,7 @@ access(all) contract DropTypes { totalMinted: minter != nil ? dropDetails.minters[minter!] : nil, minter: minter, quantity: quantity, - paymentIdentifier: paymentIdentifier + paymentIdentifiers: paymentIdentifiers.length > 0 ? paymentIdentifiers : dropDetails.paymentTokenTypes.keys ) phaseSummaries.append(summary) } @@ -307,7 +309,8 @@ access(all) contract DropTypes { address: minter, phases: phaseSummaries, royaltyRate: royaltyRate, - creator: creator + creator: creator, + paymentTokenTypes: dropDetails.paymentTokenTypes )) } diff --git a/contracts/FlowtyDrops.cdc b/contracts/FlowtyDrops.cdc index 4e76b12..50ac372 100644 --- a/contracts/FlowtyDrops.cdc +++ b/contracts/FlowtyDrops.cdc @@ -24,9 +24,9 @@ access(all) contract FlowtyDrops { // Interface to expose all the components necessary to participate in a drop // and to ask questions about a drop. access(all) resource interface DropPublic { - access(all) fun borrowPhasePublic(index: Int): &{PhasePublic} - access(all) fun borrowActivePhases(): [&{PhasePublic}] - access(all) fun borrowAllPhases(): [&{PhasePublic}] + access(all) view fun borrowPhasePublic(index: Int): &{PhasePublic} + access(all) view fun borrowActivePhases(): [&{PhasePublic}] + access(all) view fun borrowAllPhases(): [&{PhasePublic}] access(all) fun mint( payment: @{FungibleToken.Vault}, amount: Int, @@ -35,8 +35,18 @@ access(all) contract FlowtyDrops { receiverCap: Capability<&{NonFungibleToken.CollectionPublic}>, commissionReceiver: Capability<&{FungibleToken.Receiver}>?, data: {String: AnyStruct} - ): @{FungibleToken.Vault} - access(all) fun getDetails(): DropDetails + ): @{FungibleToken.Vault} { + pre { + self.getDetails().paymentTokenTypes[payment.getType().identifier] == true: "unsupported payment token type" + receiverCap.check(): "unvalid nft receiver capability" + commissionReceiver == nil || commissionReceiver!.check(): "commission receiver must be nil or a valid capability" + self.getType() == Type<@Drop>(): "unsupported type implementing DropPublic" + expectedType.isSubtype(of: Type<@{NonFungibleToken.NFT}>()): "expected type must be an NFT" + expectedType.identifier == self.getDetails().nftType: "expected type does not match drop details type" + receiverCap.check(): "receiver capability is not valid" + } + } + access(all) view fun getDetails(): DropDetails } // A phase represents a stage of a drop. Some drops will only have one @@ -51,23 +61,23 @@ access(all) contract FlowtyDrops { access(all) let resources: @{String: AnyResource} // returns whether this phase of a drop has started. - access(all) fun isActive(): Bool { + access(all) view fun isActive(): Bool { return self.details.activeChecker.hasStarted() && !self.details.activeChecker.hasEnded() } - access(all) fun getDetails(): PhaseDetails { + access(all) view fun getDetails(): PhaseDetails { return self.details } - access(EditPhase) fun borrowActiveCheckerAuth(): auth(Mutate) &{ActiveChecker} { + access(EditPhase) view fun borrowActiveCheckerAuth(): auth(Mutate) &{ActiveChecker} { return &self.details.activeChecker } - access(EditPhase) fun borrowPricerAuth(): auth(Mutate) &{Pricer} { + access(EditPhase) view fun borrowPricerAuth(): auth(Mutate) &{Pricer} { return &self.details.pricer } - access(EditPhase) fun borrowAddressVerifierAuth(): auth(Mutate) &{AddressVerifier} { + access(EditPhase) view fun borrowAddressVerifierAuth(): auth(Mutate) &{AddressVerifier} { return &self.details.addressVerifier } @@ -111,10 +121,7 @@ access(all) contract FlowtyDrops { data: {String: AnyStruct} ): @{FungibleToken.Vault} { pre { - expectedType.isSubtype(of: Type<@{NonFungibleToken.NFT}>()): "expected type must be an NFT" - expectedType.identifier == self.details.nftType: "expected type does not match drop details type" self.phases.length > phaseIndex: "phase index is too high" - receiverCap.check(): "receiver capability is not valid" } // validate the payment vault amount and type @@ -167,23 +174,23 @@ access(all) contract FlowtyDrops { return <- payment } - access(Owner) fun borrowPhase(index: Int): auth(EditPhase) &Phase { + access(Owner) view fun borrowPhase(index: Int): auth(EditPhase) &Phase { return &self.phases[index] } - access(all) fun borrowPhasePublic(index: Int): &{PhasePublic} { + access(all) view fun borrowPhasePublic(index: Int): &{PhasePublic} { return &self.phases[index] } - access(all) fun borrowActivePhases(): [&{PhasePublic}] { - let arr: [&{PhasePublic}] = [] + access(all) view fun borrowActivePhases(): [&{PhasePublic}] { + var arr: [&{PhasePublic}] = [] var count = 0 while count < self.phases.length { let ref = self.borrowPhasePublic(index: count) let activeChecker = ref.getDetails().activeChecker if activeChecker.hasStarted() && !activeChecker.hasEnded() { - arr.append(ref) + arr = arr.concat([ref]) } count = count + 1 @@ -192,12 +199,12 @@ access(all) contract FlowtyDrops { return arr } - access(all) fun borrowAllPhases(): [&{PhasePublic}] { - let arr: [&{PhasePublic}] = [] + access(all) view fun borrowAllPhases(): [&{PhasePublic}] { + var arr: [&{PhasePublic}] = [] var index = 0 while index < self.phases.length { let ref = self.borrowPhasePublic(index: index) - arr.append(ref) + arr = arr.concat([ref]) index = index + 1 } @@ -228,7 +235,7 @@ access(all) contract FlowtyDrops { return <- phase } - access(all) fun getDetails(): DropDetails { + access(all) view fun getDetails(): DropDetails { return self.details } @@ -253,6 +260,7 @@ access(all) contract FlowtyDrops { access(all) var minters: {Address: Int} access(all) let commissionRate: UFix64 access(all) let nftType: String + access(all) let paymentTokenTypes: {String: Bool} access(all) let data: {String: AnyStruct} @@ -265,7 +273,7 @@ access(all) contract FlowtyDrops { self.minters[addr] = self.minters[addr]! + num } - init(display: MetadataViews.Display, medias: MetadataViews.Medias?, commissionRate: UFix64, nftType: String) { + init(display: MetadataViews.Display, medias: MetadataViews.Medias?, commissionRate: UFix64, nftType: String, paymentTokenTypes: {String: Bool}) { pre { nftType != "": "nftType should be a composite type identifier" } @@ -276,6 +284,8 @@ access(all) contract FlowtyDrops { self.commissionRate = commissionRate self.minters = {} self.nftType = nftType + self.paymentTokenTypes = paymentTokenTypes + self.data = {} } } @@ -300,8 +310,8 @@ access(all) contract FlowtyDrops { // - How many items are left in the current phase? // - Can Address x mint on a phase? // - What is the cost to mint for the phase I am interested in (for address x)? - access(all) fun getDetails(): PhaseDetails - access(all) fun isActive(): Bool + access(all) view fun getDetails(): PhaseDetails + access(all) view fun isActive(): Bool } access(all) struct PhaseDetails { diff --git a/scripts/get_drop_summaries.cdc b/scripts/get_drop_summaries.cdc index c6ca007..2c68b8b 100644 --- a/scripts/get_drop_summaries.cdc +++ b/scripts/get_drop_summaries.cdc @@ -1,5 +1,10 @@ import "DropTypes" access(all) fun main(nftTypeIdentifier: String, minter: Address?, quantity: Int?, paymentIdentifier: String?): [DropTypes.DropSummary] { - return DropTypes.getAllDropSummaries(nftTypeIdentifier: nftTypeIdentifier, minter: minter, quantity: quantity, paymentIdentifier: paymentIdentifier) + return DropTypes.getAllDropSummaries( + nftTypeIdentifier: nftTypeIdentifier, + minter: minter, + quantity: quantity, + paymentIdentifiers: paymentIdentifier != nil ? [paymentIdentifier!] : [] + ) } \ No newline at end of file diff --git a/scripts/get_drop_summary.cdc b/scripts/get_drop_summary.cdc index 510ca71..4f8afa9 100644 --- a/scripts/get_drop_summary.cdc +++ b/scripts/get_drop_summary.cdc @@ -1,5 +1,11 @@ import "DropTypes" access(all) fun main(nftTypeIdentifier: String, dropID: UInt64, minter: Address?, quantity: Int?, paymentIdentifier: String?): DropTypes.DropSummary? { - return DropTypes.getDropSummary(nftTypeIdentifier: nftTypeIdentifier, dropID: dropID, minter: minter, quantity: quantity, paymentIdentifier: paymentIdentifier) + return DropTypes.getDropSummary( + nftTypeIdentifier: nftTypeIdentifier, + dropID: dropID, + minter: minter, + quantity: quantity, + paymentIdentifiers: paymentIdentifier != nil ? [paymentIdentifier!]: [] + ) } \ No newline at end of file diff --git a/transactions/factory/create_open_edition_drop.cdc b/transactions/factory/create_open_edition_drop.cdc index bef9b14..7d413f5 100644 --- a/transactions/factory/create_open_edition_drop.cdc +++ b/transactions/factory/create_open_edition_drop.cdc @@ -76,7 +76,8 @@ transaction(contractName: String, managerInitialTokenBalance: UFix64, start: UIn ), medias: nil, commissionRate: 0.05, - nftType: nftType + nftType: nftType, + paymentTokenTypes: {paymentTokenType: true} ) let phaseDetails = FlowtyDrops.PhaseDetails(