Smart Contract
FlowEVMBridgeHandlerInterfaces
A.1e4aa0b87d10b141.FlowEVMBridgeHandlerInterfaces
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