I am trying to port our current contract deployed here to Cadence 1.0.
The Cadence 1.0 specification no longer allows the definition of bare resources inside an interface contract. As a result, I had to change some of the previously defined resources into interfaces. However, after making this change, it is no longer possible to use these resources (now interfaces) as types within the same contract interface.
Expected Behavior
I expect to be able to use "Minter" in the same way it was defined in the pre-Crescendo contract. Specifically, I want to use the following code:
access(all) resource interface IProducer {
access(contract) let minters: @{String: Minter} // HERE
}
access(all) resource interface Producer: IContent, IProducer {
access(contract) let minters: @{String: Minter} // AND HERE
}
Steps To Reproduce
I want to port our current contract deployed here to cadence 1.0.
Due to the new specification, bare resources cannot be defined inside an interface contract. Therefore, I changed the definition of some resources into interfaces.
From this:
pub resource Minter: IMinter {
pub let id: String
pub var lastMintNumber: UInt32
pub let contentCapability: Capability
pub fun withdraw(mintNumber: UInt32): @AnyResource{TiblesNFT.INFT}
pub fun mintNext()
}
To this:
access(all) resource interface Minter: IMinter { // note here the addition of the word "interface"
access(all) let id: String
access(all) var lastMintNumber: UInt32
// access(all) let contentCapability: Capability<&{TiblesProducer.IContent}>
access(all) fun withdraw(mintNumber: UInt32): @{TiblesNFT.INFT}
access(all) fun mintNext()
}
This change removes the error message resource declarations cannot be nested inside contract interface declarations but introduces a new issue in the same contract where this resource (now an interface) is used.
The contract uses the "Minter" interface as a type inside two places:
access(all) resource interface IProducer {
access(contract) let minters: @{String: Minter} // HERE
}
access(all) resource interface Producer: IContent, IProducer {
access(contract) let minters: @{String: Minter} // AND HERE
}
However, now the "Minter" interface (previously a resource) cannot be used as a type in the same way, and the following error occurs:
error: invalid use of interface as type
--> cadence/contracts/crescendo/TiblesProducer.cdc:27:34
|
27 | access(contract) let minters: @{String: Minter}
| ^^^^^^^^^^^^^^^^^ got `{String: TiblesProducer.Minter}`; consider using `{String: {TiblesProducer.Minter}}`
error: invalid use of interface as type
--> cadence/contracts/crescendo/TiblesProducer.cdc:31:34
|
31 | access(contract) let minters: @{String: Minter}
| ^^^^^^^^^^^^^^^^^ got `{String: TiblesProducer.Minter}`; consider using `{String: {TiblesProducer.Minter}}`
✘ e93c412c964bdf40.TiblesProducer
When I follow the validation suggestion and try to stage the contract again, another error is generated:
error: mismatching field `minters` in `IProducer`
--> cadence/contracts/crescendo/TiblesProducer.cdc:27:34
|
27 | access(contract) let minters: @{String: {Minter}}
| ^^^^^^^^^^^^^^^^^^^ incompatible type annotations. expected `Minter`, found `{Minter}`
error: mismatching field `minters` in `Producer`
--> cadence/contracts/crescendo/TiblesProducer.cdc:31:34
|
31 | access(contract) let minters: @{String: {Minter}}
| ^^^^^^^^^^^^^^^^^^^ incompatible type annotations. expected `Minter`, found `{Minter}`
✘ e93c412c964bdf40.TiblesProducer
The same issue occurs when I use the complete type:
error: mismatching field `minters` in `IProducer`
--> cadence/contracts/crescendo/TiblesProducer.cdc:27:34
|
27 | access(contract) let minters: @{String: {TiblesProducer.Minter}}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incompatible type annotations. expected `Minter`, found `{TiblesProducer.Minter}`
error: mismatching field `minters` in `Producer`
--> cadence/contracts/crescendo/TiblesProducer.cdc:31:34
|
31 | access(contract) let minters: @{String: {TiblesProducer.Minter}}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incompatible type annotations. expected `Minter`, found `{TiblesProducer.Minter}`
Here is the full code of the Crescendo 1.0 TiblesProducer contract interface as it currently stands:
import TiblesNFT from 0xe93c412c964bdf40
access(all) contract interface TiblesProducer {
access(all) let ProducerStoragePath: StoragePath
access(all) let ProducerPath: PrivatePath
access(all) let ContentPath: PublicPath
// access(all) let contentCapability: Capability<&{TiblesProducer.IContent}>
access(all) event MinterCreated(minterId: String)
access(all) event TibleMinted(minterId: String, mintNumber: UInt32, id: UInt64)
// Producers must provide a ContentLocation struct so that NFTs can access metadata.
access(all) struct interface ContentLocation {}
access(all) struct interface IContentLocation {}
// This is a public resource that lets the individual tibles get their metadata.
// Adding content is done through the Producer.
access(all) resource interface IContent {
// Content is stored in the set/item/variant structures. To retrieve it, we have a contentId that maps to the path.
access(all) view fun getMetadata(contentId: String): {String: AnyStruct}?
}
// Provides access to producer activities like content creation and NFT minting.
// The resource is stored in the app account's storage with a link in /private.
access(all) resource interface IProducer {
// Minters create and store tibles before they are sold. One minter per set-item-variant combo.
access(contract) let minters: @{String: Minter}
}
access(all) resource interface Producer: IContent, IProducer {
access(contract) let minters: @{String: Minter}
}
// Mints new NFTs for a specific set/item/variant combination.
access(all) resource interface IMinter {
access(all) let id: String
// Keeps track of the mint number for items.
access(all) var lastMintNumber: UInt32
// Stored with each minted NFT so that it can access metadata.
// access(all) let contentCapability: Capability<&{TiblesProducer.IContent}>
// Used only on original purchase, when the NFT gets transferred from the producer to the user's collection.
access(all) fun withdraw(mintNumber: UInt32): @{TiblesNFT.INFT}
access(all) fun mintNext()
}
access(all) resource interface Minter: IMinter {
access(all) let id: String
access(all) var lastMintNumber: UInt32
// access(all) let contentCapability: Capability<&{TiblesProducer.IContent}>
access(all) fun withdraw(mintNumber: UInt32): @{TiblesNFT.INFT}
access(all) fun mintNext()
}
}
Current Behavior
I am trying to port our current contract deployed here to Cadence 1.0.
The Cadence 1.0 specification no longer allows the definition of bare resources inside an interface contract. As a result, I had to change some of the previously defined resources into interfaces. However, after making this change, it is no longer possible to use these resources (now interfaces) as types within the same contract interface.
Expected Behavior
I expect to be able to use "Minter" in the same way it was defined in the pre-Crescendo contract. Specifically, I want to use the following code:
Steps To Reproduce
I want to port our current contract deployed here to cadence 1.0.
Due to the new specification, bare resources cannot be defined inside an interface contract. Therefore, I changed the definition of some resources into interfaces.
From this:
To this:
This change removes the error
message resource declarations cannot be nested inside contract interface declarations
but introduces a new issue in the same contract where this resource (now an interface) is used.The contract uses the "Minter" interface as a type inside two places:
However, now the "Minter" interface (previously a resource) cannot be used as a type in the same way, and the following error occurs:
When I follow the validation suggestion and try to stage the contract again, another error is generated:
The same issue occurs when I use the complete type:
Here is the full code of the Crescendo 1.0 TiblesProducer contract interface as it currently stands:
Environment