Skip to content

Commit af074d6

Browse files
committed
Add FlowYieldVaults structure
1 parent 4869dd6 commit af074d6

23 files changed

Lines changed: 674 additions & 58 deletions
Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,44 @@
1+
import "FungibleToken"
12

23
access(all) contract FlowActions {
34

4-
}
5+
// Interfaces are not fixed and still under development.
6+
// This is the typical EVM interface translated to cadence.
7+
// Necessary to setup FlowYieldVaults structure.
8+
access(all) struct interface Swapper {
9+
access(all) token0: Type
10+
access(all) token1: Type
11+
access(all) fee: UInt32
12+
13+
/// Exact Input: "I have this many tokens, give me whatever they are worth"
14+
access(all) fun quoteExactInput(
15+
zeroForOne: Bool,
16+
amountIn: UFix64
17+
): UFix64
18+
19+
/// Exact Output: "I want exactly this many tokens, how much do I need to pay?"
20+
access(all) fun quoteExactOutput(
21+
zeroForOne: Bool,
22+
amountOut: UFix64
23+
): UFix64
24+
25+
access(all) fun swap(
26+
zeroForOne: Bool,
27+
inVault: @{FungibleToken.Vault}
28+
): @{FungibleToken.Vault}
29+
}
30+
31+
/// FYV needs this functionality but it doesn't have to be implemented like this!
32+
/// this is dangerous!! if a 3rd party provides a type and we are executing
33+
/// createEmptyVault any code can be run. (reentrancy, etc)
34+
access(all) fun getEmptyVault(_ vaultType: Type): @{FungibleToken.Vault} {
35+
post {
36+
result.getType() == vaultType:
37+
"Invalid Vault returned - expected \(vaultType.identifier) but returned \(result.getType().identifier)"
38+
}
39+
return <- getAccount(vaultType.address!)
40+
.contracts
41+
.borrow<&{FungibleToken}>(name: vaultType.contractName!)!
42+
.createEmptyVault(vaultType: vaultType)
43+
}
44+
}
Lines changed: 104 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,107 @@
1+
import "FlowYieldVaultsInterfaces"
12

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

14+
/// Emitted when a strategy is registered under `name`.
15+
access(all) event StrategyCreated(name: String)
16+
/// Emitted when a strategy is removed from the registry.
17+
access(all) event StrategyRemoved(name: String)
18+
/// Emitted when a yield vault is minted from the named strategy.
19+
access(all) event StrategyVaultCreated(name: String)
20+
21+
/// Storage path where the `Admin` resource is saved on this account.
22+
access(all) let adminStoragePath: StoragePath
23+
24+
/// Registered strategies, keyed by name. Names are unique; registering
25+
/// an already-used name panics.
26+
access(self) let strategies: {String: {FlowYieldVaultsInterfaces.Strategy}}
27+
28+
/// Admin resource; holder may register / remove strategies and mint
29+
/// yield vaults directly (bypassing any external access gate).
30+
access(all) resource Admin {
31+
/// Registers `strategy` under `name`.
32+
/// Panics if a strategy is already registered under that name.
33+
///
34+
/// **Parameters**
35+
/// - `name`: Unique identifier for the strategy in this registry.
36+
/// - `strategy`: Any value conforming to
37+
/// `FlowYieldVaultsInterfaces.Strategy`.
38+
access(all) fun registerStrategy(
39+
name: String,
40+
strategy: {FlowYieldVaultsInterfaces.Strategy}
41+
) {
42+
assert(
43+
FlowYieldVaults.strategies[name] == nil,
44+
message: "Strategy already registered: \(name)"
45+
)
46+
FlowYieldVaults.strategies[name] = strategy
47+
emit StrategyCreated(name: name)
48+
}
49+
50+
/// Removes the strategy registered under `name`.
51+
/// Panics if no strategy is registered under that name. Does not
52+
/// affect already-minted yield vaults — those captured the strategy
53+
/// parameters at creation time.
54+
///
55+
/// **Parameters**
56+
/// - `name`: Name of the strategy to remove.
57+
access(all) fun removeStrategy(name: String) {
58+
let strategy = FlowYieldVaults.strategies.remove(key: name)
59+
if strategy == nil {
60+
panic("Strategy not found")
61+
}
62+
emit StrategyRemoved(name: name)
63+
}
64+
65+
/// Mints a yield vault from a registered strategy.
66+
/// Wrapper around the contract-level `createYieldVault`
67+
/// for callers that hold the admin resource.
68+
///
69+
/// **Parameters**
70+
/// - `name`: Name of the registered strategy.
71+
///
72+
/// **Returns** A new `YieldVault` for the caller to save in storage.
73+
access(all) fun createYieldVault(name: String): @{FlowYieldVaultsInterfaces.YieldVault} {
74+
return <- FlowYieldVaults.createYieldVault(name: name)
75+
}
76+
}
77+
78+
/// Mints a yield vault from a registered strategy.
79+
/// Panics if no strategy is registered under `name`.
80+
/// `access(account)` so that only contracts on this account (e.g.
81+
/// `FlowYieldVaultsEarlyAccess`) can gate or invoke vault creation.
82+
///
83+
/// **Parameters**
84+
/// - `name`: Name of the registered strategy.
85+
///
86+
/// **Returns** A new `YieldVault` for the caller to save in storage.
87+
access(account) fun createYieldVault(name: String): @{FlowYieldVaultsInterfaces.YieldVault} {
88+
let strategy = self.strategies[name] ?? panic("Strategy not found")
89+
let vault <- strategy.createYieldVault(name: name)
90+
emit StrategyVaultCreated(name: name)
91+
return <- vault
92+
}
93+
94+
view access(all) fun strategyCount(): UInt64 {
95+
return UInt64(self.strategies.length)
96+
}
97+
98+
view access(all) fun strategyNames(): [String] {
99+
return self.strategies.keys
100+
}
101+
102+
init() {
103+
self.strategies = {}
104+
self.adminStoragePath = StoragePath(identifier: "FlowYieldVaultsAdmin")!
105+
self.account.storage.save(<- create Admin(), to: self.adminStoragePath)
106+
}
4107
}

cadence/contracts/yield_vaults/FlowYieldVaultsEarlyAccess.cdc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,14 @@ access(all) contract FlowYieldVaultsEarlyAccess {
3232
/// Panics if allowance is exhausted.
3333
///
3434
/// **Parameters**
35-
/// - `strategyID`: Identifies the vault strategy to create.
35+
/// - `name`: Name of the registered strategy to create a vault for.
3636
///
3737
/// **Returns** A new `YieldVault` to be saved in the caller's storage.
38-
access(all) fun createYieldVault(strategyID: UInt64): @{FlowYieldVaultsInterfaces.YieldVault} {
38+
access(all) fun createYieldVault(name: String): @{FlowYieldVaultsInterfaces.YieldVault} {
3939
pre { self.remainingAllowance > 0: "No remaining allowance" }
4040
self.remainingAllowance = self.remainingAllowance - 1
4141
let fyv = FlowYieldVaultsEarlyAccess.getFlowYieldVaultsContract()
42-
let vault <- fyv.createYieldVault(strategyID: strategyID)
42+
let vault <- fyv.createYieldVault(name: name)
4343
emit PassUsed(passUUID: self.uuid, remainingAllowance: self.remainingAllowance)
4444
return <- vault
4545
}

cadence/contracts/yield_vaults/FlowYieldVaultsInterfaces.cdc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ import "FungibleToken"
33
access(all) contract interface FlowYieldVaultsInterfaces {
44

55
access(all) struct interface Strategy {
6-
access(all) fun createYieldVault(strategyID: UInt64): @{YieldVault}
6+
access(all) fun createYieldVault(name: String): @{YieldVault}
77
}
88

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

11-
access(account) fun createYieldVault(strategyID: UInt64): @{YieldVault}
11+
access(account) fun createYieldVault(name: String): @{YieldVault}
1212
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import "FlowYieldVaults"
2+
3+
access(all) fun main(): [String] {
4+
return FlowYieldVaults.strategyNames()
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import "FlowYieldVaults"
2+
3+
access(all) fun main(): UInt64 {
4+
return FlowYieldVaults.strategyCount()
5+
}

0 commit comments

Comments
 (0)