Smart Contract

FastbreakVaultsCloser_V1

A.46df6b5eeec6103a.FastbreakVaultsCloser_V1

Valid From

130,498,523

Deployed

1w ago
Feb 21, 2026, 02:40:11 PM UTC

Dependents

3 imports
1/*
2================================================================================
3File: FastBreakVaultsCloser.cdc
4Project: aiSports - Flow Forte Hackathon Upgrade
5
6Development Plan & Testing Strategy
7================================================================================
8
9// OVERALL GOAL:
10// This contract is designed to be executed by a Flow Scheduled Transaction.
11// Its ultimate purpose is to take the $FLOW prize pool from a completed
12// FastBreak Vault, swap it for $JUICE using the Increment.fi DEX Action,
13// and prepare the $JUICE for distribution to the winners.
14
15// CORE CHALLENGE:
16// The Increment.fi swap Action is only available on Flow Mainnet. It cannot be
17// tested on the emulator or testnet. This requires a phased development
18// approach to validate our logic before deploying to mainnet with real funds.
19
20// ==============================================================================
21// PHASE 1: EMULATOR-FIRST MOCK LOGIC (CURRENT IMPLEMENTATION)
22// ==============================================================================
23// Objective:
24// To verify that the core Scheduled Transaction mechanism (scheduling, triggering,
25// and execution) works correctly in a controlled environment without the
26// mainnet dependency.
27
28// Implementation:
29// Instead of performing a real swap, we will implement a simple, verifiable
30// proxy action on the emulator:
31//   1. The scheduled job triggers and executes this contract's logic.
32//   2. The code checks this contract's own $FLOW balance.
33//   3. A conditional check is performed: IF the balance is above a threshold
34//      (e.g., > 0.5 FLOW for testing), THEN proceed.
35//   4. If the condition is met, the contract sends a small, fixed amount
36//      (e.g., 0.1 FLOW) to a designated recipient address. This address can
37//      only be set by the contract admin. We may not need to send the tokens, the Juice tokens can just stay in the contract account.
38
39// Success Criteria for Phase 1:
40// We can successfully schedule the job, and the designated recipient account
41// receives 0.1 FLOW at the specified interval on the emulator. This proves
42// the scheduling and execution pipeline is working.
43
44// ==============================================================================
45// PHASE 2: MAINNET INTEGRATION & LIVE TESTING
46// ==============================================================================
47// Objective:
48// To replace the mock logic with the real swap functionality and deploy to
49// mainnet for a final, controlled test.
50
51// Implementation Steps:
52//   1. Comment out or remove the mock transfer logic from Phase 1.
53//   2. Integrate the Cadence code from our `swap_flow_to_juice.cdc` transaction
54//      directly into this contract's execution logic.
55//   3. This new code will call the official Increment.fi swap Action to convert
56//      this contract's entire $FLOW balance into $JUICE.
57//   4. Deploy the finalized contract to a mainnet account.
58//   5. Fund the account with a small, controlled amount of $FLOW for testing
59//      (e.g., 1.0 FLOW).
60//   6. Schedule the transaction to run.
61
62// Success Criteria for Phase 2:
63// After the scheduled transaction executes on mainnet, we can verify on-chain
64// that the contract's $FLOW balance has been successfully swapped for $JUICE.
65
66Account notes:
67mainnet account holding Flow - 0x254b32edc33e5bc3
68
69*/
70import FungibleToken from 0xf233dcee88fe0abe
71import FlowToken from 0x1654653399040a61
72import FungibleTokenMetadataViews from 0xf233dcee88fe0abe
73import aiSportsJuice from 0x9db94c9564243ba7
74import IncrementFiSwapConnectors from 0xefa9bd7d1b17f1ed
75
76access(all)
77contract FastbreakVaultsCloser_V1 {
78
79    //add an array of token types that we should scan and swap
80    access(all) let tokenStorageVaultPaths: [StoragePath]
81
82    access(all) fun swapToJuice() {
83
84        //loop through the array of token public vault paths and check the balance of each token
85        for tokenStorageVaultPath in self.tokenStorageVaultPaths {
86            let vaultRef = self.account.storage.borrow<auth(FungibleToken.Withdraw) &{FungibleToken.Vault}>(from:tokenStorageVaultPath) ?? panic("Vault not found")
87
88            //check the type of the vault - if it is a Flow Token Vault, we need to keep some Flow tokens in the contract account for fees
89            if vaultRef.getType() == Type<@FlowToken.Vault>() {
90                let balance = vaultRef.balance
91
92                if balance > 0.5 {
93                    let balanceToSwap = balance - 0.5
94                    log("Balance to Swap: \(balanceToSwap)")
95                    let flowToWithdraw  <- vaultRef.withdraw(amount: balanceToSwap)
96
97                    //swap the balance to juice    
98                    
99                    // Router path for IncrementFi (FLOW -> stFLOW -> JUICE)
100                    let path: [String] = [
101                        "A.1654653399040a61.FlowToken",
102                        "A.d6f80565193ad727.stFlowToken",
103                        "A.9db94c9564243ba7.aiSportsJuice"
104                    ]
105
106                    // Build the IncrementFi swapper (FLOW -> JUICE via stFLOW)
107                    // Provide concrete token vault types for validation against the path
108                    let swapper = IncrementFiSwapConnectors.Swapper(
109                        path: path,
110                        inVault: Type<@FlowToken.Vault>(),
111                        outVault: Type<@aiSportsJuice.Vault>(),
112                        uniqueID: nil
113                    )
114
115                    // Perform the swap; the swapper internally quotes amountOutMin
116                    let juiceVault <- swapper.swap(quote: nil, inVault: <-flowToWithdraw)
117
118                    // Deposit JUICE into the token holder's JUICE receiver
119                    let juiceReceiver = self.account
120                        .capabilities
121                        .get<&{FungibleToken.Receiver}>(/public/aiSportsJuiceReceiver)
122                        .borrow()
123                        ?? panic("Missing /public/aiSportsJuiceReceiver capability on signer")
124
125                    juiceReceiver.deposit(from: <-juiceVault)
126                }
127            } //once we add more tokens, will need to add else logic here to swap
128        }
129    }
130
131    //this function is called by the contract admin to add a token type to the array of tokens to add/swap
132    access(account) fun addTokenType(vaultStoragePath: StoragePath) {
133        self.tokenStorageVaultPaths.append(vaultStoragePath)
134    }
135
136    init() {
137        let vaultData = FlowToken.resolveContractView(
138            resourceType: nil, 
139            viewType: Type<FungibleTokenMetadataViews.FTVaultData>()
140            ) as! FungibleTokenMetadataViews.FTVaultData
141        self.tokenStorageVaultPaths = [ vaultData.storagePath ]
142    }
143}