github.com/DapperCollectives/CAST/backend@v0.0.0-20230921221157-1350c8be7c96/main/cadence/nba/TopShotLocking.cdc (about)

     1  import NonFungibleToken from 0xf8d6e0586b0a20c7
     2  
     3  pub contract TopShotLocking {
     4  
     5      // -----------------------------------------------------------------------
     6      // TopShotLocking contract Events
     7      // -----------------------------------------------------------------------
     8  
     9      // Emitted when a Moment is locked
    10      pub event MomentLocked(id: UInt64, duration: UFix64, expiryTimestamp: UFix64)
    11  
    12      // Emitted when a Moment is unlocked
    13      pub event MomentUnlocked(id: UInt64)
    14  
    15      // Dictionary of locked NFTs
    16      // TopShot nft resource id is the key
    17      // locked until timestamp is the value
    18      access(self) var lockedNFTs: {UInt64: UFix64}
    19  
    20      // Dictionary of NFTs overridden to be unlocked
    21      access(self) var unlockableNFTs: {UInt64: Bool} // nft resource id is the key
    22  
    23      // isLocked Returns a boolean indicating if an nft exists in the lockedNFTs dictionary
    24      //
    25      // Parameters: nftRef: A reference to the NFT resource
    26      //
    27      // Returns: true if NFT is locked
    28      pub fun isLocked(nftRef: &NonFungibleToken.NFT): Bool {
    29          return self.lockedNFTs.containsKey(nftRef.id)
    30      }
    31  
    32      // getLockExpiry Returns the unix timestamp when an nft is unlockable
    33      //
    34      // Parameters: nftRef: A reference to the NFT resource
    35      //
    36      // Returns: unix timestamp
    37      pub fun getLockExpiry(nftRef: &NonFungibleToken.NFT): UFix64 {
    38          if !self.lockedNFTs.containsKey(nftRef.id) {
    39              panic("NFT is not locked")
    40          }
    41          return self.lockedNFTs[nftRef.id]!
    42      }
    43  
    44      // lockNFT Takes an NFT resource and adds its unique identifier to the lockedNFTs dictionary
    45      //
    46      // Parameters: nft: NFT resource
    47      //             duration: number of seconds the NFT will be locked for
    48      //
    49      // Returns: the NFT resource
    50      pub fun lockNFT(nft: @NonFungibleToken.NFT, duration: UFix64): @NonFungibleToken.NFT {
    51          let TopShotNFTType: Type = CompositeType("A.TOPSHOTADDRESS.TopShot.NFT")!
    52          if !nft.isInstance(TopShotNFTType) {
    53              panic("NFT is not a TopShot NFT")
    54          }
    55  
    56          if self.lockedNFTs.containsKey(nft.id) {
    57              // already locked - short circuit and return the nft
    58              return <- nft
    59          }
    60  
    61          let expiryTimestamp = getCurrentBlock().timestamp + duration
    62  
    63          self.lockedNFTs[nft.id] = expiryTimestamp
    64  
    65          emit MomentLocked(id: nft.id, duration: duration, expiryTimestamp: expiryTimestamp)
    66  
    67          return <- nft
    68      }
    69  
    70      // unlockNFT Takes an NFT resource and removes it from the lockedNFTs dictionary
    71      //
    72      // Parameters: nft: NFT resource
    73      //
    74      // Returns: the NFT resource
    75      //
    76      // NFT must be eligible for unlocking by an admin
    77      pub fun unlockNFT(nft: @NonFungibleToken.NFT): @NonFungibleToken.NFT {
    78          if !self.lockedNFTs.containsKey(nft.id) {
    79              // nft is not locked, short circuit and return the nft
    80              return <- nft
    81          }
    82  
    83          let lockExpiryTimestamp: UFix64 = self.lockedNFTs[nft.id]!
    84          let isPastExpiry: Bool = getCurrentBlock().timestamp >= lockExpiryTimestamp
    85  
    86          let isUnlockableOverridden: Bool = self.unlockableNFTs.containsKey(nft.id)
    87  
    88          if !(isPastExpiry || isUnlockableOverridden) {
    89              panic("NFT is not eligible to be unlocked, expires at ".concat(lockExpiryTimestamp.toString()))
    90          }
    91  
    92          self.unlockableNFTs.remove(key: nft.id)
    93          self.lockedNFTs.remove(key: nft.id)
    94  
    95          emit MomentUnlocked(id: nft.id)
    96  
    97          return <- nft
    98      }
    99  
   100      // getIDs Returns the ids of all locked Top Shot NFT tokens
   101      //
   102      // Returns: array of ids
   103      //
   104      pub fun getIDs(): [UInt64] {
   105          return self.lockedNFTs.keys
   106      }
   107  
   108      // getExpiry Returns the timestamp when a locked token is eligible for unlock
   109      //
   110      // Parameters: tokenID: the nft id of the locked token
   111      //
   112      // Returns: a unix timestamp in seconds
   113      //
   114      pub fun getExpiry(tokenID: UInt64): UFix64? {
   115          return self.lockedNFTs[tokenID]
   116      }
   117  
   118      // getLockedNFTsLength Returns the count of locked tokens
   119      //
   120      // Returns: an integer containing the number of locked tokens
   121      //
   122      pub fun getLockedNFTsLength(): Int {
   123          return self.lockedNFTs.length
   124      }
   125  
   126      // Admin is a special authorization resource that 
   127      // allows the owner to override the lock on a moment
   128      //
   129      pub resource Admin {
   130          // createNewAdmin creates a new Admin resource
   131          //
   132          pub fun createNewAdmin(): @Admin {
   133              return <-create Admin()
   134          }
   135  
   136          // markNFTUnlockable marks a given nft as being
   137          // unlockable, overridding the expiry timestamp
   138          // the nft owner will still need to send an unlock transaction to unlock
   139          //
   140          pub fun markNFTUnlockable(nftRef: &NonFungibleToken.NFT) {
   141              TopShotLocking.unlockableNFTs[nftRef.id] = true
   142          }
   143  
   144          // unlocks all NFTs
   145          pub fun unlockAll() {
   146              TopShotLocking.lockedNFTs = {}
   147              TopShotLocking.unlockableNFTs = {}
   148          }
   149      }
   150  
   151      // -----------------------------------------------------------------------
   152      // TopShotLocking initialization function
   153      // -----------------------------------------------------------------------
   154      //
   155      init() {
   156          self.lockedNFTs = {}
   157          self.unlockableNFTs = {}
   158  
   159          // Create a single admin resource
   160          let admin <- create Admin()
   161  
   162          // Store it in private account storage in `init` so only the admin can use it
   163          self.account.save(<-admin, to: /storage/TopShotLockingAdmin)
   164      }
   165  }