Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
188 changes: 188 additions & 0 deletions cadence/contracts/Tidal.cdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
import "FungibleToken"
import "Burner"
import "ViewResolver"

import "DFB"

///
/// THIS CONTRACT IS A MOCK AND IS NOT INTENDED FOR USE IN PRODUCTION
/// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
///
access(all) contract Tidal {

access(all) let TideManagerStoragePath: StoragePath
access(all) let TideManagerPublicPath: PublicPath

access(all) event CreatedTide(id: UInt64, initialAmount: UFix64, creator: Address?)
access(all) event DepositedToTide(id: UInt64, amount: UFix64, owner: Address?, fromUUID: UInt64)
access(all) event WithdrawnFromTide(id: UInt64, amount: UFix64, owner: Address?, toUUID: UInt64)
access(all) event AddedToManager(id: UInt64, owner: Address?, managerUUID: UInt64)
access(all) event BurnedTide(id: UInt64, remainingBalance: UFix64)

access(self) var currentIdentifier: UInt64

access(all) fun createTideManager(): @TideManager {
return <-create TideManager()
}

/* --- CONSTRUCTS --- */

access(all) struct UniqueID : DFB.UniqueIdentifier {
access(all) let id: UInt64
init() {
self.id = Tidal.currentIdentifier
Tidal.currentIdentifier = Tidal.currentIdentifier + 1
}
}

access(all) resource Tide : Burner.Burnable, FungibleToken.Receiver, FungibleToken.Provider, ViewResolver.Resolver {
access(contract) let uniqueID: {DFB.UniqueIdentifier}
access(self) let vault: @{FungibleToken.Vault}

init(_ vault: @{FungibleToken.Vault}) {
self.vault <- vault
self.uniqueID = UniqueID()
}

access(all) view fun id(): UInt64 {
return self.uniqueID.id
}

access(all) view fun getTideBalance(): UFix64 {
return self.vault.balance
}

access(contract) fun burnCallback() {
emit BurnedTide(id: self.uniqueID.id, remainingBalance: self.vault.balance)
}

access(all) view fun getViews(): [Type] {
return []
}

access(all) fun resolveView(_ view: Type): AnyStruct? {
return nil
}

access(all) fun deposit(from: @{FungibleToken.Vault}) {
pre {
self.isSupportedVaultType(type: from.getType()):
"Deposited vault of type \(from.getType().identifier) is not supported by this Tide"
}
emit DepositedToTide(id: self.uniqueID.id, amount: from.balance, owner: self.owner?.address, fromUUID: from.uuid)
self.vault.deposit(from: <-from)
}

access(all) view fun getSupportedVaultTypes(): {Type: Bool} {
return { self.vault.getType() : true }
}


access(all) view fun isSupportedVaultType(type: Type): Bool {
return self.getSupportedVaultTypes()[type] ?? false
}

access(all) view fun isAvailableToWithdraw(amount: UFix64): Bool {
return amount <= self.vault.balance
}

access(FungibleToken.Withdraw) fun withdraw(amount: UFix64): @{FungibleToken.Vault} {
pre {
self.isAvailableToWithdraw(amount: amount):
"Requested amount \(amount) is greater than withdrawable balance of \(self.vault.balance)"
}
let res <- self.vault.withdraw(amount: amount)
emit WithdrawnFromTide(id: self.uniqueID.id, amount: amount, owner: self.owner?.address, toUUID: res.uuid)
return <- res
}
}

access(all) entitlement Owner

access(all) resource TideManager : ViewResolver.ResolverCollection {
access(self) let tides: @{UInt64: Tide}

init() {
self.tides <- {}
}

access(all) view fun borrowTide(id: UInt64): &Tide? {
return &self.tides[id]
}

access(all) view fun borrowViewResolver(id: UInt64): &{ViewResolver.Resolver}? {
return &self.tides[id]
}

access(all) view fun getIDs(): [UInt64] {
return self.tides.keys
}

access(all) view fun getNumberOfTides(): Int {
return self.tides.length
}

access(all) fun createTide(withVault: @{FungibleToken.Vault}) {
let balance = withVault.balance
let tide <-create Tide(<-withVault)

emit CreatedTide(id: tide.uniqueID.id, initialAmount: balance, creator: self.owner?.address)

self.addTide(<-tide)
}

access(all) fun addTide(_ tide: @Tide) {
pre {
self.tides[tide.uniqueID.id] == nil:
"Collision with Tide ID \(tide.uniqueID.id) - a Tide with this ID already exists"
}
emit AddedToManager(id: tide.uniqueID.id, owner: self.owner?.address, managerUUID: self.uuid)
self.tides[tide.uniqueID.id] <-! tide
}

access(all) fun depositToTide(_ id: UInt64, from: @{FungibleToken.Vault}) {
pre {
self.tides[id] != nil:
"No Tide with ID \(id) found"
}
let tide = (&self.tides[id] as &Tide?)!
tide.deposit(from: <-from)
}

access(Owner) fun withdrawTide(id: UInt64): @Tide {
pre {
self.tides[id] != nil:
"No Tide with ID \(id) found"
}
return <- self.tides.remove(key: id)!
}

access(Owner) fun withdrawFromTide(_ id: UInt64, amount: UFix64): @{FungibleToken.Vault} {
pre {
self.tides[id] != nil:
"No Tide with ID \(id) found"
}
let tide = (&self.tides[id] as auth(FungibleToken.Withdraw) &Tide?)!
return <- tide.withdraw(amount: amount)
}

access(Owner) fun closeTide(_ id: UInt64): @{FungibleToken.Vault} {
pre {
self.tides[id] != nil:
"No Tide with ID \(id) found"
}
let tide <- self.withdrawTide(id: id)
let res <- tide.withdraw(amount: tide.getTideBalance())
Burner.burn(<-tide)
return <-res
}
}

init() {
let pathIdentifier = "TidalTideManager_\(self.account.address)"
self.TideManagerStoragePath = StoragePath(identifier: pathIdentifier)!
self.TideManagerPublicPath = PublicPath(identifier: pathIdentifier)!

self.currentIdentifier = 0
}
}
9 changes: 9 additions & 0 deletions cadence/contracts/internal-dependencies/interfaces/DFB.cdc
Original file line number Diff line number Diff line change
Expand Up @@ -193,4 +193,13 @@ access(all) contract DFB {
}
}
}

/// An interface for a price oracle adapter. Implementations should adapt this interface to various price feed
/// oracles deployed on Flow
access(all) struct interface PriceOracle {
/// Returns the asset type serving as the price basis - e.g. USD in FLOW/USD
access(all) view fun unitOfAccount(): Type
/// Returns the latest price data for a given asset denominated in unitOfAccount()
access(all) fun price(ofToken: Type): UFix64
}
}
Loading