Skip to content
Open
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
2 changes: 0 additions & 2 deletions FLOW_YIELD_VAULTS_EVM_BRIDGE_DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ EVM users deposit FLOW and submit requests to a Solidity contract. A Cadence wor
│ │ └─────────────────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ │ State: │ │
│ │ - yieldVaultsByEVMAddress: {String: [UInt64]} │ │
│ │ - yieldVaultOwnershipLookup: {String: {UInt64: Bool}} │ │
│ │ - flowYieldVaultsRequestsAddress: EVM.EVMAddress? │ │
│ │ - maxRequestsPerTx: Int (default: 1) │ │
Expand Down Expand Up @@ -132,7 +131,6 @@ Worker contract that processes EVM requests and manages YieldVault positions.
**Key State:**
```cadence
// YieldVault ownership tracking
access(all) let yieldVaultsByEVMAddress: {String: [UInt64]}
access(all) let yieldVaultOwnershipLookup: {String: {UInt64: Bool}}

// Configuration (stored as contract-only vars; exposed via getters)
Expand Down
2 changes: 1 addition & 1 deletion FRONTEND_INTEGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,7 @@ import FlowYieldVaultsEVM from 0xdf111ffc5064198a
access(all) fun main(): {String: AnyStruct} {
return {
"flowYieldVaultsRequestsAddress": FlowYieldVaultsEVM.getFlowYieldVaultsRequestsAddress()?.toString() ?? "not set",
"totalEVMUsers": FlowYieldVaultsEVM.yieldVaultsByEVMAddress.keys.length
"totalEVMUsers": FlowYieldVaultsEVM.yieldVaultOwnershipLookup.keys.length
}
}
`;
Expand Down
2 changes: 1 addition & 1 deletion TESTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ access_control_test.cdc: 7 tests PASS
- testRequestsAddressCanBeUpdated
- testWorkerCreationRequiresCOA
- testWorkerCreationRequiresBetaBadge
- testYieldVaultsByEVMAddressMapping
- testYieldVaultOwnershipLookupMapping

error_handling_test.cdc: 4 tests PASS
- testInvalidRequestType
Expand Down
37 changes: 16 additions & 21 deletions cadence/contracts/FlowYieldVaultsEVM.cdc
Original file line number Diff line number Diff line change
Expand Up @@ -163,10 +163,6 @@ access(all) contract FlowYieldVaultsEVM {
/// @notice Storage path for Admin resource
access(all) let AdminStoragePath: StoragePath

/// @notice YieldVault Ids owned by each EVM address
/// @dev Maps EVM address string to array of owned YieldVault Ids for public queries
access(all) let yieldVaultsByEVMAddress: {String: [UInt64]}

/// @notice O(1) lookup for yieldvault ownership verification
/// @dev Maps EVM address string to {yieldVaultId: true} for fast ownership checks
access(all) let yieldVaultOwnershipLookup: {String: {UInt64: Bool}}
Expand Down Expand Up @@ -730,7 +726,7 @@ access(all) contract FlowYieldVaultsEVM {
/// 2. Withdraws funds from COA (bridging ERC20 if needed)
/// 3. Validates vault type matches the requested vaultIdentifier
/// 4. Creates YieldVault via YieldVaultManager
/// 5. Records ownership in yieldVaultsByEVMAddress and yieldVaultOwnershipLookup
/// 5. Records ownership in yieldVaultOwnershipLookup
/// @param request The CREATE_YIELDVAULT request containing vault/strategy identifiers and amount
/// @return ProcessResult with success status, created yieldVaultId, and status message
access(self) fun processCreateYieldVault(_ request: EVMRequest): ProcessResult {
Expand Down Expand Up @@ -790,17 +786,11 @@ access(all) contract FlowYieldVaultsEVM {
// Phase 5: Record ownership in contract state for O(1) lookups
let evmAddr = request.user.toString()

// Initialize array for this address if needed
if FlowYieldVaultsEVM.yieldVaultsByEVMAddress[evmAddr] == nil {
FlowYieldVaultsEVM.yieldVaultsByEVMAddress[evmAddr] = []
}
FlowYieldVaultsEVM.yieldVaultsByEVMAddress[evmAddr]!.append(yieldVaultId)

// Initialize ownership map for this address if needed
if FlowYieldVaultsEVM.yieldVaultOwnershipLookup[evmAddr] == nil {
FlowYieldVaultsEVM.yieldVaultOwnershipLookup[evmAddr] = {}
}
FlowYieldVaultsEVM.yieldVaultOwnershipLookup[evmAddr]!.insert(key: yieldVaultId, true)
let _ = FlowYieldVaultsEVM.yieldVaultOwnershipLookup[evmAddr]!.insert(key: yieldVaultId, true)

emit YieldVaultCreatedForEVMUser(
requestId: request.id,
Expand Down Expand Up @@ -856,10 +846,11 @@ access(all) contract FlowYieldVaultsEVM {
self.bridgeFundsToEVMUser(vault: <-vault, recipient: request.user, tokenAddress: request.tokenAddress)

// Step 4: Remove yieldVaultId from ownership tracking
if let index = FlowYieldVaultsEVM.yieldVaultsByEVMAddress[evmAddr]!.firstIndex(of: request.yieldVaultId) {
let _ = FlowYieldVaultsEVM.yieldVaultsByEVMAddress[evmAddr]!.remove(at: index)
let _ = FlowYieldVaultsEVM.yieldVaultOwnershipLookup[evmAddr]!.remove(key: request.yieldVaultId)
// Clean up empty dictionaries to optimize storage costs
if FlowYieldVaultsEVM.yieldVaultOwnershipLookup[evmAddr]!.length == 0 {
let _ = FlowYieldVaultsEVM.yieldVaultOwnershipLookup.remove(key: evmAddr)
}
FlowYieldVaultsEVM.yieldVaultOwnershipLookup[evmAddr]!.remove(key: request.yieldVaultId)

emit YieldVaultClosedForEVMUser(
requestId: request.id,
Expand Down Expand Up @@ -1639,20 +1630,25 @@ access(all) contract FlowYieldVaultsEVM {

/// @notice Gets all YieldVault Ids owned by an EVM address
/// @param evmAddress The EVM address string to query
/// @return Array of YieldVault Ids owned by the address
/// @return Array of YieldVault Ids owned by the address (order is not guaranteed)
access(all) view fun getYieldVaultIdsForEVMAddress(_ evmAddress: String): [UInt64] {
return self.yieldVaultsByEVMAddress[evmAddress] ?? []
if !self.yieldVaultOwnershipLookup.containsKey(evmAddress) {
return []
}

return self.yieldVaultOwnershipLookup[evmAddress]!.keys
}

/// @notice Checks if an EVM address owns a specific YieldVault Id (O(1) lookup)
/// @param evmAddress The EVM address string to check
/// @param yieldVaultId The YieldVault Id to verify ownership of
/// @return True if the address owns the YieldVault, false otherwise
access(all) view fun doesEVMAddressOwnYieldVault(evmAddress: String, yieldVaultId: UInt64): Bool {
if let ownershipMap = self.yieldVaultOwnershipLookup[evmAddress] {
return ownershipMap[yieldVaultId] ?? false
if !self.yieldVaultOwnershipLookup.containsKey(evmAddress) {
return false
}
return false

return self.yieldVaultOwnershipLookup[evmAddress]!.containsKey(yieldVaultId)
}

/// @notice Gets the configured FlowYieldVaultsRequests contract address
Expand Down Expand Up @@ -1946,7 +1942,6 @@ access(all) contract FlowYieldVaultsEVM {
self.WorkerStoragePath = /storage/flowYieldVaultsEVM
self.AdminStoragePath = /storage/flowYieldVaultsEVMAdmin
self.maxRequestsPerTx = 1
self.yieldVaultsByEVMAddress = {}
self.yieldVaultOwnershipLookup = {}
self.flowYieldVaultsRequestsAddress = nil

Expand Down
2 changes: 1 addition & 1 deletion cadence/scripts/check_yieldvault_details.cdc
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ access(all) fun main(account: Address): {String: AnyStruct} {
result["contractAddress"] = account.toString()
result["flowYieldVaultsRequestsAddress"] = FlowYieldVaultsEVM.getFlowYieldVaultsRequestsAddress()?.toString() ?? "not set"

let yieldVaultsByEVM = FlowYieldVaultsEVM.yieldVaultsByEVMAddress
let yieldVaultsByEVM = FlowYieldVaultsEVM.yieldVaultOwnershipLookup
result["totalEVMAddresses"] = yieldVaultsByEVM.keys.length

let allYieldVaultIds: [UInt64] = []
Expand Down
2 changes: 1 addition & 1 deletion cadence/scripts/check_yieldvaultmanager_status.cdc
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ access(all) fun main(accountAddress: Address): {String: AnyStruct} {
paths["yieldVaultManagerPublic"] = FlowYieldVaults.YieldVaultManagerPublicPath.toString()
result["paths"] = paths

let yieldVaultsByEVM = FlowYieldVaultsEVM.yieldVaultsByEVMAddress
let yieldVaultsByEVM = FlowYieldVaultsEVM.yieldVaultOwnershipLookup
result["totalEVMAddresses"] = yieldVaultsByEVM.keys.length

var totalYieldVaultsMapped = 0
Expand Down
12 changes: 6 additions & 6 deletions cadence/scripts/get_contract_state.cdc
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,25 @@ access(all) fun main(contractAddress: Address): {String: AnyStruct} {

result["flowYieldVaultsRequestsAddress"] = FlowYieldVaultsEVM.getFlowYieldVaultsRequestsAddress()?.toString() ?? "Not set"
result["maxRequestsPerTx"] = FlowYieldVaultsEVM.getMaxRequestsPerTx()
result["yieldVaultsByEVMAddress"] = FlowYieldVaultsEVM.yieldVaultsByEVMAddress
result["yieldVaultOwnershipLookup"] = FlowYieldVaultsEVM.yieldVaultOwnershipLookup

result["WorkerStoragePath"] = FlowYieldVaultsEVM.WorkerStoragePath.toString()
result["AdminStoragePath"] = FlowYieldVaultsEVM.AdminStoragePath.toString()

var totalYieldVaults = 0
var totalEVMAddresses = 0
for evmAddress in FlowYieldVaultsEVM.yieldVaultsByEVMAddress.keys {
for evmAddress in FlowYieldVaultsEVM.yieldVaultOwnershipLookup.keys {
totalEVMAddresses = totalEVMAddresses + 1
let yieldVaultIds = FlowYieldVaultsEVM.yieldVaultsByEVMAddress[evmAddress]!
totalYieldVaults = totalYieldVaults + yieldVaultIds.length
let yieldVaultIds = FlowYieldVaultsEVM.yieldVaultOwnershipLookup[evmAddress]!
totalYieldVaults = totalYieldVaults + yieldVaultIds.keys.length
}

result["totalEVMAddresses"] = totalEVMAddresses
result["totalYieldVaults"] = totalYieldVaults

let evmAddressDetails: {String: Int} = {}
for evmAddress in FlowYieldVaultsEVM.yieldVaultsByEVMAddress.keys {
evmAddressDetails[evmAddress] = FlowYieldVaultsEVM.yieldVaultsByEVMAddress[evmAddress]!.length
for evmAddress in FlowYieldVaultsEVM.yieldVaultOwnershipLookup.keys {
evmAddressDetails[evmAddress] = FlowYieldVaultsEVM.yieldVaultOwnershipLookup[evmAddress]!.length
}
result["evmAddressDetails"] = evmAddressDetails

Expand Down
4 changes: 2 additions & 2 deletions cadence/tests/access_control_test.cdc
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,8 @@ fun testWorkerCreationRequiresBetaBadge() {
}

access(all)
fun testYieldVaultsByEVMAddressMapping() {
// Verify the yieldVaultsByEVMAddress mapping is accessible
fun testYieldVaultOwnershipLookupMapping() {
// Verify the yieldVaultOwnershipLookup mapping is accessible
let testAddress = "0x6666666666666666666666666666666666666666"
let yieldVaultIds = FlowYieldVaultsEVM.getYieldVaultIdsForEVMAddress(testAddress)

Expand Down