-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
d808d82
commit 5d838b2
Showing
7 changed files
with
310 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
import "FungibleToken" | ||
import "StringUtils" | ||
|
||
// ScopedFTProviders | ||
// | ||
// TO AVOID RISK, PLEASE DEPLOY YOUR OWN VERSION OF THIS CONTRACT SO THAT | ||
// MALICIOUS UPDATES ARE NOT POSSIBLE | ||
// | ||
// ScopedProviders are meant to solve the issue of unbounded access FungibleToken vaults | ||
// when a provider is called for. | ||
pub contract ScopedFTProviders { | ||
pub struct interface FTFilter { | ||
pub fun canWithdrawAmount(_ amount: UFix64): Bool | ||
pub fun markAmountWithdrawn(_ amount: UFix64) | ||
pub fun getDetails(): {String: AnyStruct} | ||
} | ||
|
||
pub struct AllowanceFilter: FTFilter { | ||
access(self) let allowance: UFix64 | ||
access(self) var allowanceUsed: UFix64 | ||
|
||
init(_ allowance: UFix64) { | ||
self.allowance = allowance | ||
self.allowanceUsed = 0.0 | ||
} | ||
|
||
pub fun canWithdrawAmount(_ amount: UFix64): Bool { | ||
return amount + self.allowanceUsed <= self.allowance | ||
} | ||
|
||
pub fun markAmountWithdrawn(_ amount: UFix64) { | ||
self.allowanceUsed = self.allowanceUsed + amount | ||
} | ||
|
||
pub fun getDetails(): {String: AnyStruct} { | ||
return { | ||
"allowance": self.allowance, | ||
"allowanceUsed": self.allowanceUsed | ||
} | ||
} | ||
} | ||
|
||
// ScopedFTProvider | ||
// | ||
// A ScopedFTProvider is a wrapped FungibleTokenProvider with | ||
// filters that can be defined by anyone using the ScopedFTProvider. | ||
pub resource ScopedFTProvider: FungibleToken.Provider { | ||
access(self) let provider: Capability<&{FungibleToken.Provider}> | ||
access(self) var filters: [{FTFilter}] | ||
|
||
// block timestamp that this provider can no longer be used after | ||
access(self) let expiration: UFix64? | ||
|
||
pub init(provider: Capability<&{FungibleToken.Provider}>, filters: [{FTFilter}], expiration: UFix64?) { | ||
self.provider = provider | ||
self.filters = filters | ||
self.expiration = expiration | ||
} | ||
|
||
pub fun check(): Bool { | ||
return self.provider.check() | ||
} | ||
|
||
pub fun isExpired(): Bool { | ||
if let expiration = self.expiration { | ||
return getCurrentBlock().timestamp >= expiration | ||
} | ||
return false | ||
} | ||
|
||
pub fun canWithdraw(_ amount: UFix64): Bool { | ||
if self.isExpired() { | ||
return false | ||
} | ||
|
||
for filter in self.filters { | ||
if !filter.canWithdrawAmount(amount) { | ||
return false | ||
} | ||
} | ||
|
||
return true | ||
} | ||
|
||
pub fun withdraw(amount: UFix64): @FungibleToken.Vault { | ||
pre { | ||
!self.isExpired(): "provider has expired" | ||
} | ||
|
||
var i = 0 | ||
while i < self.filters.length { | ||
if !self.filters[i].canWithdrawAmount(amount) { | ||
panic(StringUtils.join(["cannot withdraw tokens. filter of type", self.filters[i].getType().identifier, "failed."], " ")) | ||
} | ||
|
||
self.filters[i].markAmountWithdrawn(amount) | ||
i = i + 1 | ||
} | ||
|
||
return <-self.provider.borrow()!.withdraw(amount: amount) | ||
} | ||
|
||
pub fun getDetails(): [{String: AnyStruct}] { | ||
let details: [{String: AnyStruct}] = [] | ||
for filter in self.filters { | ||
details.append(filter.getDetails()) | ||
} | ||
|
||
return details | ||
} | ||
} | ||
|
||
pub fun createScopedFTProvider( | ||
provider: Capability<&{FungibleToken.Provider}>, | ||
filters: [{FTFilter}], | ||
expiration: UFix64? | ||
): @ScopedFTProvider { | ||
return <- create ScopedFTProvider(provider: provider, filters: filters, expiration: expiration) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
import "NonFungibleToken" | ||
import "StringUtils" | ||
|
||
// ScopedNFTProviders | ||
// | ||
// TO AVOID RISK, PLEASE DEPLOY YOUR OWN VERSION OF THIS CONTRACT SO THAT | ||
// MALICIOUS UPDATES ARE NOT POSSIBLE | ||
// | ||
// ScopedNFTProviders are meant to solve the issue of unbounded access to NFT Collections. | ||
// A provider can be given extensible filters which allow limited access to resources based on any trait on the NFT itself. | ||
// | ||
// By using a scoped provider, only a subset of assets can be taken if the provider leaks | ||
// instead of the entire nft collection. | ||
pub contract ScopedNFTProviders { | ||
pub struct interface NFTFilter { | ||
pub fun canWithdraw(_ nft: &NonFungibleToken.NFT): Bool | ||
pub fun markWithdrawn(_ nft: &NonFungibleToken.NFT) | ||
pub fun getDetails(): {String: AnyStruct} | ||
} | ||
|
||
pub struct NFTIDFilter: NFTFilter { | ||
// the ids that are allowed to be withdrawn. | ||
// If ids[num] is false, the id cannot be withdrawn anymore | ||
access(self) let ids: {UInt64: Bool} | ||
|
||
init(_ ids: [UInt64]) { | ||
let d: {UInt64: Bool} = {} | ||
for i in ids { | ||
d[i] = true | ||
} | ||
self.ids = d | ||
} | ||
|
||
pub fun canWithdraw(_ nft: &NonFungibleToken.NFT): Bool { | ||
return self.ids[nft.id] != nil && self.ids[nft.id] == true | ||
} | ||
|
||
pub fun markWithdrawn(_ nft: &NonFungibleToken.NFT) { | ||
self.ids[nft.id] = false | ||
} | ||
|
||
pub fun getDetails(): {String: AnyStruct} { | ||
return { | ||
"ids": self.ids | ||
} | ||
} | ||
} | ||
|
||
pub struct UUIDFilter: NFTFilter { | ||
// the ids that are allowed to be withdrawn. | ||
// If ids[num] is false, the id cannot be withdrawn anymore | ||
access(self) let uuids: {UInt64: Bool} | ||
|
||
init(_ uuids: [UInt64]) { | ||
let d: {UInt64: Bool} = {} | ||
for i in uuids { | ||
d[i] = true | ||
} | ||
self.uuids = d | ||
} | ||
|
||
pub fun canWithdraw(_ nft: &NonFungibleToken.NFT): Bool { | ||
return self.uuids[nft.uuid] != nil && self.uuids[nft.uuid]! == true | ||
} | ||
|
||
pub fun markWithdrawn(_ nft: &NonFungibleToken.NFT) { | ||
self.uuids[nft.uuid] = false | ||
} | ||
|
||
pub fun getDetails(): {String: AnyStruct} { | ||
return { | ||
"uuids": self.uuids | ||
} | ||
} | ||
} | ||
|
||
// ScopedNFTProvider | ||
// | ||
// Wrapper around an NFT Provider that is restricted to specific ids. | ||
pub resource ScopedNFTProvider: NonFungibleToken.Provider { | ||
access(self) let provider: Capability<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic}> | ||
access(self) let filters: [{NFTFilter}] | ||
|
||
// block timestamp that this provider can no longer be used after | ||
access(self) let expiration: UFix64? | ||
|
||
pub fun isExpired(): Bool { | ||
if let expiration = self.expiration { | ||
return getCurrentBlock().timestamp >= expiration | ||
} | ||
return false | ||
} | ||
|
||
pub init(provider: Capability<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic}>, filters: [{NFTFilter}], expiration: UFix64?) { | ||
self.provider = provider | ||
self.expiration = expiration | ||
self.filters = filters | ||
} | ||
|
||
pub fun canWithdraw(_ id: UInt64): Bool { | ||
if self.isExpired() { | ||
return false | ||
} | ||
|
||
let nft = self.provider.borrow()!.borrowNFT(id: id) | ||
if nft == nil { | ||
return false | ||
} | ||
|
||
var i = 0 | ||
while i < self.filters.length { | ||
if !self.filters[i].canWithdraw(nft) { | ||
return false | ||
} | ||
i = i + 1 | ||
} | ||
return true | ||
} | ||
|
||
pub fun check(): Bool { | ||
return self.provider.check() | ||
} | ||
|
||
pub fun withdraw(withdrawID: UInt64): @NonFungibleToken.NFT { | ||
pre { | ||
!self.isExpired(): "provider has expired" | ||
} | ||
|
||
let nft <- self.provider.borrow()!.withdraw(withdrawID: withdrawID) | ||
let ref = &nft as &NonFungibleToken.NFT | ||
|
||
var i = 0 | ||
while i < self.filters.length { | ||
if !self.filters[i].canWithdraw(ref) { | ||
panic(StringUtils.join(["cannot withdraw nft. filter of type", self.filters[i].getType().identifier, "failed."], " ")) | ||
} | ||
|
||
self.filters[i].markWithdrawn(ref) | ||
i = i + 1 | ||
} | ||
|
||
return <-nft | ||
} | ||
|
||
pub fun getDetails(): [{String: AnyStruct}] { | ||
let details: [{String: AnyStruct}] = [] | ||
for f in self.filters { | ||
details.append(f.getDetails()) | ||
} | ||
|
||
return details | ||
} | ||
} | ||
|
||
pub fun createScopedNFTProvider( | ||
provider: Capability<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic}>, | ||
filters: [{NFTFilter}], | ||
expiration: UFix64? | ||
): @ScopedNFTProvider { | ||
return <- create ScopedNFTProvider(provider: provider, filters: filters, expiration: expiration) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters