Smart Contract

FlowEVMBridgeHandlerInterfaces

A.1e4aa0b87d10b141.FlowEVMBridgeHandlerInterfaces

Valid From

85,457,484

Deployed

1w ago
Feb 16, 2026, 08:14:21 PM UTC

Dependents

6 imports
1import FungibleToken from 0xf233dcee88fe0abe
2import NonFungibleToken from 0x1d7e57aa55817448
3
4import EVM from 0xe467b9dd11fa00df
5
6/// FlowEVMBridgeHandlerInterfaces
7///
8/// This contract defines the interfaces for the FlowEVM Bridge Handlers. These Handlers are intended to encapsulate
9/// the logic for bridging edge case assets between Cadence and EVM and require configuration by the bridge account to
10/// enable. Contracts implementing these resources should be deployed to the bridge account so that privileged methods,
11/// particularly those related to fulfilling bridge requests remain in the closed loop of bridge contract logic and
12/// defined assets in the custody of the bridge account.
13///
14access(all) contract FlowEVMBridgeHandlerInterfaces {
15
16    /******************
17        Entitlements
18    *******************/
19
20    /// Entitlement related to administrative setters
21    access(all) entitlement Admin
22    /// Entitlement related to minting handled assets
23    access(all) entitlement Mint
24
25    /*************
26        Events
27    **************/
28    
29    /// Event emitted when a handler is enabled between a Cadence type and an EVM address
30    access(all) event HandlerEnabled(
31        handlerType: String,
32        handlerUUID: UInt64,
33        targetType: String,
34        targetEVMAddress: String
35    )
36    /// Event emitted when a handler is disabled, pausing bridging between VMs
37    access(all) event HandlerDisabled(
38        handlerType: String,
39        handlerUUID: UInt64,
40        targetType: String?,
41        targetEVMAddress: String?
42    )
43    /// Emitted when a minter resource is set in a handler
44    access(all) event MinterSet(handlerType: String,
45        handlerUUID: UInt64,
46        targetType: String?,
47        targetEVMAddress: String?,
48        minterType: String,
49        minterUUID: UInt64
50    )
51
52    /****************
53        Constructs
54    *****************/
55    
56    /// Non-privileged interface for querying handler information
57    ///
58    access(all) resource interface HandlerInfo {
59        /// Returns whether the Handler is enabled
60        access(all) view fun isEnabled(): Bool
61        /// Returns the Cadence type handled by the Handler, nil if not set
62        access(all) view fun getTargetType(): Type?
63        /// Returns the EVM address handled by the Handler, nil if not set
64        access(all) view fun getTargetEVMAddress(): EVM.EVMAddress?
65        /// Returns the Type of the expected minter if the handler utilizes one
66        access(all) view fun getExpectedMinterType(): Type?
67    }
68
69    /// Administrative interface for Handler configuration
70    ///
71    access(all) resource interface HandlerAdmin : HandlerInfo {
72        /// Sets the target Cadence Type handled by this resource. Once the targe type is set - whether by this method
73        /// or on initialization - this setter will fail.
74        access(Admin) fun setTargetType(_ type: Type) {
75            pre {
76                self.getTargetType() == nil: "Target Type has already been set"
77            }
78            post {
79                self.getTargetType()! == type: "Problem setting target type"
80            }
81        }
82        /// Sets the target EVM address handled by this resource
83        access(Admin) fun setTargetEVMAddress(_ address: EVM.EVMAddress) {
84            pre {
85                self.getTargetEVMAddress() == nil: "Target EVM address has already been set"
86            }
87            post {
88                self.getTargetEVMAddress()!.equals(address!): "Problem setting target EVM address"
89            }
90        }
91        access(Admin) fun setMinter(_ minter: @{FlowEVMBridgeHandlerInterfaces.TokenMinter}) {
92            pre {
93                self.getExpectedMinterType() == minter.getType(): "Minter is not of the expected type"
94                minter.getMintedType() == self.getTargetType(): "Minter does not mint the target type"
95                emit MinterSet(
96                    handlerType: self.getType().identifier,
97                    handlerUUID: self.uuid,
98                    targetType: self.getTargetType()?.identifier,
99                    targetEVMAddress: self.getTargetEVMAddress()?.toString(),
100                    minterType: minter.getType().identifier,
101                    minterUUID: minter.uuid
102                )
103            }
104        }
105        /// Enables the Handler to fulfill bridge requests for the configured targets. If implementers utilize a minter,
106        /// they should additionally ensure the minter is set before enabling.
107        access(Admin) fun enableBridging() {
108            pre {
109                self.getTargetType() != nil && self.getTargetEVMAddress() != nil:
110                "Cannot enable before setting bridge target Type and EVM Address"
111                !self.isEnabled(): "Handler has already been enabled"
112            }
113            post {
114                self.isEnabled(): "Problem enabling Handler"
115                emit HandlerEnabled(
116                    handlerType: self.getType().identifier,
117                    handlerUUID: self.uuid,
118                    targetType: self.getTargetType()!.identifier,
119                    targetEVMAddress: self.getTargetEVMAddress()!.toString()
120                )
121            }
122        }
123
124        /// Disables the Handler from fulfilling bridge requests.
125        access(Admin) fun disableBridging() {
126            pre {
127                self.isEnabled():
128                "Cannot disable: ".concat(self.getType().identifier).concat(" is already disabled")
129            }
130            post {
131                !self.isEnabled():
132                "Problem disabling ".concat(self.getType().identifier)
133                emit HandlerDisabled(
134                    handlerType: self.getType().identifier,
135                    handlerUUID: self.uuid,
136                    targetType: self.getTargetType()?.identifier,
137                    targetEVMAddress: self.getTargetEVMAddress()?.toString()
138                )
139            }
140        }
141    }
142
143    /// Minter interface for configurations requiring the minting of Cadence fungible tokens
144    ///
145    access(all) resource interface TokenMinter {
146        /// Returns the Cadence type minted by this resource
147        access(all) view fun getMintedType(): Type
148        /// Mints the specified amount of tokens
149        access(Mint) fun mint(amount: UFix64): @{FungibleToken.Vault} {
150            pre {
151                amount > 0.0: "Attempting to mint 0.0 - Amount minted must be greater than 0"
152            }
153            post {
154                result.getType() == self.getMintedType():
155                "TokenMinter ".concat(self.getType().identifier).concat(" with uuid ").concat(self.uuid.toString())
156                    .concat(" expected to mint ").concat(self.getMintedType().identifier)
157                    .concat(" but returned ").concat(result.getType().identifier)
158                result.balance == amount:
159                "Minted amount ".concat(result.balance.toString())
160                    .concat(" does not match requested amount ").concat(amount.toString())
161            }
162        }
163    }
164
165    /// Handler interface for bridging FungibleToken assets. Implementations should be stored within the bridge account
166    /// and called be the bridge contract for bridging operations on the Handler's target Type and EVM contract.
167    ///
168    access(all) resource interface TokenHandler : HandlerAdmin {
169        /// Fulfills a request to bridge tokens from the Cadence side to the EVM side
170        access(account) fun fulfillTokensToEVM(
171            tokens: @{FungibleToken.Vault},
172            to: EVM.EVMAddress
173        ) {
174            pre {
175                self.isEnabled():
176                "TokenHandler ".concat(self.getType().identifier).concat(" with uuid ")
177                    .concat(self.uuid.toString()).concat(" is not yet enabled")
178                tokens.getType() == self.getTargetType():
179                "TokenHandler ".concat(self.getType().identifier).concat(" with uuid ").concat(self.uuid.toString())
180                    .concat(" expects ").concat(self.getTargetType()?.identifier ?? "nil")
181                    .concat(" but received ").concat(tokens.getType().identifier)
182                tokens.balance > 0.0:
183                "Attempting to bridge 0.0 tokens - zero amounts are unsupported"
184            }
185        }
186        /// Fulfills a request to bridge tokens from the EVM side to the Cadence side
187        access(account) fun fulfillTokensFromEVM(
188            owner: EVM.EVMAddress,
189            type: Type,
190            amount: UInt256,
191            protectedTransferCall: fun (): EVM.Result
192        ): @{FungibleToken.Vault} {
193            pre {
194                self.isEnabled():
195                "TokenHandler ".concat(self.getType().identifier).concat(" with uuid ")
196                    .concat(self.uuid.toString()).concat(" is not yet enabled")
197                amount > UInt256(0): "Attempting to bridge 0 tokens from EVM - zero amounts are unsupported"
198            }
199            post {
200                result.getType() == self.getTargetType():
201                "TokenHandler ".concat(self.getType().identifier).concat(" with uuid ").concat(self.uuid.toString())
202                    .concat(" expected to return ").concat(self.getTargetType()?.identifier ?? "nil")
203                    .concat(" but returned ").concat(result.getType().identifier)
204            }
205        }
206    }
207}
208