@flowtyio/flow-contracts 0.1.0-beta.9 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/contracts/FungibleTokenSwitchboard.cdc +360 -0
- package/contracts/MetadataViews.cdc +79 -6
- package/contracts/NonFungibleToken.cdc +17 -10
- package/contracts/capability-cache/CapabilityCache.cdc +97 -0
- package/contracts/dapper/TopShot.cdc +323 -259
- package/contracts/dapper/TopShotLocking.cdc +41 -15
- package/contracts/dapper/offers/DapperOffersV2.cdc +46 -43
- package/contracts/dapper/offers/OffersV2.cdc +40 -56
- package/contracts/dapper/offers/Resolver.cdc +20 -13
- package/contracts/emerald-city/FLOAT.cdc +259 -254
- package/contracts/evm/CrossVMNFT.cdc +50 -0
- package/contracts/evm/EVM.cdc +851 -0
- package/contracts/evm/FlowEVMBridgeConfig.cdc +454 -0
- package/contracts/evm/FlowEVMBridgeHandlerInterfaces.cdc +163 -0
- package/contracts/evm/FlowEVMBridgeHandlers.cdc +230 -0
- package/contracts/evm/FlowEVMBridgeUtils.cdc +1303 -0
- package/contracts/evm/IBridgePermissions.cdc +19 -0
- package/contracts/evm/ICrossVM.cdc +12 -0
- package/contracts/evm/ICrossVMAsset.cdc +19 -0
- package/contracts/evm/Serialize.cdc +141 -0
- package/contracts/evm/SerializeMetadata.cdc +221 -0
- package/contracts/example/ExampleNFT.cdc +2 -2
- package/contracts/find/FindViews.cdc +357 -353
- package/contracts/flow-utils/ScopedFTProviders.cdc +5 -2
- package/contracts/flow-utils/ScopedNFTProviders.cdc +6 -2
- package/contracts/flowty-drops/ContractManager.cdc +73 -0
- package/contracts/flowty-drops/DropFactory.cdc +75 -0
- package/contracts/flowty-drops/DropTypes.cdc +282 -0
- package/contracts/flowty-drops/FlowtyActiveCheckers.cdc +113 -0
- package/contracts/flowty-drops/FlowtyAddressVerifiers.cdc +64 -0
- package/contracts/flowty-drops/FlowtyDrops.cdc +461 -0
- package/contracts/flowty-drops/FlowtyPricers.cdc +48 -0
- package/contracts/flowty-drops/initializers/ContractBorrower.cdc +14 -0
- package/contracts/flowty-drops/initializers/ContractInitializer.cdc +7 -0
- package/contracts/flowty-drops/initializers/OpenEditionInitializer.cdc +57 -0
- package/contracts/flowty-drops/nft/BaseCollection.cdc +97 -0
- package/contracts/flowty-drops/nft/BaseNFT.cdc +107 -0
- package/contracts/flowty-drops/nft/ContractFactory.cdc +13 -0
- package/contracts/flowty-drops/nft/ContractFactoryTemplate.cdc +48 -0
- package/contracts/flowty-drops/nft/NFTMetadata.cdc +140 -0
- package/contracts/flowty-drops/nft/OpenEditionNFT.cdc +42 -0
- package/contracts/flowty-drops/nft/OpenEditionTemplate.cdc +54 -0
- package/contracts/flowty-drops/nft/UniversalCollection.cdc +29 -0
- package/contracts/fungible-token-router/FungibleTokenRouter.cdc +103 -0
- package/contracts/hybrid-custody/CapabilityDelegator.cdc +28 -26
- package/contracts/hybrid-custody/CapabilityFactory.cdc +20 -18
- package/contracts/hybrid-custody/CapabilityFilter.cdc +41 -24
- package/contracts/hybrid-custody/HybridCustody.cdc +303 -242
- package/contracts/hybrid-custody/factories/FTAllFactory.cdc +16 -4
- package/contracts/hybrid-custody/factories/FTBalanceFactory.cdc +16 -4
- package/contracts/hybrid-custody/factories/FTProviderFactory.cdc +17 -5
- package/contracts/hybrid-custody/factories/FTReceiverBalanceFactory.cdc +16 -4
- package/contracts/hybrid-custody/factories/FTReceiverFactory.cdc +16 -4
- package/contracts/hybrid-custody/factories/FTVaultFactory.cdc +46 -0
- package/contracts/hybrid-custody/factories/NFTCollectionFactory.cdc +45 -0
- package/contracts/hybrid-custody/factories/NFTCollectionPublicFactory.cdc +16 -4
- package/contracts/hybrid-custody/factories/NFTProviderAndCollectionFactory.cdc +22 -0
- package/contracts/hybrid-custody/factories/NFTProviderFactory.cdc +16 -4
- package/contracts/lost-and-found/LostAndFound.cdc +21 -17
- package/contracts/tokens/USDCFlow.cdc +232 -0
- package/flow.json +278 -7
- package/package.json +1 -1
- package/contracts/hybrid-custody/factories/NFTProviderAndCollectionPublicFactory.cdc +0 -10
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
import "EVM"
|
|
2
|
+
|
|
3
|
+
import "FlowToken"
|
|
4
|
+
|
|
5
|
+
import "FlowEVMBridgeHandlerInterfaces"
|
|
6
|
+
|
|
7
|
+
/// This contract is used to store configuration information shared by FlowEVMBridge contracts
|
|
8
|
+
///
|
|
9
|
+
access(all)
|
|
10
|
+
contract FlowEVMBridgeConfig {
|
|
11
|
+
|
|
12
|
+
/******************
|
|
13
|
+
Entitlements
|
|
14
|
+
*******************/
|
|
15
|
+
|
|
16
|
+
access(all) entitlement Gas
|
|
17
|
+
access(all) entitlement Fee
|
|
18
|
+
access(all) entitlement Pause
|
|
19
|
+
|
|
20
|
+
/*************
|
|
21
|
+
Fields
|
|
22
|
+
**************/
|
|
23
|
+
|
|
24
|
+
/// Amount of FLOW paid to onboard a Type or EVMAddress to the bridge
|
|
25
|
+
access(all)
|
|
26
|
+
var onboardFee: UFix64
|
|
27
|
+
/// Flat rate fee for all bridge requests
|
|
28
|
+
access(all)
|
|
29
|
+
var baseFee: UFix64
|
|
30
|
+
/// Default ERC20.decimals() value
|
|
31
|
+
access(all)
|
|
32
|
+
let defaultDecimals: UInt8
|
|
33
|
+
/// The gas limit for all EVM calls related to bridge operations
|
|
34
|
+
access(all)
|
|
35
|
+
var gasLimit: UInt64
|
|
36
|
+
/// Flag enabling pausing of bridge operations
|
|
37
|
+
access(self)
|
|
38
|
+
var paused: Bool
|
|
39
|
+
/// Mapping of Type to its associated EVMAddress. The contained struct values also store the operational status of
|
|
40
|
+
/// the association, allowing for pausing of operations by Type
|
|
41
|
+
access(self) let registeredTypes: {Type: TypeEVMAssociation}
|
|
42
|
+
/// Reverse mapping of registeredTypes. Note the EVMAddress is stored as a hex string since the EVMAddress type
|
|
43
|
+
/// as of contract development is not a hashable or equatable type and making it so is not supported by Cadence
|
|
44
|
+
access(self)
|
|
45
|
+
let evmAddressHexToType: {String: Type}
|
|
46
|
+
/// Mapping of Type to its associated EVMAddress as relevant to the bridge
|
|
47
|
+
access(self)
|
|
48
|
+
let typeToTokenHandlers: @{Type: {FlowEVMBridgeHandlerInterfaces.TokenHandler}}
|
|
49
|
+
|
|
50
|
+
/********************
|
|
51
|
+
Path Constants
|
|
52
|
+
*********************/
|
|
53
|
+
|
|
54
|
+
/// StoragePath where bridge Cadence Owned Account is stored
|
|
55
|
+
access(all)
|
|
56
|
+
let coaStoragePath: StoragePath
|
|
57
|
+
/// StoragePath where bridge config Admin is stored
|
|
58
|
+
access(all)
|
|
59
|
+
let adminStoragePath: StoragePath
|
|
60
|
+
/// PublicPath where a public Capability on the bridge config Admin is exposed
|
|
61
|
+
access(all)
|
|
62
|
+
let adminPublicPath: PublicPath
|
|
63
|
+
/// StoragePath to store the Provider capability used as a bridge fee Provider
|
|
64
|
+
access(all)
|
|
65
|
+
let providerCapabilityStoragePath: StoragePath
|
|
66
|
+
|
|
67
|
+
/*************
|
|
68
|
+
Events
|
|
69
|
+
**************/
|
|
70
|
+
|
|
71
|
+
/// Emitted whenever the onboarding fee is updated
|
|
72
|
+
///
|
|
73
|
+
access(all)
|
|
74
|
+
event BridgeFeeUpdated(old: UFix64, new: UFix64, isOnboarding: Bool)
|
|
75
|
+
/// Emitted whenever a TokenHandler is configured
|
|
76
|
+
///
|
|
77
|
+
access(all)
|
|
78
|
+
event HandlerConfigured(targetType: String, targetEVMAddress: String?, isEnabled: Bool)
|
|
79
|
+
/// Emitted whenever the bridge is paused or unpaused globally - true for paused, false for unpaused
|
|
80
|
+
///
|
|
81
|
+
access(all)
|
|
82
|
+
event BridgePauseStatusUpdated(paused: Bool)
|
|
83
|
+
/// Emitted whenever a specific asset is paused or unpaused - true for paused, false for unpaused
|
|
84
|
+
///
|
|
85
|
+
access(all)
|
|
86
|
+
event AssetPauseStatusUpdated(paused: Bool, type: String, evmAddress: String)
|
|
87
|
+
/// Emitted whenever an association is updated
|
|
88
|
+
///
|
|
89
|
+
access(all)
|
|
90
|
+
event AssociationUpdated(type: String, evmAddress: String)
|
|
91
|
+
|
|
92
|
+
/*************
|
|
93
|
+
Getters
|
|
94
|
+
*************/
|
|
95
|
+
|
|
96
|
+
/// Returns whether all bridge operations are currently paused or active
|
|
97
|
+
///
|
|
98
|
+
access(all)
|
|
99
|
+
view fun isPaused(): Bool {
|
|
100
|
+
return self.paused
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/// Returns whether operations for a given Type are paused. A return value of nil indicates the Type is not yet
|
|
104
|
+
/// onboarded to the bridge.
|
|
105
|
+
///
|
|
106
|
+
access(all)
|
|
107
|
+
view fun isTypePaused(_ type: Type): Bool? {
|
|
108
|
+
if !self.typeHasTokenHandler(type) {
|
|
109
|
+
// Most all assets will fall into this block - check if the asset is onboarded and paused
|
|
110
|
+
return self.registeredTypes[type]?.isPaused ?? nil
|
|
111
|
+
}
|
|
112
|
+
// If the asset has a TokenHandler, return true if either the Handler is paused or the type is paused
|
|
113
|
+
return self.borrowTokenHandler(type)!.isEnabled() == false || self.registeredTypes[type]?.isPaused == true
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/// Retrieves the EVMAddress associated with a given Type if it has been onboarded to the bridge
|
|
117
|
+
///
|
|
118
|
+
access(all)
|
|
119
|
+
view fun getEVMAddressAssociated(with type: Type): EVM.EVMAddress? {
|
|
120
|
+
return self.registeredTypes[type]?.evmAddress
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/// Retrieves the type associated with a given EVMAddress if it has been onboarded to the bridge
|
|
124
|
+
///
|
|
125
|
+
access(all)
|
|
126
|
+
view fun getTypeAssociated(with evmAddress: EVM.EVMAddress): Type? {
|
|
127
|
+
let evmAddressHex = evmAddress.toString()
|
|
128
|
+
return self.evmAddressHexToType[evmAddressHex]
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/****************************
|
|
132
|
+
Bridge Account Methods
|
|
133
|
+
****************************/
|
|
134
|
+
|
|
135
|
+
/// Enables bridge contracts to add new associations between types and EVM addresses
|
|
136
|
+
///
|
|
137
|
+
access(account)
|
|
138
|
+
fun associateType(_ type: Type, with evmAddress: EVM.EVMAddress) {
|
|
139
|
+
pre {
|
|
140
|
+
self.getEVMAddressAssociated(with: type) == nil: "Type already associated with an EVMAddress"
|
|
141
|
+
self.getTypeAssociated(with: evmAddress) == nil: "EVMAddress already associated with a Type"
|
|
142
|
+
}
|
|
143
|
+
self.registeredTypes[type] = TypeEVMAssociation(associated: evmAddress)
|
|
144
|
+
let evmAddressHex = evmAddress.toString()
|
|
145
|
+
self.evmAddressHexToType[evmAddressHex] = type
|
|
146
|
+
|
|
147
|
+
emit AssociationUpdated(type: type.identifier, evmAddress: evmAddressHex)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/// Returns whether the given Type has a TokenHandler configured
|
|
151
|
+
///
|
|
152
|
+
access(account)
|
|
153
|
+
view fun typeHasTokenHandler(_ type: Type): Bool {
|
|
154
|
+
return self.typeToTokenHandlers[type] != nil
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/// Returns whether the given EVMAddress has a TokenHandler configured
|
|
158
|
+
///
|
|
159
|
+
access(account)
|
|
160
|
+
view fun evmAddressHasTokenHandler(_ evmAddress: EVM.EVMAddress): Bool {
|
|
161
|
+
let associatedType = self.getTypeAssociated(with: evmAddress)
|
|
162
|
+
return associatedType != nil ? self.typeHasTokenHandler(associatedType!) : false
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/// Adds a TokenHandler to the bridge configuration
|
|
166
|
+
///
|
|
167
|
+
access(account)
|
|
168
|
+
fun addTokenHandler(_ handler: @{FlowEVMBridgeHandlerInterfaces.TokenHandler}) {
|
|
169
|
+
pre {
|
|
170
|
+
handler.getTargetType() != nil: "Cannot configure Handler without a target Cadence Type set"
|
|
171
|
+
self.getEVMAddressAssociated(with: handler.getTargetType()!) == nil:
|
|
172
|
+
"Cannot configure Handler for Type that has already been onboarded to the bridge"
|
|
173
|
+
self.borrowTokenHandler(handler.getTargetType()!) == nil:
|
|
174
|
+
"Cannot configure Handler for Type that already has a Handler configured"
|
|
175
|
+
}
|
|
176
|
+
let type = handler.getTargetType()!
|
|
177
|
+
var targetEVMAddressHex: String? = nil
|
|
178
|
+
if let targetEVMAddress = handler.getTargetEVMAddress() {
|
|
179
|
+
targetEVMAddressHex = targetEVMAddress.toString()
|
|
180
|
+
|
|
181
|
+
let associatedType = self.getTypeAssociated(with: targetEVMAddress)
|
|
182
|
+
assert(
|
|
183
|
+
associatedType == nil,
|
|
184
|
+
message: "Handler target EVMAddress is already associated with a different Type"
|
|
185
|
+
)
|
|
186
|
+
self.associateType(type, with: targetEVMAddress)
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
emit HandlerConfigured(
|
|
190
|
+
targetType: type.identifier,
|
|
191
|
+
targetEVMAddress: targetEVMAddressHex,
|
|
192
|
+
isEnabled: handler.isEnabled()
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
self.typeToTokenHandlers[type] <-! handler
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/// Returns an unentitled reference to the TokenHandler associated with the given Type
|
|
199
|
+
///
|
|
200
|
+
access(account)
|
|
201
|
+
view fun borrowTokenHandler(
|
|
202
|
+
_ type: Type
|
|
203
|
+
): &{FlowEVMBridgeHandlerInterfaces.TokenHandler}? {
|
|
204
|
+
return &self.typeToTokenHandlers[type]
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/// Returns an entitled reference to the TokenHandler associated with the given Type
|
|
208
|
+
///
|
|
209
|
+
access(self)
|
|
210
|
+
view fun borrowTokenHandlerAdmin(
|
|
211
|
+
_ type: Type
|
|
212
|
+
): auth(FlowEVMBridgeHandlerInterfaces.Admin) &{FlowEVMBridgeHandlerInterfaces.TokenHandler}? {
|
|
213
|
+
return &self.typeToTokenHandlers[type]
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/*****************
|
|
217
|
+
Constructs
|
|
218
|
+
*****************/
|
|
219
|
+
|
|
220
|
+
/// Entry in the registeredTypes mapping, associating a Type with an EVMAddress and its operational status. Since
|
|
221
|
+
/// the registeredTypes mapping is indexed on Type, this struct does not additionally store the Type to reduce
|
|
222
|
+
/// redundant storage.
|
|
223
|
+
///
|
|
224
|
+
access(all) struct TypeEVMAssociation {
|
|
225
|
+
/// The EVMAddress associated with the Type
|
|
226
|
+
access(all) let evmAddress: EVM.EVMAddress
|
|
227
|
+
/// Flag indicating whether operations for the associated Type are paused
|
|
228
|
+
access(all) var isPaused: Bool
|
|
229
|
+
|
|
230
|
+
init(associated evmAddress: EVM.EVMAddress) {
|
|
231
|
+
self.evmAddress = evmAddress
|
|
232
|
+
self.isPaused = false
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/// Pauses operations for this association
|
|
236
|
+
///
|
|
237
|
+
access(contract) fun pause() {
|
|
238
|
+
self.isPaused = true
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/// Unpauses operations for this association
|
|
242
|
+
///
|
|
243
|
+
access(contract) fun unpause() {
|
|
244
|
+
self.isPaused = false
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/*****************
|
|
249
|
+
Config Admin
|
|
250
|
+
*****************/
|
|
251
|
+
|
|
252
|
+
/// Admin resource enables updates to the bridge fees
|
|
253
|
+
///
|
|
254
|
+
access(all)
|
|
255
|
+
resource Admin {
|
|
256
|
+
|
|
257
|
+
/// Sets the TokenMinter for the given Type. If a TokenHandler does not exist for the given Type, the operation
|
|
258
|
+
/// reverts. The provided minter must be of the expected type for the TokenHandler and the handler cannot have
|
|
259
|
+
/// a minter already set.
|
|
260
|
+
///
|
|
261
|
+
/// @param targetType: Cadence type indexing the relevant TokenHandler
|
|
262
|
+
/// @param minter: TokenMinter minter to set for the TokenHandler
|
|
263
|
+
///
|
|
264
|
+
access(all)
|
|
265
|
+
fun setTokenHandlerMinter(targetType: Type, minter: @{FlowEVMBridgeHandlerInterfaces.TokenMinter}) {
|
|
266
|
+
pre {
|
|
267
|
+
FlowEVMBridgeConfig.typeHasTokenHandler(targetType):
|
|
268
|
+
"Cannot set minter for Type that does not have a TokenHandler configured"
|
|
269
|
+
FlowEVMBridgeConfig.borrowTokenHandlerAdmin(targetType) != nil:
|
|
270
|
+
"No handler found for target Type"
|
|
271
|
+
FlowEVMBridgeConfig.borrowTokenHandlerAdmin(targetType)!.getExpectedMinterType() == minter.getType():
|
|
272
|
+
"Invalid minter type"
|
|
273
|
+
}
|
|
274
|
+
FlowEVMBridgeConfig.borrowTokenHandlerAdmin(targetType)!.setMinter(<-minter)
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/// Sets the gas limit for all EVM calls related to bridge operations
|
|
278
|
+
///
|
|
279
|
+
/// @param lim the new gas limit
|
|
280
|
+
///
|
|
281
|
+
access(Gas)
|
|
282
|
+
fun setGasLimit(_ limit: UInt64) {
|
|
283
|
+
FlowEVMBridgeConfig.gasLimit = limit
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/// Updates the onboarding fee
|
|
287
|
+
///
|
|
288
|
+
/// @param new: UFix64 - new onboarding fee
|
|
289
|
+
///
|
|
290
|
+
/// @emits BridgeFeeUpdated with the old and new rates and isOnboarding set to true
|
|
291
|
+
///
|
|
292
|
+
access(Fee)
|
|
293
|
+
fun updateOnboardingFee(_ new: UFix64) {
|
|
294
|
+
emit BridgeFeeUpdated(old: FlowEVMBridgeConfig.onboardFee, new: new, isOnboarding: true)
|
|
295
|
+
FlowEVMBridgeConfig.onboardFee = new
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/// Updates the base fee
|
|
299
|
+
///
|
|
300
|
+
/// @param new: UFix64 - new base fee
|
|
301
|
+
///
|
|
302
|
+
/// @emits BridgeFeeUpdated with the old and new rates and isOnboarding set to false
|
|
303
|
+
///
|
|
304
|
+
access(Fee)
|
|
305
|
+
fun updateBaseFee(_ new: UFix64) {
|
|
306
|
+
emit BridgeFeeUpdated(old: FlowEVMBridgeConfig.baseFee, new: new, isOnboarding: false)
|
|
307
|
+
FlowEVMBridgeConfig.baseFee = new
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/// Pauses the bridge, preventing all bridge operations
|
|
311
|
+
///
|
|
312
|
+
access(Pause)
|
|
313
|
+
fun pauseBridge() {
|
|
314
|
+
if FlowEVMBridgeConfig.isPaused() {
|
|
315
|
+
return
|
|
316
|
+
}
|
|
317
|
+
FlowEVMBridgeConfig.paused = true
|
|
318
|
+
emit BridgePauseStatusUpdated(paused: true)
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/// Unpauses the bridge, allowing bridge operations to resume
|
|
322
|
+
///
|
|
323
|
+
access(Pause)
|
|
324
|
+
fun unpauseBridge() {
|
|
325
|
+
if !FlowEVMBridgeConfig.isPaused() {
|
|
326
|
+
return
|
|
327
|
+
}
|
|
328
|
+
FlowEVMBridgeConfig.paused = false
|
|
329
|
+
emit BridgePauseStatusUpdated(paused: false)
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/// Pauses all operations for a given asset type
|
|
333
|
+
///
|
|
334
|
+
access(Pause)
|
|
335
|
+
fun pauseType(_ type: Type) {
|
|
336
|
+
let association = &FlowEVMBridgeConfig.registeredTypes[type] as &TypeEVMAssociation?
|
|
337
|
+
?? panic("Type not associated with an EVM Address")
|
|
338
|
+
|
|
339
|
+
if association.isPaused {
|
|
340
|
+
return
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
association.pause()
|
|
344
|
+
|
|
345
|
+
let evmAddress = association.evmAddress.toString()
|
|
346
|
+
emit AssetPauseStatusUpdated(paused: true, type: type.identifier, evmAddress: evmAddress)
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/// Unpauses all operations for a given asset type
|
|
350
|
+
///
|
|
351
|
+
access(Pause)
|
|
352
|
+
fun unpauseType(_ type: Type) {
|
|
353
|
+
let association = &FlowEVMBridgeConfig.registeredTypes[type] as &TypeEVMAssociation?
|
|
354
|
+
?? panic("Type not associated with an EVM Address")
|
|
355
|
+
|
|
356
|
+
if !association.isPaused {
|
|
357
|
+
return
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
association.unpause()
|
|
361
|
+
let evmAddress = association.evmAddress.toString()
|
|
362
|
+
emit AssetPauseStatusUpdated(paused: false, type: type.identifier, evmAddress: evmAddress)
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/// Sets the target EVM contract address on the handler for a given Type, associating the Cadence type with the
|
|
366
|
+
/// provided EVM address. If a TokenHandler does not exist for the given Type, the operation reverts.
|
|
367
|
+
///
|
|
368
|
+
/// @param targetType: Cadence type to associate with the target EVM address
|
|
369
|
+
/// @param targetEVMAddress: target EVM address to associate with the Cadence type
|
|
370
|
+
///
|
|
371
|
+
/// @emits HandlerConfigured with the target Type, target EVM address, and whether the handler is enabled
|
|
372
|
+
///
|
|
373
|
+
access(FlowEVMBridgeHandlerInterfaces.Admin)
|
|
374
|
+
fun setHandlerTargetEVMAddress(targetType: Type, targetEVMAddress: EVM.EVMAddress) {
|
|
375
|
+
pre {
|
|
376
|
+
FlowEVMBridgeConfig.getEVMAddressAssociated(with: targetType) == nil:
|
|
377
|
+
"Type already associated with an EVM Address"
|
|
378
|
+
FlowEVMBridgeConfig.getTypeAssociated(with: targetEVMAddress) == nil:
|
|
379
|
+
"EVM Address already associated with another Type"
|
|
380
|
+
}
|
|
381
|
+
let handler = FlowEVMBridgeConfig.borrowTokenHandlerAdmin(targetType)
|
|
382
|
+
?? panic("No handler found for target Type")
|
|
383
|
+
handler.setTargetEVMAddress(targetEVMAddress)
|
|
384
|
+
|
|
385
|
+
// Get the EVM address currently associated with the target Type. If the association does not exist or the
|
|
386
|
+
// EVM address is different, update the association
|
|
387
|
+
FlowEVMBridgeConfig.associateType(targetType, with: targetEVMAddress)
|
|
388
|
+
assert(
|
|
389
|
+
FlowEVMBridgeConfig.getEVMAddressAssociated(with: targetType)!.equals(targetEVMAddress),
|
|
390
|
+
message: "Problem associating target Type and target EVM Address"
|
|
391
|
+
)
|
|
392
|
+
|
|
393
|
+
emit HandlerConfigured(
|
|
394
|
+
targetType: targetType.identifier,
|
|
395
|
+
targetEVMAddress: targetEVMAddress.toString(),
|
|
396
|
+
isEnabled: handler.isEnabled()
|
|
397
|
+
)
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/// Enables the TokenHandler for the given Type. If a TokenHandler does not exist for the given Type, the
|
|
401
|
+
/// operation reverts.
|
|
402
|
+
///
|
|
403
|
+
/// @param targetType: Cadence type indexing the relevant TokenHandler
|
|
404
|
+
///
|
|
405
|
+
/// @emits HandlerConfigured with the target Type, target EVM address, and whether the handler is enabled
|
|
406
|
+
///
|
|
407
|
+
access(FlowEVMBridgeHandlerInterfaces.Admin)
|
|
408
|
+
fun enableHandler(targetType: Type) {
|
|
409
|
+
let handler = FlowEVMBridgeConfig.borrowTokenHandlerAdmin(targetType)
|
|
410
|
+
?? panic("No handler found for target Type")
|
|
411
|
+
handler.enableBridging()
|
|
412
|
+
|
|
413
|
+
let targetEVMAddressHex = handler.getTargetEVMAddress()?.toString()
|
|
414
|
+
?? panic("Handler cannot be enabled without a target EVM Address")
|
|
415
|
+
|
|
416
|
+
emit HandlerConfigured(
|
|
417
|
+
targetType: handler.getTargetType()!.identifier,
|
|
418
|
+
targetEVMAddress: targetEVMAddressHex,
|
|
419
|
+
isEnabled: handler.isEnabled()
|
|
420
|
+
)
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
init() {
|
|
425
|
+
self.onboardFee = 0.0
|
|
426
|
+
self.baseFee = 0.0
|
|
427
|
+
self.defaultDecimals = 18
|
|
428
|
+
self.gasLimit = 15_000_000
|
|
429
|
+
self.paused = true
|
|
430
|
+
|
|
431
|
+
// Although $FLOW does not have ERC20 address, we associate the the Vault with the EVM address from which
|
|
432
|
+
// EVM transfers originate
|
|
433
|
+
// See FLIP #223 - https://github.com/onflow/flips/pull/225
|
|
434
|
+
let flowOriginationAddress = EVM.EVMAddress(
|
|
435
|
+
bytes: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0]
|
|
436
|
+
)
|
|
437
|
+
let flowVaultType = Type<@FlowToken.Vault>()
|
|
438
|
+
let flowOriginationAddressHex = flowOriginationAddress.toString()
|
|
439
|
+
self.registeredTypes = { flowVaultType: TypeEVMAssociation(associated: flowOriginationAddress) }
|
|
440
|
+
self.evmAddressHexToType = { flowOriginationAddressHex: flowVaultType }
|
|
441
|
+
|
|
442
|
+
self.typeToTokenHandlers <- {}
|
|
443
|
+
|
|
444
|
+
self.adminStoragePath = /storage/flowEVMBridgeConfigAdmin
|
|
445
|
+
self.adminPublicPath = /public/flowEVMBridgeConfigAdmin
|
|
446
|
+
self.coaStoragePath = /storage/evm
|
|
447
|
+
self.providerCapabilityStoragePath = /storage/bridgeFlowVaultProvider
|
|
448
|
+
|
|
449
|
+
// Create & save Admin, issuing a public unentitled Admin Capability
|
|
450
|
+
self.account.storage.save(<-create Admin(), to: self.adminStoragePath)
|
|
451
|
+
let adminCap = self.account.capabilities.storage.issue<&Admin>(self.adminStoragePath)
|
|
452
|
+
self.account.capabilities.publish(adminCap, at: self.adminPublicPath)
|
|
453
|
+
}
|
|
454
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import "FungibleToken"
|
|
2
|
+
import "NonFungibleToken"
|
|
3
|
+
|
|
4
|
+
import "EVM"
|
|
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
|
+
///
|
|
14
|
+
access(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
|
+
access(all) event MinterSet(handlerType: String,
|
|
37
|
+
handlerUUID: UInt64,
|
|
38
|
+
targetType: String?,
|
|
39
|
+
targetEVMAddress: String?,
|
|
40
|
+
minterType: String,
|
|
41
|
+
minterUUID: UInt64
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
/****************
|
|
45
|
+
Constructs
|
|
46
|
+
*****************/
|
|
47
|
+
|
|
48
|
+
/// Non-privileged interface for querying handler information
|
|
49
|
+
///
|
|
50
|
+
access(all) resource interface HandlerInfo {
|
|
51
|
+
/// Returns whether the Handler is enabled
|
|
52
|
+
access(all) view fun isEnabled(): Bool
|
|
53
|
+
/// Returns the Cadence type handled by the Handler, nil if not set
|
|
54
|
+
access(all) view fun getTargetType(): Type?
|
|
55
|
+
/// Returns the EVM address handled by the Handler, nil if not set
|
|
56
|
+
access(all) view fun getTargetEVMAddress(): EVM.EVMAddress?
|
|
57
|
+
/// Returns the Type of the expected minter if the handler utilizes one
|
|
58
|
+
access(all) view fun getExpectedMinterType(): Type?
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/// Administrative interface for Handler configuration
|
|
62
|
+
///
|
|
63
|
+
access(all) resource interface HandlerAdmin : HandlerInfo {
|
|
64
|
+
/// Sets the target Cadence Type handled by this resource. Once the targe type is set - whether by this method
|
|
65
|
+
/// or on initialization - this setter will fail.
|
|
66
|
+
access(Admin) fun setTargetType(_ type: Type) {
|
|
67
|
+
pre {
|
|
68
|
+
self.getTargetType() == nil: "Target Type has already been set"
|
|
69
|
+
}
|
|
70
|
+
post {
|
|
71
|
+
self.getTargetType()! == type: "Problem setting target type"
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/// Sets the target EVM address handled by this resource
|
|
75
|
+
access(Admin) fun setTargetEVMAddress(_ address: EVM.EVMAddress) {
|
|
76
|
+
pre {
|
|
77
|
+
self.getTargetEVMAddress() == nil: "Target EVM address has already been set"
|
|
78
|
+
}
|
|
79
|
+
post {
|
|
80
|
+
self.getTargetEVMAddress()!.equals(address!): "Problem setting target EVM address"
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
access(Admin) fun setMinter(_ minter: @{FlowEVMBridgeHandlerInterfaces.TokenMinter}) {
|
|
84
|
+
pre {
|
|
85
|
+
self.getExpectedMinterType() == minter.getType(): "Minter is not of the expected type"
|
|
86
|
+
minter.getMintedType() == self.getTargetType(): "Minter does not mint the target type"
|
|
87
|
+
emit MinterSet(
|
|
88
|
+
handlerType: self.getType().identifier,
|
|
89
|
+
handlerUUID: self.uuid,
|
|
90
|
+
targetType: self.getTargetType()?.identifier,
|
|
91
|
+
targetEVMAddress: self.getTargetEVMAddress()?.toString(),
|
|
92
|
+
minterType: minter.getType().identifier,
|
|
93
|
+
minterUUID: minter.uuid
|
|
94
|
+
)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/// Enables the Handler to fulfill bridge requests for the configured targets. If implementers utilize a minter,
|
|
98
|
+
/// they should additionally ensure the minter is set before enabling.
|
|
99
|
+
access(Admin) fun enableBridging() {
|
|
100
|
+
pre {
|
|
101
|
+
self.getTargetType() != nil && self.getTargetEVMAddress() != nil:
|
|
102
|
+
"Cannot enable before setting bridge targets"
|
|
103
|
+
!self.isEnabled(): "Handler already enabled"
|
|
104
|
+
}
|
|
105
|
+
post {
|
|
106
|
+
self.isEnabled(): "Problem enabling Handler"
|
|
107
|
+
emit HandlerEnabled(
|
|
108
|
+
handlerType: self.getType().identifier,
|
|
109
|
+
handlerUUID: self.uuid,
|
|
110
|
+
targetType: self.getTargetType()!.identifier,
|
|
111
|
+
targetEVMAddress: self.getTargetEVMAddress()!.toString()
|
|
112
|
+
)
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/// Minter interface for configurations requiring the minting of Cadence fungible tokens
|
|
118
|
+
///
|
|
119
|
+
access(all) resource interface TokenMinter {
|
|
120
|
+
/// Returns the Cadence type minted by this resource
|
|
121
|
+
access(all) view fun getMintedType(): Type
|
|
122
|
+
/// Mints the specified amount of tokens
|
|
123
|
+
access(Mint) fun mint(amount: UFix64): @{FungibleToken.Vault} {
|
|
124
|
+
pre {
|
|
125
|
+
amount > 0.0: "Amount must be greater than 0"
|
|
126
|
+
}
|
|
127
|
+
post {
|
|
128
|
+
result.getType() == self.getMintedType(): "Invalid Vault type returned"
|
|
129
|
+
result.balance == amount: "Minted amount does not match requested amount"
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/// Handler interface for bridging FungibleToken assets. Implementations should be stored within the bridge account
|
|
135
|
+
/// and called be the bridge contract for bridging operations on the Handler's target Type and EVM contract.
|
|
136
|
+
///
|
|
137
|
+
access(all) resource interface TokenHandler : HandlerAdmin {
|
|
138
|
+
/// Fulfills a request to bridge tokens from the Cadence side to the EVM side
|
|
139
|
+
access(account) fun fulfillTokensToEVM(
|
|
140
|
+
tokens: @{FungibleToken.Vault},
|
|
141
|
+
to: EVM.EVMAddress
|
|
142
|
+
) {
|
|
143
|
+
pre {
|
|
144
|
+
self.isEnabled(): "Handler is not yet enabled"
|
|
145
|
+
tokens.getType() == self.getTargetType(): "Invalid Vault type"
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
/// Fulfills a request to bridge tokens from the EVM side to the Cadence side
|
|
149
|
+
access(account) fun fulfillTokensFromEVM(
|
|
150
|
+
owner: EVM.EVMAddress,
|
|
151
|
+
type: Type,
|
|
152
|
+
amount: UInt256,
|
|
153
|
+
protectedTransferCall: fun (): EVM.Result
|
|
154
|
+
): @{FungibleToken.Vault} {
|
|
155
|
+
pre {
|
|
156
|
+
self.isEnabled(): "Handler is not yet enabled"
|
|
157
|
+
}
|
|
158
|
+
post {
|
|
159
|
+
result.getType() == self.getTargetType(): "Invalid Vault type returned"
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|