Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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
4 changes: 0 additions & 4 deletions cadence/contracts/actions/FlowActions.cdc

This file was deleted.

52 changes: 52 additions & 0 deletions cadence/contracts/actions/FlowActionsIdea.cdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import "FungibleToken"

// -----------------------------------------------------------------------------
// ⚠️ DISCLAIMER — DRAFT / SUBJECT TO CHANGE
// -----------------------------------------------------------------------------
// The `Swapper` interface and helpers in this contract are placeholders
// needed only to wire up the FlowYieldVaults lending-strategy prototype.
// Signatures, semantics, and the set of methods will change once the real
// actions design lands. `getEmptyVault` in particular is explicitly unsafe —
// see the comment on it. Do not build on this contract outside of this repo.
// -----------------------------------------------------------------------------

access(all) contract FlowActionsIdea {

// This is the typical EVM interface translated to cadence.
// Necessary to setup FlowYieldVaults structure.
access(all) struct interface Swapper {
access(all) token0: Type
access(all) token1: Type
access(all) fee: UInt32

/// Exact Input: "I have this many tokens, give me whatever they are worth"
view access(all) fun quoteExactInput(
zeroForOne: Bool,
amountIn: UFix64
): UFix64

/// Exact Output: "I want exactly this many tokens, how much do I need to pay?"
view access(all) fun quoteExactOutput(
zeroForOne: Bool,
amountOut: UFix64
): UFix64

access(all) fun swap(
zeroForOne: Bool,
inVault: @{FungibleToken.Vault}
): @{FungibleToken.Vault}
}

/// This is dangerous!! if a 3rd party provides a type and we are executing
/// createEmptyVault any code can be run. (reentrancy, etc)
access(all) fun getEmptyVault(_ vaultType: Type): @{FungibleToken.Vault} {
post {
result.getType() == vaultType:
"Invalid Vault returned - expected \(vaultType.identifier) but returned \(result.getType().identifier)"
}
return <- getAccount(vaultType.address!)
.contracts
.borrow<&{FungibleToken}>(name: vaultType.contractName!)!
.createEmptyVault(vaultType: vaultType)
}
}
61 changes: 60 additions & 1 deletion cadence/contracts/alp/FlowALP.cdc
Original file line number Diff line number Diff line change
@@ -1,4 +1,63 @@
import "FungibleToken"
import "FlowActionsIdea"
import "FlowALPInterfaceIdea"
import "FlowALPTypesIdea"

access(all) contract FlowALP {
// -----------------------------------------------------------------------------
// ⚠️ DISCLAIMER — DRAFT / SUBJECT TO CHANGE
// -----------------------------------------------------------------------------
// This is a placeholder ALP implementation that exists only to unblock the
// FlowYieldVaults lending-strategy prototype. Every method is a stub — the
// real lending-market logic will replace this whole contract. Do not build on
// it outside of this repo.
// -----------------------------------------------------------------------------

access(all) contract FlowALP: FlowALPInterfaceIdea {

access(all) resource Position: FlowALPInterfaceIdea.ALPPosition {
access(all) fun deposit(from: @{FungibleToken.Vault}) {
destroy from
}

access(all) fun withdraw(type: Type, amount: UFix64): @{FungibleToken.Vault} {
let _ = amount
return <- FlowActionsIdea.getEmptyVault(type)
}

access(all) view fun depositRequiredForMinHealth(type: Type, minHealth: UFix64): UFix64 {
let _t = type
let _h = minHealth
return 0.0
}

access(all) view fun withdrawRequiredForMaxHealth(type: Type, maxHealth: UFix64): UFix64 {
let _t = type
let _h = maxHealth
return 0.0
}

access(all) view fun withdrawPossibleWithDeposit(type: Type, depositAmount: UFix64, maxHealth: UFix64): UFix64 {
let _t = type
let _d = depositAmount
let _h = maxHealth
return 0.0
}

access(all) view fun debtRepaymentForCollateralWithdrawal(debtType: Type, collateralType: Type, collateralAmount: UFix64, targetHealth: UFix64): UFix64 {
let _d = debtType
let _ct = collateralType
let _c = collateralAmount
let _h = targetHealth
return 0.0
}

access(all) view fun positionData(type: Type): FlowALPTypesIdea.TokenData {
let _ = type
return FlowALPTypesIdea.TokenData(amount: 0.0, direction: FlowALPTypesIdea.Direction.Collateral)
}
}

access(account) fun createPosition(): @{FlowALPInterfaceIdea.ALPPosition} {
return <- create Position()
}
}
19 changes: 19 additions & 0 deletions cadence/contracts/alp/FlowALPHealthWatcher.cdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import "FlowALPHealthWatcherIdea"

// -----------------------------------------------------------------------------
// ⚠️ DISCLAIMER — DRAFT / SUBJECT TO CHANGE
// -----------------------------------------------------------------------------
// This is a placeholder health-watcher implementation that exists only to
// unblock the FlowYieldVaults lending-strategy prototype. The real watcher
// semantics (registration, triggering, callbacks) will replace this whole
// contract. Do not build on it outside of this repo.
// -----------------------------------------------------------------------------

access(all) contract FlowALPHealthWatcher {

access(all) resource Watcher: FlowALPHealthWatcherIdea.Watcher {}

access(all) fun createWatcher(): @Watcher {
return <- create Watcher()
}
}
19 changes: 19 additions & 0 deletions cadence/contracts/alp/FlowALPHealthWatcherIdea.cdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// -----------------------------------------------------------------------------
// ⚠️ DISCLAIMER — DRAFT / SUBJECT TO CHANGE
// -----------------------------------------------------------------------------
// This contract is a placeholder shim needed only to wire up the
// FlowYieldVaults lending-strategy prototype. The `Callback` and `Watcher`
// shapes will change once the real ALP health-monitoring design lands.
// Do not build on this contract outside of this repo.
// -----------------------------------------------------------------------------

access(all) contract interface FlowALPHealthWatcherIdea {

access(all) struct interface Callback {
access(all) fun healthWatcherCallback()
}

access(all) resource interface Watcher {}

access(contract) fun createWatcher(): @{Watcher}
}
40 changes: 40 additions & 0 deletions cadence/contracts/alp/FlowALPInterfaceIdea.cdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import "FungibleToken"
import "FlowALPTypesIdea"

// -----------------------------------------------------------------------------
// ⚠️ DISCLAIMER — DRAFT / SUBJECT TO CHANGE
// -----------------------------------------------------------------------------
// This interface is a placeholder shim so the FlowYieldVaults lending-strategy
// prototype has something to talk to. Method signatures, return types, and the
// set of methods themselves will change once the real ALP design lands. It
// exists today only to let the yield-vaults layer compile and be tested.
// Do not build on this interface outside of this repo.
// -----------------------------------------------------------------------------

access(all) contract interface FlowALPInterfaceIdea {

access(all) resource interface ALPPosition {
access(all) fun deposit(from: @{FungibleToken.Vault})
access(all) fun withdraw(type: Type, amount: UFix64): @{FungibleToken.Vault}

/// Amount of `type` to DEPOSIT/REPAY to bring health back up to `minHealth`.
/// Returns 0.0 if health is already at or above `minHealth`.
view access(all) fun depositRequiredForMinHealth(type: Type, minHealth: UFix64): UFix64

/// Amount of `type` available to WITHDRAW/BORROW while keeping health at `maxHealth`.
/// Returns 0.0 if health is already at or below `maxHealth`.
view access(all) fun withdrawRequiredForMaxHealth(type: Type, maxHealth: UFix64): UFix64

view access(all) fun withdrawPossibleWithDeposit(type: Type, depositAmount: UFix64, maxHealth: UFix64): UFix64


/// Debt repayment required to offset a planned collateral withdrawal
/// while maintaining `targetHealth`.
view access(all) fun debtRepaymentForCollateralWithdrawal(debtType: Type, collateralType: Type, collateralAmount: UFix64, targetHealth: UFix64): UFix64

/// Current balance and direction (collateral vs debt) for `type`.
view access(all) fun positionData(type: Type): FlowALPTypesIdea.TokenData
}

access(account) fun createPosition(): @{ALPPosition}
}
26 changes: 26 additions & 0 deletions cadence/contracts/alp/FlowALPTypesIdea.cdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// -----------------------------------------------------------------------------
// ⚠️ DISCLAIMER — DRAFT / SUBJECT TO CHANGE
// -----------------------------------------------------------------------------
// These types are placeholders used only to unblock the FlowYieldVaults
// lending-strategy prototype. The enum, struct, and their field shapes will
// almost certainly change once the real ALP design lands. Do not build on
// them outside of this repo.
// -----------------------------------------------------------------------------

access(all) contract FlowALPTypesIdea {

access(all) enum Direction: UInt8 {
access(all) case Collateral
access(all) case Debt
}

access(all) struct TokenData {
access(all) let amount: UFix64
access(all) let direction: Direction

view init(amount: UFix64, direction: Direction) {
self.amount = amount
self.direction = direction
}
}
}
105 changes: 104 additions & 1 deletion cadence/contracts/yield_vaults/FlowYieldVaults.cdc
Original file line number Diff line number Diff line change
@@ -1,4 +1,107 @@
import "FlowYieldVaultsInterfaces"

access(all) contract FlowYieldVaults {
/// Registry of yield vault strategies on this account, keyed by name.
/// An `Admin` resource (saved at `adminStoragePath` on the contract account)
/// registers and removes strategies conforming to
/// `FlowYieldVaultsInterfaces.Strategy`. Yield vaults are minted from a
/// registered strategy by `name` through `createYieldVault`.
///
/// This contract is strategy-agnostic: it does not depend on any specific
/// strategy family. Concrete strategies live in their own contracts and are
/// plugged in through `Admin.registerStrategy`.
access(all) contract FlowYieldVaults: FlowYieldVaultsInterfaces {

/// Emitted when a strategy is registered under `name`.
access(all) event StrategyCreated(name: String)
/// Emitted when a strategy is removed from the registry.
access(all) event StrategyRemoved(name: String)
/// Emitted when a yield vault is minted from the named strategy.
access(all) event StrategyVaultCreated(name: String)

/// Storage path where the `Admin` resource is saved on this account.
access(all) let adminStoragePath: StoragePath

/// Registered strategies, keyed by name. Names are unique; registering
/// an already-used name panics.
access(self) let strategies: {String: {FlowYieldVaultsInterfaces.Strategy}}

/// Admin resource; holder may register / remove strategies and mint
/// yield vaults directly (bypassing any external access gate).
access(all) resource Admin {
/// Registers `strategy` under `name`.
/// Panics if a strategy is already registered under that name.
///
/// **Parameters**
/// - `name`: Unique identifier for the strategy in this registry.
/// - `strategy`: Any value conforming to
/// `FlowYieldVaultsInterfaces.Strategy`.
access(all) fun registerStrategy(
name: String,
strategy: {FlowYieldVaultsInterfaces.Strategy}
) {
assert(
FlowYieldVaults.strategies[name] == nil,
message: "Strategy already registered: \(name)"
)
FlowYieldVaults.strategies[name] = strategy
emit StrategyCreated(name: name)
}

/// Removes the strategy registered under `name`.
/// Panics if no strategy is registered under that name. Does not
/// affect already-minted yield vaults — those captured the strategy
/// parameters at creation time.
///
/// **Parameters**
/// - `name`: Name of the strategy to remove.
access(all) fun removeStrategy(name: String) {
let strategy = FlowYieldVaults.strategies.remove(key: name)
if strategy == nil {
panic("Strategy not found")
}
emit StrategyRemoved(name: name)
}

/// Mints a yield vault from a registered strategy.
/// Wrapper around the contract-level `createYieldVault`
/// for callers that hold the admin resource.
///
/// **Parameters**
/// - `name`: Name of the registered strategy.
///
/// **Returns** A new `YieldVault` for the caller to save in storage.
access(all) fun createYieldVault(name: String): @{FlowYieldVaultsInterfaces.YieldVault} {
return <- FlowYieldVaults.createYieldVault(name: name)
}
}

/// Mints a yield vault from a registered strategy.
/// Panics if no strategy is registered under `name`.
/// `access(account)` so that only contracts on this account (e.g.
/// `FlowYieldVaultsEarlyAccess`) can gate or invoke vault creation.
///
/// **Parameters**
/// - `name`: Name of the registered strategy.
///
/// **Returns** A new `YieldVault` for the caller to save in storage.
access(account) fun createYieldVault(name: String): @{FlowYieldVaultsInterfaces.YieldVault} {
let strategy = self.strategies[name] ?? panic("Strategy not found")
let vault <- strategy.createYieldVault(name: name)
emit StrategyVaultCreated(name: name)
return <- vault
}

view access(all) fun strategyCount(): UInt64 {
return UInt64(self.strategies.length)
}

view access(all) fun strategyNames(): [String] {
return self.strategies.keys
}

init() {
self.strategies = {}
self.adminStoragePath = StoragePath(identifier: "FlowYieldVaultsAdmin")!
self.account.storage.save(<- create Admin(), to: self.adminStoragePath)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,14 @@ access(all) contract FlowYieldVaultsEarlyAccess {
/// Panics if allowance is exhausted.
///
/// **Parameters**
/// - `strategyID`: Identifies the vault strategy to create.
/// - `name`: Name of the registered strategy to create a vault for.
///
/// **Returns** A new `YieldVault` to be saved in the caller's storage.
access(all) fun createYieldVault(strategyID: UInt64): @{FlowYieldVaultsInterfaces.YieldVault} {
access(all) fun createYieldVault(name: String): @{FlowYieldVaultsInterfaces.YieldVault} {
pre { self.remainingAllowance > 0: "No remaining allowance" }
self.remainingAllowance = self.remainingAllowance - 1
let fyv = FlowYieldVaultsEarlyAccess.getFlowYieldVaultsContract()
let vault <- fyv.createYieldVault(strategyID: strategyID)
let vault <- fyv.createYieldVault(name: name)
emit PassUsed(passUUID: self.uuid, remainingAllowance: self.remainingAllowance)
return <- vault
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import "FungibleToken"
access(all) contract interface FlowYieldVaultsInterfaces {

access(all) struct interface Strategy {
access(all) fun createYieldVault(strategyID: UInt64): @{YieldVault}
access(all) fun createYieldVault(name: String): @{YieldVault}
}

access(all) resource interface YieldVault: FungibleToken.Provider, FungibleToken.Receiver {}

access(account) fun createYieldVault(strategyID: UInt64): @{YieldVault}
access(account) fun createYieldVault(name: String): @{YieldVault}
}
Loading