Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
52aa23e
add MOET contract & add to flow.json config
sisyphusSmiling May 30, 2025
d2989e8
add MOET init arg to emulator deployment
sisyphusSmiling May 30, 2025
48951ad
import MOET into TidalProtocol
sisyphusSmiling May 30, 2025
257b35c
remove Pool creation in TidalProtocol init
sisyphusSmiling May 30, 2025
e74e0d0
add contract-level pool creation
sisyphusSmiling May 30, 2025
2f32bf9
move test methods
sisyphusSmiling May 30, 2025
7638691
add Position creation logic to Pool & InternalPosition including Sour…
sisyphusSmiling May 30, 2025
7d227dd
enable provision of sink/source through to InternalPosition
sisyphusSmiling May 30, 2025
8a28640
update TidalProtocolSink/Source connectors
sisyphusSmiling May 30, 2025
1bdde15
update contract notes
sisyphusSmiling May 31, 2025
915bc9a
Fix test logic errors - Fixed testReentrancyProtection and testFuzzIn…
kgrgpg Jun 2, 2025
0be084d
feat: Add MOET stablecoin integration with token management - Add add…
kgrgpg Jun 2, 2025
86c9774
feat: Implement comprehensive governance system for pool management -…
kgrgpg Jun 2, 2025
d89cbef
Fix MOET integration tests and duplicate flow.json aliases - Fixed du…
kgrgpg Jun 2, 2025
4b3223d
feat: FlowToken integration tests (WIP) - Add FlowToken and FungibleT…
kgrgpg Jun 2, 2025
04ed7bd
feat: Complete FlowToken integration for TidalProtocol
kgrgpg Jun 2, 2025
45ddb96
Add integration documentation from feature branches
kgrgpg Jun 2, 2025
0305528
Merge branch 'feature/flowtoken-integration' into feature/complete-in…
kgrgpg Jun 2, 2025
f42d5a7
Add comprehensive integration summary documentation
kgrgpg Jun 2, 2025
9b23303
Update test coverage report
kgrgpg Jun 2, 2025
7ab6b88
Add merge instructions and final integration documentation
kgrgpg Jun 2, 2025
c67295e
RESTORE: Dieter's comprehensive oracle implementation - Restores Pric…
kgrgpg Jun 2, 2025
3cd75a9
ANALYSIS: Complete comparison with Dieter's latest code - Found 40% o…
kgrgpg Jun 2, 2025
32976f3
cleanup: Remove temporary analysis file
kgrgpg Jun 2, 2025
2b2e5b2
RESTORE Phase 1: Critical infrastructure from Dieter's implementation…
kgrgpg Jun 2, 2025
3ddeba4
RESTORE Phase 2: Complete Dieter's critical functionality - Added dep…
kgrgpg Jun 2, 2025
e9c9305
docs: Complete restoration status documentation - 80% of Dieter's fun…
kgrgpg Jun 2, 2025
70b426a
feat: 100% restoration of Dieter's AlpenFlow implementation achieved
kgrgpg Jun 2, 2025
a4e2fb2
docs: comprehensive test update documentation based on 100% restoration
kgrgpg Jun 2, 2025
e9c521c
docs: add NEXT_STEPS.md with clear implementation plan
kgrgpg Jun 2, 2025
4693d7f
Merge branch 'feature/restore-dete-oracle-implementation' into gio/re…
sisyphusSmiling Jun 2, 2025
a8ed46d
update InternalPosition to handle various Sink/Source connectors base…
sisyphusSmiling Jun 2, 2025
2c9077f
remove FungibleToken & unused contract methods, move remaining test …
sisyphusSmiling Jun 2, 2025
6d0dbbf
fix InternalPosition rebalancing sink/source assignment
sisyphusSmiling Jun 3, 2025
e5a7f3a
replace DFB placeholder interfaces with imported definitions
sisyphusSmiling Jun 3, 2025
65c4f2f
test: comprehensive update to follow oracle-based patterns and restor…
kgrgpg Jun 3, 2025
fe20ab6
update Pool creation pattern to use a stored factory & add test suppo…
sisyphusSmiling Jun 3, 2025
b437e52
test: Fix test patterns based on documentation guidance - Updated edg…
kgrgpg Jun 3, 2025
efa9dd8
test: Update tests and create missing transaction files - Fixed oracl…
kgrgpg Jun 3, 2025
bb3b69f
docs: Update test summary with latest findings and patterns - Documen…
kgrgpg Jun 3, 2025
286aa96
feat: Major test improvements - 88.52% pass rate achieved! Fixed enha…
kgrgpg Jun 3, 2025
d8bf210
feat: Fixed all governance and MOET integration tests - 90.34% pass r…
kgrgpg Jun 3, 2025
ded730a
feat: Rewrote fuzzy testing and deleted redundant access control test…
kgrgpg Jun 3, 2025
eb37950
docs: Organize documentation into structured folders - Created organi…
kgrgpg Jun 3, 2025
971695d
chore: Clean up temporary PR files after PR creation
kgrgpg Jun 3, 2025
274ff85
Merge branch 'fix/update-tests-for-complete-restoration' into gio/ref…
sisyphusSmiling Jun 3, 2025
799199f
add initial functional platform integration tests
sisyphusSmiling Jun 3, 2025
33676cf
fix overflow by assigning TokenState.lastUpdate as current timestamp …
sisyphusSmiling Jun 4, 2025
df6147a
add initial platform integration test cases & supporting mocks, txns,…
sisyphusSmiling Jun 4, 2025
e3a1251
refactor openPosition to include configurable pushToDropDownSink on o…
sisyphusSmiling Jun 4, 2025
c00199a
remove SwapSink definition from TidalProtocol
sisyphusSmiling Jun 4, 2025
ef7ad75
add print debug log lines to TidalProtocol
sisyphusSmiling Jun 4, 2025
93a479e
Merge branch 'feature/contracts-restoration' into gio/refactor-pool-c…
sisyphusSmiling Jun 4, 2025
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
5 changes: 5 additions & 0 deletions .cursor/rules/tests-rules.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
description:
globs:
alwaysApply: false
---
610 changes: 311 additions & 299 deletions cadence/contracts/TidalProtocol.cdc

Large diffs are not rendered by default.

812 changes: 812 additions & 0 deletions cadence/contracts/TidalProtocol_before_oracle_restore.cdc

Large diffs are not rendered by default.

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

import "DFB"

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

/// token price denominated in USD
access(self) let mockedPrices: {Type: UFix64}
/// the token type in which prices are denominated
access(self) let unitOfAccount: Type
/// bps up or down by which current price moves when bumpPrice is called
access(self) let bumpVariance: UInt16

access(all) struct PriceOracle : DFB.PriceOracle {

/// Returns the asset type serving as the price basis - e.g. USD in FLOW/USD
access(all) view fun unitOfAccount(): Type {
return MockOracle.unitOfAccount
}

/// Returns the latest price data for a given asset denominated in unitOfAccount()
access(all) fun price(ofToken: Type): UFix64? {
if ofToken == self.unitOfAccount() {
return 1.0
}
return MockOracle.mockedPrices[ofToken]
}
}

// resets the price of the token within 0-bumpVariance (bps) of the current price
// allows for mocked data to have variability
access(all) fun bumpPrice(forToken: Type) {
if forToken == self.unitOfAccount {
return
}
let current = self.mockedPrices[forToken]
?? panic("MockOracle does not have a price set for token \(forToken.identifier)")
let sign = revertibleRandom<UInt8>(modulo: 2) // 0 - down | 1 - up
let variance = self.convertToBPS(revertibleRandom<UInt16>(modulo: self.bumpVariance)) // bps up or down
if sign == 0 {
self.mockedPrices[forToken] = current - (current * variance)
} else {
self.mockedPrices[forToken] = current + (current * variance)
}
}

access(all) fun setPrice(forToken: Type, price: UFix64) {
self.mockedPrices[forToken] = price
}

access(self) view fun convertToBPS(_ variance: UInt16): UFix64 {
var res = UFix64(variance)
for i in InclusiveRange(0, 3) {
res = res / 10.0
}
return res
}

init(unitOfAccountIdentifier: String) {
self.mockedPrices = {}
// e.g. vault.getType().identifier == 'A.0ae53cb6e3f42a79.FlowToken.Vault'
self.unitOfAccount = CompositeType(unitOfAccountIdentifier) ?? panic("Invalid unitOfAccountIdentifier \(unitOfAccountIdentifier)")
self.bumpVariance = 100 // 0.1% variance
}
}
56 changes: 56 additions & 0 deletions cadence/contracts/mocks/MockTidalProtocolConsumer.cdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import "FungibleToken"

import "DFB"
import "TidalProtocol"

/// THIS CONTRACT IS NOT SAFE FOR PRODUCTION - FOR TEST USE ONLY
/// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
///
/// A simple contract enabling the persistent storage of a Position similar to a pattern expected for platforms
/// building on top of TidalProtocol's lending protocol
///
access(all) contract MockTidalProtocolConsumer {

/// Canonical path for where the wrapper is to be stored
access(all) let WrapperStoragePath: StoragePath

/// Opens a TidalProtocol Position and returns a PositionWrapper containing that new position
///
access(all)
fun createPositionWrapper(
collateral: @{FungibleToken.Vault},
issuanceSink: {DFB.Sink},
repaymentSource: {DFB.Source}?,
pushToDrawDownSink: Bool
): @PositionWrapper {
return <- create PositionWrapper(
position: TidalProtocol.openPosition(
collateral: <-collateral,
issuanceSink: issuanceSink,
repaymentSource: repaymentSource,
pushToDrawDownSink: pushToDrawDownSink
)
)
}

/// A simple resource encapsulating a TidalProtocol Position
access(all) resource PositionWrapper {

access(self) let position: TidalProtocol.Position

init(position: TidalProtocol.Position) {
self.position = position
}

/// NOT SAFE FOR PRODUCTION
///
/// Returns a reference to the wrapped Position
access(all) fun borrowPosition(): &TidalProtocol.Position {
return &self.position
}
}

init() {
self.WrapperStoragePath = /storage/tidalProtocolPositionWrapper
}
}
14 changes: 14 additions & 0 deletions cadence/scripts/funds_required_for_target_health.cdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import TidalProtocol from "TidalProtocol"

access(all) fun main(poolAddress: Address, pid: UInt64, tokenType: Type, targetHealth: UFix64): UFix64 {
let poolCap = getAccount(poolAddress)
.capabilities.get<&TidalProtocol.Pool>(/public/tidalPool)
.borrow()
?? panic("Could not borrow pool capability")

return poolCap.fundsRequiredForTargetHealth(
pid: pid,
type: tokenType,
targetHealth: targetHealth
)
}
19 changes: 19 additions & 0 deletions cadence/scripts/get_available_balance.cdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import TidalProtocol from "../contracts/TidalProtocol.cdc"

access(all) fun main(poolAddress: Address, positionId: UInt64, tokenType: String): UFix64 {
// Get the pool reference
let pool = getAccount(poolAddress).capabilities.borrow<&TidalProtocol.Pool>(
/public/tidalPool
) ?? panic("Could not borrow pool reference")

// Parse the token type
let vaultType = CompositeType(tokenType)
?? panic("Invalid token type identifier")

// Get the position
let position = pool.borrowPosition(pid: positionId)
?? panic("Position not found")

// Get available balance (includes source integration)
return position.getAvailableBalance(tokenType: vaultType)
}
10 changes: 10 additions & 0 deletions cadence/scripts/get_flowtoken_balance.cdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import FlowToken from "FlowToken"
import FungibleToken from "FungibleToken"

access(all) fun main(address: Address): UFix64 {
let account = getAccount(address)
let vaultRef = account.capabilities.borrow<&{FungibleToken.Balance}>(/public/flowTokenBalance)
?? panic("Could not borrow Balance reference to the Vault")

return vaultRef.balance
}
13 changes: 13 additions & 0 deletions cadence/scripts/get_pool_reference.cdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import TidalProtocol from "TidalProtocol"

// Script to check if an account has a pool capability published
access(all) fun main(address: Address): Bool {
let account = getAccount(address)

// Check if the account has a pool capability published
let poolCap = account.capabilities.get<&TidalProtocol.Pool>(
/public/tidalProtocolPool
)

return poolCap.check()
}
41 changes: 41 additions & 0 deletions cadence/scripts/get_position_balances.cdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import TidalProtocol from "../contracts/TidalProtocol.cdc"

access(all) struct BalanceInfo {
access(all) let tokenType: Type
access(all) let balance: UFix64
access(all) let availableBalance: UFix64

init(tokenType: Type, balance: UFix64, availableBalance: UFix64) {
self.tokenType = tokenType
self.balance = balance
self.availableBalance = availableBalance
}
}

access(all) fun main(poolAddress: Address, positionId: UInt64): [BalanceInfo] {
// Get the pool reference
let pool = getAccount(poolAddress).capabilities.borrow<&TidalProtocol.Pool>(
/public/tidalPool
) ?? panic("Could not borrow pool reference")

// Get the position
let position = pool.borrowPosition(pid: positionId)
?? panic("Position not found")

// Get all balances
let balances = position.getBalances()

// Create result array
let result: [BalanceInfo] = []

for balance in balances {
let availableBalance = position.getAvailableBalance(tokenType: balance.tokenType)
result.append(BalanceInfo(
tokenType: balance.tokenType,
balance: balance.balance,
availableBalance: availableBalance
))
}

return result
}
14 changes: 14 additions & 0 deletions cadence/scripts/get_position_details.cdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import TidalProtocol from "TidalProtocol"

access(all) fun main(accountAddress: Address, positionID: UInt64): TidalProtocol.PositionDetails? {
// Get the pool capability from the account
let capability = getAccount(accountAddress).capabilities
.get<&TidalProtocol.Pool>(/public/testPool)

if let pool = capability.borrow() {
// Get position details
return pool.getPositionDetails(pid: positionID)
}

return nil
}
10 changes: 10 additions & 0 deletions cadence/scripts/get_position_health.cdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import TidalProtocol from "TidalProtocol"

access(all) fun main(poolAddress: Address, pid: UInt64): UFix64 {
let poolCap = getAccount(poolAddress)
.capabilities.get<&TidalProtocol.Pool>(/public/tidalPool)
.borrow()
?? panic("Could not borrow pool capability")

return poolCap.positionHealth(pid: pid)
}
16 changes: 16 additions & 0 deletions cadence/scripts/get_target_health.cdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import TidalProtocol from "../contracts/TidalProtocol.cdc"

access(all) fun main(poolAddress: Address, positionId: UInt64): UFix64 {
// Get the pool reference
let pool = getAccount(poolAddress).capabilities.borrow<&TidalProtocol.Pool>(
/public/tidalPool
) ?? panic("Could not borrow pool reference")

// Get the position
let position = pool.borrowPosition(pid: positionId)
?? panic("Position not found")

// Note: getTargetHealth() always returns 1.5 in the Position struct interface
// The actual target health is stored in InternalPosition and not accessible
return position.getTargetHealth()
}
8 changes: 8 additions & 0 deletions cadence/scripts/health_computation.cdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import TidalProtocol from "TidalProtocol"

access(all) fun main(effectiveCollateral: UFix64, effectiveDebt: UFix64): UFix64 {
return TidalProtocol.healthComputation(
effectiveCollateral: effectiveCollateral,
effectiveDebt: effectiveDebt
)
}
57 changes: 57 additions & 0 deletions cadence/scripts/test_access_control.cdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import TidalProtocol from "TidalProtocol"

// Test script for validating access control and entitlements
access(all) fun main(): Bool {
// Test 1: Create pool and position (tests public access)
let oracle = TidalProtocol.DummyPriceOracle(defaultToken: Type<String>())
let pool <- TidalProtocol.createTestPoolWithOracle(defaultToken: Type<String>())
let positionId = pool.createPosition()

// Test 2: Verify public functions work without special entitlements
let health = pool.positionHealth(pid: positionId)
let supportedTokens = pool.getSupportedTokens()
let tokenSupported = pool.isTokenSupported(tokenType: Type<String>())
let reserveBalance = pool.reserveBalance(type: Type<String>())

// Test 3: Get position details instead of creating Position struct
let positionDetails = pool.getPositionDetails(pid: positionId)
let positionHealth = positionDetails.health
let positionBalances = positionDetails.balances
let availableBalance = positionDetails.defaultTokenAvailableBalance

// Test 4: Test that health functions return expected values for empty position
let healthIsOne = health == 1.0 && positionHealth == 1.0
let balancesEmpty = positionBalances.length == 0
let reserveIsZero = reserveBalance == 0.0
let availableIsZero = availableBalance == 0.0

// Test 5: Verify DummyPriceOracle works correctly
let oracleUnitOfAccount = oracle.unitOfAccount()
let defaultTokenPrice = oracle.price(token: Type<String>())
let priceIsOne = defaultTokenPrice == 1.0
let correctUnitOfAccount = oracleUnitOfAccount == Type<String>()

// Test 6: Verify helper functions work
let healthCalc = TidalProtocol.healthComputation(effectiveCollateral: 100.0, effectiveDebt: 50.0)
let healthIs2 = healthCalc == 2.0

// Test 7: Verify Balance Direction enum
let creditDirection = TidalProtocol.BalanceDirection.Credit
let debitDirection = TidalProtocol.BalanceDirection.Debit
let directionsWork = creditDirection != debitDirection

// Cleanup
destroy pool

// Comprehensive result
return healthIsOne &&
balancesEmpty &&
reserveIsZero &&
availableIsZero &&
priceIsOne &&
correctUnitOfAccount &&
healthIs2 &&
directionsWork &&
tokenSupported &&
supportedTokens.length >= 1
}
34 changes: 34 additions & 0 deletions cadence/scripts/test_access_practical.cdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import TidalProtocol from "TidalProtocol"

// Test practical access control scenarios
access(all) fun main(): Bool {
// Test 1: Create pool and verify public access
let oracle = TidalProtocol.DummyPriceOracle(defaultToken: Type<String>())
let pool <- TidalProtocol.createTestPoolWithOracle(defaultToken: Type<String>())

// Test 2: Public functions should work
let positionId = pool.createPosition()
let health = pool.positionHealth(pid: positionId)
let supportedTokens = pool.getSupportedTokens()

// Test 3: Verify position details access
let details = pool.getPositionDetails(pid: positionId)

// Test 4: Check all public getters work
let isSupported = pool.isTokenSupported(tokenType: Type<String>())
let reserveBalance = pool.reserveBalance(type: Type<String>())

// Get default token from position details
let defaultToken = details.poolDefaultToken

// Cleanup
destroy pool

// All tests passed if we got here
return health == 1.0 &&
details.health == 1.0 &&
supportedTokens.length >= 1 &&
defaultToken == Type<String>() &&
isSupported &&
reserveBalance == 0.0
}
Loading