Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend Lock & Swap Lock #38

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
68 changes: 59 additions & 9 deletions locked-nft/contracts/NFTLocker.cdc
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@ pub contract NFTLocker {
from: Address?,
nftType: Type
)
pub event NFTLockExtended(
id: UInt64,
lockedAt: UInt64,
lockedUntil: UInt64,
extendedDuration: UInt64,
nftType: Type
)

/// Named Paths
///
Expand All @@ -44,27 +51,31 @@ pub contract NFTLocker {
pub let id: UInt64
pub let owner: Address
pub let lockedAt: UInt64
pub let lockedUntil: UInt64
pub let duration: UInt64
pub var lockedUntil: UInt64
HouseOfHufflepuff marked this conversation as resolved.
Show resolved Hide resolved
pub let nftType: Type
pub let extension: {String: AnyStruct}
Deewai marked this conversation as resolved.
Show resolved Hide resolved

init (id: UInt64, owner: Address, duration: UInt64, nftType: Type) {
init (id: UInt64, owner: Address, duration: UInt64, nftType: Type, extension: {String: AnyStruct}) {
if let lockedToken = (NFTLocker.lockedTokens[nftType]!)[id] {
self.id = id
self.owner = lockedToken.owner
self.lockedAt = lockedToken.lockedAt
self.lockedUntil = lockedToken.lockedUntil
self.duration = lockedToken.duration
self.nftType = lockedToken.nftType
self.extension = lockedToken.extension
} else {
self.id = id
self.owner = owner
self.lockedAt = UInt64(getCurrentBlock().timestamp)
self.lockedUntil = self.lockedAt + duration
self.duration = duration
self.nftType = nftType
self.extension = extension
}
}

pub fun extendLock(extendedDuration: UInt64) {
self.lockedUntil = self.lockedUntil + extendedDuration
HouseOfHufflepuff marked this conversation as resolved.
Show resolved Hide resolved
}
}

pub fun getNFTLockerDetails(id: UInt64, nftType: Type): NFTLocker.LockedData? {
Expand All @@ -83,6 +94,14 @@ pub contract NFTLocker {
return false
}

pub fun nftIsLocked(id: UInt64, nftType: Type): Bool {
if let lockedToken = (NFTLocker.lockedTokens[nftType]!)[id] {
return true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't you need to check the lockedUntil here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Glad you asked, because my intention was to delete the token from NFTLocker.lockedTokens, so that the key does not exist & would not have a lockedUntil. But I found a bug that I fixed here.

nftIsLocked will return false when the token does not exist for the type. Added tests to support.

https://github.com/dapperlabs/studio-platform-smart-contracts/pull/38/files#diff-787282924cd2e33a1f8859a16e87a50889699486d711b3fae0720d52b147b7f7R143

}

return false
}

/// A public collection interface that returns the ids
/// of nft locked for a given type
///
Expand All @@ -95,6 +114,7 @@ pub contract NFTLocker {
pub resource interface LockProvider {
pub fun lock(token: @NonFungibleToken.NFT, duration: UInt64)
pub fun unlock(id: UInt64, nftType: Type): @NonFungibleToken.NFT
pub fun extendLock(id: UInt64, nftType: Type, extendedDuration: UInt64)
}

/// An NFT Collection
Expand All @@ -106,6 +126,10 @@ pub contract NFTLocker {
///
pub fun unlock(id: UInt64, nftType: Type): @NonFungibleToken.NFT {
pre {
NFTLocker.nftIsLocked(
id: id,
nftType: nftType
) == true : "token is not locked"
NFTLocker.canUnlockToken(
id: id,
nftType: nftType
Expand All @@ -114,8 +138,9 @@ pub contract NFTLocker {

let token <- self.lockedNFTs[nftType]?.remove(key: id)!!

if let lockedToken = NFTLocker.lockedTokens[nftType] {
lockedToken.remove(key: id)
if let lockedType = NFTLocker.lockedTokens[nftType] {
lockedType.remove(key: id)
NFTLocker.lockedTokens[nftType] = lockedType
}
NFTLocker.totalLockedTokens = NFTLocker.totalLockedTokens - 1

Expand Down Expand Up @@ -151,7 +176,8 @@ pub contract NFTLocker {
id: id,
owner: self.owner!.address,
duration: duration,
nftType: nftType
nftType: nftType,
extension: {}
)
nestedLock[id] = lockedData
NFTLocker.lockedTokens[nftType] = nestedLock
Expand All @@ -163,7 +189,7 @@ pub contract NFTLocker {
to: self.owner?.address,
lockedAt: lockedData.lockedAt,
lockedUntil: lockedData.lockedUntil,
duration: lockedData.duration,
duration: duration,
nftType: nftType
)

Expand All @@ -172,6 +198,30 @@ pub contract NFTLocker {
destroy oldToken
}

pub fun extendLock(id: UInt64, nftType: Type, extendedDuration: UInt64) {
pre {
NFTLocker.nftIsLocked(
id: id,
nftType: nftType
) == true : "token is not locked"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there could be another validation for old lockedUntil + extendedDuration > now otherwise the extension seems moot

}

let lockedToken = (NFTLocker.lockedTokens[nftType]!)[id]!
lockedToken.extendLock(extendedDuration: extendedDuration)

let nestedLock = NFTLocker.lockedTokens[nftType]!
nestedLock[id] = lockedToken
NFTLocker.lockedTokens[nftType] = nestedLock

emit NFTLockExtended(
id: id,
lockedAt: lockedToken.lockedAt,
lockedUntil: lockedToken.lockedUntil,
extendedDuration: extendedDuration,
nftType: nftType
)
}

pub fun getIDs(nftType: Type): [UInt64]? {
return self.lockedNFTs[nftType]?.keys
}
Expand Down