DeploySEALED
*╱!╱╲◇*╳!@█$◇●╳~▫◇□!╱╳#@#○○╱&▪!?□#▪*▒$●╳*$%■░█~○@@?~●╲╳●~&@▫?#▓▫
Transaction ID
Execution Fee
0.00000574 FLOWTransaction Summary
DeployContract deployment
Contract deployment
Script Arguments
0nameString
Certifily
1codeString
// Certifily NFT Smart Contract
// NFT : www.Certifi.ly
// Version : 1.0.0
// Blockchain : Flow www.onFlow.org
import NonFungibleToken from 0x1d7e57aa55817448
import MetadataViews from 0x1d7e57aa55817448
import ViewResolver from 0x1d7e57aa55817448
access(all) contract Certifily: NonFungibleToken {
// Total number of token supply
access(all) var totalSupply: UInt64
/// Path where the `Collection` is stored
access(all) let certifilyStoragePath: StoragePath
/// Path where the public capability for the `Collection` is
access(all) let certifilyPublicPath: PublicPath
/// NFT Minter
access(all) let certifilyMinterPath: StoragePath
// Contract Events
access(all) event ContractInitialized()
access(all) event Withdraw(id: UInt64, from: Address?)
access(all) event Deposit(id: UInt64, to: Address?)
access(all) event Mint(id: UInt64, content:String, owner: Address?, insitution:String)
// TOKEN RESOURCE
access(all) resource NFT: NonFungibleToken.NFT {
// Unique identifier for NFT Token
access(all) let id :UInt64
// Meta data to store token data (use dict for data)
access(self) let metaData: {String : String}
access(all) fun getMetadata():{String: String} {
return self.metaData
}
// NFT token insitution
access(all) let insitution:String
access(all) let certType:UInt8
// Certificate token holder address
access(all) let holder:Address?
// View permission for the NFT (an array of addresses)
access(all) let viewPermission: [String]
// In current store static dict in meta data
init(id : UInt64, content : String, insitution:String, description:String , holder:Address?,previewContent:String,certType:UInt8, viewPermission: [String]) {
self.id = id
self.metaData = {"content" : content, "description": description, "previewContent":previewContent }
self.holder = holder
self.insitution = insitution
self.certType = certType
self.viewPermission = viewPermission
}
/// createEmptyCollection creates an empty Collection
/// and returns it to the caller so that they can own NFTs
/// @{NonFungibleToken.Collection}
access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} {
return <-Certifily.createEmptyCollection(nftType: Type<@Certifily.NFT>())
}
access(all) view fun getViews(): [Type] {
return [
Type<MetadataViews.Display>(),
Type<MetadataViews.ExternalURL>(),
Type<MetadataViews.NFTCollectionData>(),
Type<MetadataViews.NFTCollectionDisplay>(),
Type<MetadataViews.Serial>(),
Type<MetadataViews.Traits>()
]
}
// Function to add an address to viewPermission
access(all) fun addViewPermission(address: [String]) {
for addr in address {
// Check if the address is not already in the viewPermission array
if !self.viewPermission.contains(addr) {
self.viewPermission.append(addr)
}
}
}
// Function to remove an address from viewPermission
access(all) fun removeViewPermission(address: String) {
// Find the index of the address in viewPermission and remove it
let index = self.viewPermission.firstIndex(of: address)
if let idx = index {
self.viewPermission.remove(at: idx)
}
}
access(all) fun resolveView(_ view: Type): AnyStruct? {
switch view {
case Type<MetadataViews.Display>():
return MetadataViews.Display(
name: self.insitution,
description: self.metaData["description"]!,
thumbnail: MetadataViews.HTTPFile(
url: self.metaData["previewContent"]!
)
)
case Type<MetadataViews.Serial>():
return MetadataViews.Serial(
self.id
)
case Type<MetadataViews.ExternalURL>():
return MetadataViews.ExternalURL("https://certifi.ly")
case Type<MetadataViews.NFTCollectionData>():
return MetadataViews.NFTCollectionData(
storagePath: Certifily.certifilyStoragePath,
publicPath: Certifily.certifilyPublicPath,
publicCollection: Type<&Certifily.Collection>(),
publicLinkedType: Type<&Certifily.Collection>(),
createEmptyCollectionFunction: (fun(): @{NonFungibleToken.Collection} {
return <-Certifily.createEmptyCollection(nftType: Type<@Certifily.NFT>())
})
)
case Type<MetadataViews.NFTCollectionDisplay>():
let media = MetadataViews.Media(
file: MetadataViews.HTTPFile(
url: "https://alpha.certifi.ly/logo512.png"
),
mediaType: "image/png"
)
return MetadataViews.NFTCollectionDisplay(
name: "Certifily Collection",
description: "Next-gen NFT documents B2B SaaS platform for all-gen",
externalURL: MetadataViews.ExternalURL("https://certifi.ly"),
squareImage: media,
bannerImage: media,
socials: {
"twitter": MetadataViews.ExternalURL("https://twitter.com/certifily"),
"instagram": MetadataViews.ExternalURL("https://www.instagram.com/certifi.ly/"),
"discord" : MetadataViews.ExternalURL("https://discord.io/certifily")
}
)
case Type<MetadataViews.Traits>():
return []
}
return nil
}
}
// Account's public collection
access(all) resource interface CertifilyCollectionPublic {
// Function to check if an address has view permission for an NFT
access(all) view fun hasViewPermission(id: UInt64, address: String): Bool?
access(all) fun borrowCertifily(id: UInt64): &{NonFungibleToken.NFT}? {
// If the result isn't nil, the id of the returned reference
// should be the same as the argument to the function
post {
(result == nil) || (result?.id == id):
"Cannot borrow CaaPass reference: The ID of the returned reference is incorrect"
}
}
}
// NFT Collection resource
access(all) resource Collection : CertifilyCollectionPublic, NonFungibleToken.Collection {
/// getSupportedNFTTypes returns a list of NFT types that this receiver accepts
access(all) view fun getSupportedNFTTypes(): {Type: Bool} {
let supportedTypes: {Type: Bool} = {}
supportedTypes[Type<@Certifily.NFT>()] = true
return supportedTypes
}
/// Returns whether or not the given type is accepted by the collection
/// A collection that can accept any type should just return true by default
access(all) view fun isSupportedNFTType(type: Type): Bool {
return type == Type<@Certifily.NFT>()
}
/// createEmptyCollection creates an empty Collection for the specified NFT type
/// and returns it to the caller so that they can own NFTs
access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} {
return <- create Collection()
}
// Contains caller's list of NFTs
access(all) var ownedNFTs: @{UInt64: {NonFungibleToken.NFT}}
init() {
self.ownedNFTs <- {}
}
access(all) fun deposit(token: @{NonFungibleToken.NFT}) {
let token <- token as! @Certifily.NFT
let id: UInt64 = token.id
// add the new token to the dictionary which removes the old one
let oldToken <- self.ownedNFTs[id] <- token
emit Deposit(id: id, to: self.owner?.address)
destroy oldToken
}
// function returns token keys of owner
access(all) view fun getIDs():[UInt64] {
return self.ownedNFTs.keys
}
// function returns token data of token id
access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}? {
return (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?)
}
// Gets a reference to an NFT in the collection as a Certifily,
// exposing all of its fields.
access(all) view fun borrowCertifily(id: UInt64): &{NonFungibleToken.NFT}? {
if self.ownedNFTs[id] != nil {
// let ref = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)!
// return ref as! &Certifily.NFT
return (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?)
} else {
return nil
}
}
// function to check wether the owner have token or not
access(all) fun tokenExists(id:UInt64) : Bool {
return self.ownedNFTs[id] != nil
}
/// withdraw removes an NFT from the collection and moves it to the caller
access(NonFungibleToken.Withdraw) fun withdraw(withdrawID:UInt64) : @{NonFungibleToken.NFT} {
// let ref = (&self.ownedNFTs[withdrawID] as auth &NonFungibleToken.NFT?)!
let ref = (&self.ownedNFTs[withdrawID] as &{NonFungibleToken.NFT}?)
let val = ref as! &Certifily.NFT
if val.certType == 1 {
panic("Cert Type is not allowed to withdraw")
}
let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT")
emit Withdraw(id: token.id, from: self.owner?.address)
return <-token
}
// access(all) fun borrowViewResolver(id: UInt64): &AnyResource{MetadataViews.Resolver} {
access(all) view fun borrowViewResolver(id: UInt64): &{ViewResolver.Resolver}? {
// let nft = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)!
// let nft = (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?)
// let CertifilyNFT = nft as! &Certifily.NFT
// return CertifilyNFT as &{ViewResolver.Resolver}
if let nft = &self.ownedNFTs[id] as &{NonFungibleToken.NFT}? {
return nft as &{ViewResolver.Resolver}
}
return nil
}
// Function to add an address to viewPermission
access(all) fun addViewPermission(id: UInt64, address: [String]) {
// let ref = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)!
let ref = (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?)
let nft = ref as! &Certifily.NFT?
// Call the NFT's addViewPermission function
nft?.addViewPermission(address: address)
}
access(all) fun removeViewPermission(id: UInt64, address: String) {
// let ref = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)!
let ref = (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?)
let nft = ref as! &Certifily.NFT?
// Call the NFT's removeViewPermission function
nft?.removeViewPermission(address: address)
}
access(all) view fun hasViewPermission(id: UInt64, address: String): Bool? {
// let ref = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)!
let ref = (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?)
let nft = ref as! &Certifily.NFT?
// Check if the address has view permission
return nft?.viewPermission?.contains(address)
}
}
/// createEmptyCollection creates an empty Collection for the specified NFT type
/// and returns it to the caller so that they can own NFTs
access(all) fun createEmptyCollection(nftType: Type): @{NonFungibleToken.Collection} {
return <- create Collection()
}
/// Function that returns all the Metadata Views implemented by a Non Fungible Token
///
/// @return An array of Types defining the implemented views. This value will be used by
/// developers to know which parameter to pass to the resolveView() method.
///
access(all) view fun getContractViews(resourceType: Type?): [Type] {
return [
Type<MetadataViews.NFTCollectionData>(),
Type<MetadataViews.NFTCollectionDisplay>(),
Type<MetadataViews.EVMBridgedMetadata>()
]
}
/// Function that resolves a metadata view for this contract.
///
/// @param view: The Type of the desired view.
/// @return A structure representing the requested view.
///
access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? {
switch viewType {
case Type<MetadataViews.NFTCollectionData>():
let collectionData = MetadataViews.NFTCollectionData(
storagePath: Certifily.certifilyStoragePath,
publicPath: Certifily.certifilyPublicPath,
publicCollection: Type<&Certifily.Collection>(),
publicLinkedType: Type<&Certifily.Collection>(),
createEmptyCollectionFunction: (fun(): @{NonFungibleToken.Collection} {
return <-Certifily.createEmptyCollection(nftType: Type<@Certifily.NFT>())
})
)
return collectionData
case Type<MetadataViews.NFTCollectionDisplay>():
let media = MetadataViews.Media(
file: MetadataViews.HTTPFile(
url: "https://certifi.ly/logo512.png"
),
mediaType: "image/png+xml"
)
return MetadataViews.NFTCollectionDisplay(
name: "The Example Collection",
description: "This collection is used as an example to help you develop your next Flow NFT.",
externalURL: MetadataViews.ExternalURL("https://certifi.ly"),
squareImage: media,
bannerImage: media,
socials: {
"twitter": MetadataViews.ExternalURL("https://twitter.com/certifily")
}
)
case Type<MetadataViews.EVMBridgedMetadata>():
// Implementing this view gives the project control over how the bridged NFT is represented as an ERC721
// when bridged to EVM on Flow via the public infrastructure bridge.
// Compose the contract-level URI. In this case, the contract metadata is located on some HTTP host,
// but it could be IPFS, S3, a data URL containing the JSON directly, etc.
return MetadataViews.EVMBridgedMetadata(
name: "Certifily",
symbol: "XMPL",
uri: MetadataViews.URI(
baseURI: nil, // setting baseURI as nil sets the given value as the uri field value
value: "https://certifi.ly"
)
)
}
return nil
}
// NFT MINTER
access(all) resource NFTMinter {
access(all) fun Mint(recipient: Address,content:String, insitution:String, description:String,previewContent:String,certType:UInt8,viewPermission: [String]) : @Certifily.NFT {
let token <- create NFT(id: Certifily.totalSupply, content:content, insitution:insitution, description:description, holder: recipient,previewContent:previewContent, certType:certType, viewPermission:viewPermission)
emit Mint(id:Certifily.totalSupply,content:content,owner: recipient, insitution:insitution)
Certifily.totalSupply = Certifily.totalSupply + 1 as UInt64
return <-token
}
}
// Contract init
init() {
// total supply is zero at the time of contract deployment
self.totalSupply = 0
self.certifilyStoragePath = /storage/CertifilyNFTCollection
self.certifilyPublicPath = /public/CertifilyNFTPublicCollection
self.certifilyMinterPath = /storage/CertifilyNFTMinter
// Create a Collection resource and save it to storage
let collection <- create Collection()
self.account.storage.save(<-collection, to: self.certifilyStoragePath)
// create a public capability for the collection
let collectionCap = self.account.capabilities.storage.issue<&Certifily.Collection>(self.certifilyStoragePath)
self.account.capabilities.publish(collectionCap, at: self.certifilyPublicPath)
// store a minter resource in account storage
self.account.storage.save(<-create NFTMinter(), to: self.certifilyMinterPath)
emit ContractInitialized()
}
}
Cadence Script
1transaction(name: String, code: String ) {
2 prepare(signer: auth(AddContract) &Account) {
3 signer.contracts.add(name: name, code: code.utf8 )
4 }
5 }