Smart Contract

LayerZeroConnectors

A.6daee039a7b9c2f0.LayerZeroConnectors

Valid From

123,196,366

Deployed

6d ago
Feb 21, 2026, 10:01:28 PM UTC

Dependents

0 imports
1import DeFiActions from 0x92195d814edf9cb0
2import FungibleToken from 0xf233dcee88fe0abe
3import FlareFDCTriggers from 0x6daee039a7b9c2f0
4
5/// LayerZeroConnectors: Simplified Flow Actions connectors for LayerZero cross-chain messaging
6/// Uses struct-based DeFiActions pattern for cross-chain operations
7access(all) contract LayerZeroConnectors {
8    
9    /// Events
10    access(all) event CrossChainMessageSent(
11        messageId: String,
12        targetChain: UInt16,
13        payload: String,
14        gasLimit: UInt256
15    )
16    
17    access(all) event CrossChainMessageReceived(
18        messageId: String,
19        sourceChain: UInt16,
20        payload: String
21    )
22    
23    access(all) event ActionExecuted(
24        actionId: String,
25        actionType: String,
26        success: Bool
27    )
28    
29    /// LayerZero chain IDs
30    access(all) let ChainIds: {String: UInt16}
31    
32    /// Cross-chain action types
33    access(all) enum CrossChainActionType: UInt8 {
34        access(all) case TokenTransfer
35        access(all) case LiquidityProvision
36        access(all) case Swap
37        access(all) case Stake
38        access(all) case Unstake
39        access(all) case Harvest
40        access(all) case Compound
41    }
42    
43    /// Cross-chain message structure
44    access(all) struct CrossChainMessage {
45        access(all) let messageId: String
46        access(all) let sourceChain: UInt16
47        access(all) let targetChain: UInt16
48        access(all) let actionType: CrossChainActionType
49        access(all) let payload: {String: String}
50        access(all) let gasLimit: UInt256
51        access(all) let timestamp: UFix64
52        
53        init(
54            messageId: String,
55            sourceChain: UInt16,
56            targetChain: UInt16,
57            actionType: CrossChainActionType,
58            payload: {String: String},
59            gasLimit: UInt256
60        ) {
61            self.messageId = messageId
62            self.sourceChain = sourceChain
63            self.targetChain = targetChain
64            self.actionType = actionType
65            self.payload = payload
66            self.gasLimit = gasLimit
67            self.timestamp = getCurrentBlock().timestamp
68        }
69    }
70    
71    /// LayerZero Message Sink: Processes cross-chain messages following DeFiActions pattern
72    access(all) struct LayerZeroMessageSink: DeFiActions.Sink {
73        access(contract) var uniqueID: DeFiActions.UniqueIdentifier?
74        access(contract) let targetChain: UInt16
75        access(contract) let actionType: CrossChainActionType
76        
77        init(
78            targetChain: UInt16,
79            actionType: CrossChainActionType,
80            uniqueID: DeFiActions.UniqueIdentifier?
81        ) {
82            self.targetChain = targetChain
83            self.actionType = actionType
84            self.uniqueID = uniqueID
85        }
86        
87        /// Required by Sink: advertise the supported vault type
88        access(all) view fun getSinkType(): Type {
89            // Accept any FungibleToken vault for cross-chain messaging
90            return Type<@{FungibleToken.Vault}>()
91        }
92        
93        /// This sink can accept unlimited capacity for message creation
94        access(all) fun minimumCapacity(): UFix64 {
95            return UFix64.max
96        }
97        
98        /// Deposit vault and create cross-chain message
99        access(all) fun depositCapacity(from: auth(FungibleToken.Withdraw) &{FungibleToken.Vault}) {
100            let amount = from.balance
101            if amount == 0.0 { return }
102            
103            // Create cross-chain message based on deposit
104            let messageId = self.generateMessageId()
105            let message = CrossChainMessage(
106                messageId: messageId,
107                sourceChain: LayerZeroConnectors.ChainIds["Flow"]!,
108                targetChain: self.targetChain,
109                actionType: self.actionType,
110                payload: {
111                    "amount": amount.toString(),
112                    "token_type": from.getType().identifier,
113                    "timestamp": getCurrentBlock().timestamp.toString()
114                },
115                gasLimit: 200000
116            )
117            
118            // Consume the vault (in real implementation, this would be bridged)
119            let vault <- from.withdraw(amount: amount)
120            destroy vault
121            
122            // Send cross-chain message
123            LayerZeroConnectors.sendCrossChainMessage(message)
124        }
125        
126        /// Report metadata about this component
127        access(all) fun getComponentInfo(): DeFiActions.ComponentInfo {
128            return DeFiActions.ComponentInfo(
129                type: self.getType(),
130                id: self.id(),
131                innerComponents: []
132            )
133        }
134        
135        /// UniqueIdentifier passthrough
136        access(contract) view fun copyID(): DeFiActions.UniqueIdentifier? {
137            return self.uniqueID
138        }
139        
140        /// Allow framework to set UniqueIdentifier
141        access(contract) fun setID(_ id: DeFiActions.UniqueIdentifier?) {
142            self.uniqueID = id
143        }
144        
145        access(self) fun generateMessageId(): String {
146            let timestamp = getCurrentBlock().timestamp
147            let id = self.id() ?? 0
148            return "lz-".concat(id.toString()).concat("-").concat(timestamp.toString())
149        }
150    }
151    
152    /// FDC Trigger Handler that processes Flare triggers
153    access(all) resource FDCLayerZeroHandler: FlareFDCTriggers.TriggerHandler {
154        access(all) let supportedTypes: [FlareFDCTriggers.TriggerType]
155        access(self) var isHandlerActive: Bool
156        access(self) let chainMapping: {String: UInt16}
157        
158        access(all) fun handleTrigger(trigger: FlareFDCTriggers.FDCTrigger): Bool {
159            if !self.isHandlerActive {
160                return false
161            }
162            
163            // Convert FDC trigger to LayerZero action type
164            let actionType = self.mapTriggerToAction(trigger.triggerType)
165            let targetChainId = self.chainMapping[trigger.targetChain.rawValue.toString()] ?? 101
166            
167            // Create cross-chain message
168            let messageId = self.generateMessageId(trigger)
169            let payload: {String: String} = {}
170            
171            // Convert trigger payload to string format
172            for key in trigger.payload.keys {
173                if let value = trigger.payload[key] {
174                    // Convert AnyStruct to string representation
175                    payload[key] = value.getType().identifier.concat(":").concat(key)
176                }
177            }
178            
179            let message = CrossChainMessage(
180                messageId: messageId,
181                sourceChain: LayerZeroConnectors.ChainIds["Flow"]!,
182                targetChain: targetChainId,
183                actionType: actionType,
184                payload: payload,
185                gasLimit: 300000
186            )
187            
188            LayerZeroConnectors.sendCrossChainMessage(message)
189            
190            // Emit local event (not importing FlareFDCTriggers event)
191            emit ActionExecuted(
192                actionId: messageId,
193                actionType: actionType.rawValue.toString(),
194                success: true
195            )
196            
197            return true
198        }
199        
200        access(all) fun getSupportedTriggerTypes(): [FlareFDCTriggers.TriggerType] {
201            return self.supportedTypes
202        }
203        
204        access(all) fun isActive(): Bool {
205            return self.isHandlerActive
206        }
207        
208        access(all) fun setActive(_ active: Bool) {
209            self.isHandlerActive = active
210        }
211        
212        access(self) fun mapTriggerToAction(_ triggerType: FlareFDCTriggers.TriggerType): CrossChainActionType {
213            switch triggerType {
214                case FlareFDCTriggers.TriggerType.PriceThreshold:
215                    return CrossChainActionType.Swap
216                case FlareFDCTriggers.TriggerType.LiquidityChange:
217                    return CrossChainActionType.LiquidityProvision
218                case FlareFDCTriggers.TriggerType.VolumeSpike:
219                    return CrossChainActionType.Swap
220                case FlareFDCTriggers.TriggerType.DefiProtocolEvent:
221                    return CrossChainActionType.Compound
222                default:
223                    return CrossChainActionType.TokenTransfer
224            }
225        }
226        
227        access(self) fun generateMessageId(_ trigger: FlareFDCTriggers.FDCTrigger): String {
228            return "fdc-".concat(trigger.id).concat("-").concat(getCurrentBlock().timestamp.toString())
229        }
230        
231        init() {
232            self.supportedTypes = [
233                FlareFDCTriggers.TriggerType.PriceThreshold,
234                FlareFDCTriggers.TriggerType.VolumeSpike,
235                FlareFDCTriggers.TriggerType.LiquidityChange,
236                FlareFDCTriggers.TriggerType.DefiProtocolEvent
237            ]
238            self.isHandlerActive = true
239            self.chainMapping = {
240                "0": 101,   // Ethereum
241                "1": 102,   // BSC
242                "2": 109,   // Polygon
243                "3": 110,   // Arbitrum
244                "4": 111,   // Optimism
245                "5": 106    // Avalanche
246            }
247        }
248    }
249    
250    /// Message storage for cross-chain communication
251    access(self) var pendingMessages: {String: CrossChainMessage}
252    access(self) var messageNonce: UInt256
253    
254    /// Send cross-chain message via LayerZero
255    access(all) fun sendCrossChainMessage(_ message: CrossChainMessage) {
256        self.pendingMessages[message.messageId] = message
257        
258        // In real implementation, this would call LayerZero endpoint
259        emit CrossChainMessageSent(
260            messageId: message.messageId,
261            targetChain: message.targetChain,
262            payload: self.encodeMessage(message),
263            gasLimit: message.gasLimit
264        )
265    }
266    
267    /// Receive cross-chain message from LayerZero
268    access(all) fun receiveCrossChainMessage(
269        messageId: String,
270        sourceChain: UInt16,
271        payload: String
272    ) {
273        emit CrossChainMessageReceived(
274            messageId: messageId,
275            sourceChain: sourceChain,
276            payload: payload
277        )
278    }
279    
280    /// Factory functions
281    access(all) fun createLayerZeroMessageSink(
282        targetChain: UInt16,
283        actionType: CrossChainActionType,
284        uniqueID: DeFiActions.UniqueIdentifier?
285    ): LayerZeroMessageSink {
286        return LayerZeroMessageSink(
287            targetChain: targetChain,
288            actionType: actionType,
289            uniqueID: uniqueID
290        )
291    }
292    
293    access(all) fun createFDCHandler(): @FDCLayerZeroHandler {
294        return <- create FDCLayerZeroHandler()
295    }
296    
297    access(self) fun encodeMessage(_ message: CrossChainMessage): String {
298        // Encode message for LayerZero transmission
299        return message.messageId.concat(":").concat(message.actionType.rawValue.toString())
300    }
301    
302    init() {
303        self.pendingMessages = {}
304        self.messageNonce = 0
305        
306        // Initialize LayerZero chain IDs
307        self.ChainIds = {
308            "Flow": 114,        // Flow (hypothetical LZ chain ID)
309            "Ethereum": 101,
310            "BSC": 102,
311            "Polygon": 109,
312            "Arbitrum": 110,
313            "Optimism": 111,
314            "Avalanche": 106
315        }
316    }
317}