Skip to content

Instantly share code, notes, and snippets.

@briandilley
Last active December 22, 2021 19:24
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save briandilley/962e94682b7945d882fcd99702011ea4 to your computer and use it in GitHub Desktop.
Save briandilley/962e94682b7945d882fcd99702011ea4 to your computer and use it in GitHub Desktop.
import StandardViewTypes from 0x02
import SomeNFT from 0x03
import ViewResolvers from 0x04
// Add support for the Person view to the existing NFT contract
transaction {
prepare(signer: AuthAccount) {
let admin = signer.borrow<&SomeNFT.ViewResolverRegistry>(from: SomeNFT.VIEW_RESOLVER_REGISTRY_PATH)!
let resolver <- ViewResolvers.createPersonViewResolver()
admin.registerViewResolver(<- resolver)
}
}
pub contract interface NonFungibleToken {
pub var totalSupply: UInt64
pub event ContractInitialized()
pub event Withdraw(id: UInt64, from: Address?)
pub event Deposit(id: UInt64, to: Address?)
pub resource interface INFT {
pub let id: UInt64
pub fun availableViews(): [Type]
pub fun resolveView(_ type: Type): AnyStruct?
}
pub resource NFT: INFT {
pub let id: UInt64
pub fun availableViews(): [Type]
pub fun resolveView(_ type: Type): AnyStruct?
}
pub resource interface Provider {
pub fun withdraw(withdrawID: UInt64): @NFT {
post {
result.id == withdrawID: "The ID of the withdrawn token must be the same as the requested ID"
}
}
}
pub resource interface Receiver {
pub fun deposit(token: @NFT)
}
pub resource interface CollectionPublic {
pub fun deposit(token: @NFT)
pub fun getIDs(): [UInt64]
pub fun borrowNFT(id: UInt64): &NFT
}
pub resource Collection: Provider, Receiver, CollectionPublic {
pub var ownedNFTs: @{UInt64: NFT}
pub fun withdraw(withdrawID: UInt64): @NFT
pub fun deposit(token: @NFT)
pub fun getIDs(): [UInt64]
pub fun borrowNFT(id: UInt64): &NFT {
pre {
self.ownedNFTs[id] != nil: "NFT does not exist in the collection!"
}
}
}
pub fun createEmptyCollection(): @Collection {
post {
result.getIDs().length == 0: "The created collection must be empty!"
}
}
}
import NonFungibleToken from 0x01
pub contract SomeNFT : NonFungibleToken {
pub var totalSupply: UInt64
pub let viewResolvers: @{String: AnyResource{ViewResolver}}
pub event ContractInitialized()
pub event Withdraw(id: UInt64, from: Address?)
pub event Deposit(id: UInt64, to: Address?)
pub event ViewResolverRegistered(resolverType: Type, viewType: Type)
pub event ViewResolverDeregistered(resolverType: Type, viewType: Type)
access(all) let VIEW_RESOLVER_REGISTRY_PATH: StoragePath
init() {
self.totalSupply = 0
self.viewResolvers <- {}
self.VIEW_RESOLVER_REGISTRY_PATH = /storage/ViewResolverRegistry
self.account.save<@ViewResolverRegistry>(
<- create ViewResolverRegistry(),
to: SomeNFT.VIEW_RESOLVER_REGISTRY_PATH
)
}
pub resource interface ViewResolver {
pub fun getViewType(): Type
pub fun canResolveView(_ nft: &NFT): Bool
pub fun resolveView(_ nft: &NFT): AnyStruct?
}
pub resource ViewResolverRegistry {
pub fun registerViewResolver(_ resolver: @AnyResource{ViewResolver}) {
pre {
SomeNFT.viewResolvers[resolver.getViewType().identifier] == nil : "A ViewResolver for that type exists"
}
emit ViewResolverRegistered(resolverType: resolver.getType(), viewType: resolver.getViewType())
SomeNFT.viewResolvers[resolver.getViewType().identifier] <-! resolver
}
pub fun deregisterViewResolver(_ resolverType: Type): @AnyResource{ViewResolver}? {
pre {
SomeNFT.viewResolvers[resolverType.identifier] != nil : "No ViewResolver with that name exists"
}
let resolver <- SomeNFT.viewResolvers.remove(key: resolverType.identifier)!
emit ViewResolverDeregistered(resolverType: resolver.getType(), viewType: resolver.getViewType())
return <- resolver
}
}
pub fun availableViews(_ nft: &NFT): [Type] {
let ret: [Type] = []
for key in SomeNFT.viewResolvers.keys {
let resolver = &SomeNFT.viewResolvers[key] as &AnyResource{ViewResolver}
if resolver != nil {
ret.append(resolver.getViewType())
}
}
return ret
}
pub fun resolveView(_ nft: &NFT, _ type: Type): AnyStruct? {
var resolver: &AnyResource{ViewResolver}? = nil
for key in SomeNFT.viewResolvers.keys {
resolver = &SomeNFT.viewResolvers[key] as &AnyResource{ViewResolver}
if resolver != nil && resolver.getType() == type {
break
}
resolver = nil
}
if resolver == nil {
return nil
} else if !resolver!.canResolveView(nft) {
return nil
}
return resolver!.resolveView(nft)
}
pub resource NFT: NonFungibleToken.INFT {
pub let id: UInt64
// the follow is immutable "view"
pub let name: String
pub let year: UInt8
pub let shavedElbows: Bool
init(id: UInt64, name: String, year: UInt8, shavedElbows: Bool) {
self.id = SomeNFT.totalSupply
self.name = name
self.year = year
self.shavedElbows = shavedElbows
SomeNFT.totalSupply = SomeNFT.totalSupply + 1
}
pub fun availableViews(): [Type] {
return SomeNFT.availableViews(&self as &NFT)
}
pub fun resolveView(_ type: Type): AnyStruct? {
return SomeNFT.resolveView(&self as &NFT, type)
}
}
pub resource Collection: NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic {
pub var ownedNFTs: @{UInt64: NonFungibleToken.NFT}
init() {
self.ownedNFTs <- {}
}
pub fun withdraw(withdrawID: UInt64): @NonFungibleToken.NFT {
let token <- self.ownedNFTs.remove(key: withdrawID)
?? panic("Cannot withdraw: NFT does not exist in the collection")
emit Withdraw(id: token.id, from: self.owner?.address)
return <-token
}
pub fun deposit(token: @NonFungibleToken.NFT) {
let token <- token as! @SomeNFT.NFT
let id = token.id
let oldToken <- self.ownedNFTs[id] <- token
if self.owner?.address != nil {
emit Deposit(id: id, to: self.owner?.address)
}
destroy oldToken
}
pub fun getIDs(): [UInt64] {
return self.ownedNFTs.keys
}
pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT {
return &self.ownedNFTs[id] as &NonFungibleToken.NFT
}
destroy() {
destroy self.ownedNFTs
}
}
pub fun createEmptyCollection(): @NonFungibleToken.Collection {
return <- create SomeNFT.Collection()
}
}
access(all) contract StandardViewTypes {
pub struct Person {
pub let name: String
init(name: String) {
self.name = name
}
}
}
import SomeNFT from 0x03
import StandardViewTypes from 0x02
pub contract ViewResolvers {
pub resource PersonViewResolver : SomeNFT.ViewResolver {
pub fun getViewType(): Type {
return Type<StandardViewTypes.Person>()
}
pub fun canResolveView(_ nft: &SomeNFT.NFT): Bool {
return nft.isInstance(Type<@SomeNFT.NFT>())
}
pub fun resolveView(_ nft: &SomeNFT.NFT): AnyStruct? {
return StandardViewTypes.Person(name: nft.name)
}
}
pub fun createPersonViewResolver(): @PersonViewResolver {
return <- create ViewResolvers.PersonViewResolver()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment