diff --git a/cadence/contracts/bridge/FlowEVMBridge.cdc b/cadence/contracts/bridge/FlowEVMBridge.cdc index 7e3bcd95..0865994d 100644 --- a/cadence/contracts/bridge/FlowEVMBridge.cdc +++ b/cadence/contracts/bridge/FlowEVMBridge.cdc @@ -71,6 +71,8 @@ contract FlowEVMBridge : IFlowEVMNFTBridge, IFlowEVMTokenBridge { !FlowEVMBridgeConfig.isPaused(): "Bridge operations are currently paused" type != Type<@FlowToken.Vault>(): "$FLOW cannot be bridged via the VM bridge - use the CadenceOwnedAccount interface" + !FlowEVMBridgeConfig.isCadenceTypeBlocked(type): + "This Cadence Type ".concat(type.identifier).concat(" is currently blocked from being onboarded") self.typeRequiresOnboarding(type) == true: "Onboarding is not needed for this type" FlowEVMBridgeUtils.typeAllowsBridging(type): "This type is not supported as defined by the project's development team" @@ -144,7 +146,7 @@ contract FlowEVMBridge : IFlowEVMNFTBridge, IFlowEVMTokenBridge { pre { !FlowEVMBridgeConfig.isPaused(): "Bridge operations are currently paused" !FlowEVMBridgeConfig.isEVMAddressBlocked(address): - "This EVM contract is currently blocked from being onboarded" + "This EVM contract ".concat(address.toString()).concat(" is currently blocked from being onboarded") } /* Validate the EVM contract */ // diff --git a/cadence/contracts/bridge/FlowEVMBridgeConfig.cdc b/cadence/contracts/bridge/FlowEVMBridgeConfig.cdc index 0d807951..0fec0cc9 100644 --- a/cadence/contracts/bridge/FlowEVMBridgeConfig.cdc +++ b/cadence/contracts/bridge/FlowEVMBridgeConfig.cdc @@ -133,7 +133,14 @@ contract FlowEVMBridgeConfig { /// access(all) view fun isEVMAddressBlocked(_ evmAddress: EVM.EVMAddress): Bool { - return self.borrowBlocklist().isBlocked(evmAddress) + return self.borrowEVMBlocklist().isBlocked(evmAddress) + } + + /// Returns whether the given Cadence Type is currently blocked from onboarding to the bridge + /// + access(all) + view fun isCadenceTypeBlocked(_ type: Type): Bool { + return self.borrowCadenceBlocklist().isBlocked(type) } /**************************** @@ -224,9 +231,17 @@ contract FlowEVMBridgeConfig { /// Returns an entitled reference to the bridge EVMBlocklist /// access(self) - view fun borrowBlocklist(): auth(Blocklist) &EVMBlocklist { + view fun borrowEVMBlocklist(): auth(Blocklist) &EVMBlocklist { return self.account.storage.borrow(from: /storage/evmBlocklist) - ?? panic("Missing or mis-typed Blocklist in storage") + ?? panic("Missing or mis-typed EVMBlocklist in storage") + } + + /// Returns an entitled reference to the bridge CadenceBlocklist + /// + access(self) + view fun borrowCadenceBlocklist(): auth(Blocklist) &CadenceBlocklist { + return self.account.storage.borrow(from: /storage/cadenceBlocklist) + ?? panic("Missing or mis-typed CadenceBlocklist in storage") } /***************** @@ -291,6 +306,45 @@ contract FlowEVMBridgeConfig { } } + access(all) fun initCadenceBlocklist() { + let cadenceBlocklistStoragePath = /storage/cadenceBlocklist + assert( + self.account.storage.type(at: cadenceBlocklistStoragePath) == nil, + message: "CadenceBlocklist already stored" + ) + self.account.storage.save(<-create CadenceBlocklist(), to: cadenceBlocklistStoragePath) + } + + /// CadenceBlocklist resource stores a mapping of Cadence Types that are blocked from onboarding to the bridge + /// + access(all) resource CadenceBlocklist { + /// Mapping of serialized Cadence Type to their blocked status + /// + access(all) let blocklist: {Type: Bool} + + init() { + self.blocklist = {} + } + + /// Returns whether the given Type is blocked from onboarding to the bridge + /// + access(all) view fun isBlocked(_ type: Type): Bool { + return self.blocklist[type] ?? false + } + + /// Blocks the given Type from onboarding to the bridge + /// + access(Blocklist) fun block(_ type: Type) { + self.blocklist[type] = true + } + + /// Removes the given type from the blocklist + /// + access(Blocklist) fun unblock(_ type: Type) { + self.blocklist.remove(key: type) + } + } + /***************** Config Admin *****************/ @@ -497,7 +551,8 @@ contract FlowEVMBridgeConfig { let adminCap = self.account.capabilities.storage.issue<&Admin>(self.adminStoragePath) self.account.capabilities.publish(adminCap, at: self.adminPublicPath) - // Initialize the EVMBlocklist + // Initialize the blocklists self.account.storage.save(<-create EVMBlocklist(), to: /storage/evmBlocklist) + self.account.storage.save(<-create CadenceBlocklist(), to: /storage/cadenceBlocklist) } } diff --git a/cadence/scripts/bridge/is_cadence_type_blocked.cdc b/cadence/scripts/bridge/is_cadence_type_blocked.cdc new file mode 100644 index 00000000..e792ae9c --- /dev/null +++ b/cadence/scripts/bridge/is_cadence_type_blocked.cdc @@ -0,0 +1,14 @@ +import "EVM" + +import "FlowEVMBridgeConfig" + +/// Returns whether a Cadence Type is blocked from onboarded to the FlowEVMBridge +/// +/// @param typeIdentifier: The Cadence Type identifier of the asset in question +/// +/// @return Whether the Cadence type is blocked from onboarding to the FlowEVMBridge +/// +access(all) fun main(typeIdentifier: String): Bool { + let type = CompositeType(typeIdentifier) ?? panic("Invalid type identifier ".concat(typeIdentifier)) + return FlowEVMBridgeConfig.isCadenceTypeBlocked(type) +} diff --git a/cadence/transactions/bridge/admin/blocklist/block_cadence_type.cdc b/cadence/transactions/bridge/admin/blocklist/block_cadence_type.cdc new file mode 100644 index 00000000..4af65925 --- /dev/null +++ b/cadence/transactions/bridge/admin/blocklist/block_cadence_type.cdc @@ -0,0 +1,28 @@ +import "EVM" + +import "FlowEVMBridgeConfig" + +/// Blocks the given Cadence Type from onboarding. +/// +/// @param typeIdentifier: The Cadence identifier of the type to block +/// +transaction(typeIdentifier: String) { + + let cadenceBlocklist: auth(FlowEVMBridgeConfig.Blocklist) &FlowEVMBridgeConfig.CadenceBlocklist + let type: Type + + prepare(signer: auth(BorrowValue) &Account) { + self.cadenceBlocklist = signer.storage.borrow( + from: /storage/cadenceBlocklist + ) ?? panic("Could not borrow FlowEVMBridgeConfig Admin reference") + self.type = CompositeType(typeIdentifier) ?? panic("Invalid type identifier ".concat(typeIdentifier)) + } + + execute { + self.cadenceBlocklist.block(self.type) + } + + post { + FlowEVMBridgeConfig.isCadenceTypeBlocked(self.type): "Type was not blocked" + } +} diff --git a/cadence/transactions/bridge/admin/blocklist/init_cadence_blocklist.cdc b/cadence/transactions/bridge/admin/blocklist/init_cadence_blocklist.cdc new file mode 100644 index 00000000..9ce0a061 --- /dev/null +++ b/cadence/transactions/bridge/admin/blocklist/init_cadence_blocklist.cdc @@ -0,0 +1,9 @@ +import "FlowEVMBridgeConfig" + +transaction { + prepare(signer: &Account) {} + + execute { + FlowEVMBridgeConfig.initCadenceBlocklist() + } +} \ No newline at end of file diff --git a/cadence/transactions/bridge/admin/blocklist/unblock_cadence_type.cdc b/cadence/transactions/bridge/admin/blocklist/unblock_cadence_type.cdc new file mode 100644 index 00000000..80cb26f1 --- /dev/null +++ b/cadence/transactions/bridge/admin/blocklist/unblock_cadence_type.cdc @@ -0,0 +1,28 @@ +import "EVM" + +import "FlowEVMBridgeConfig" + +/// Unblocks the given Cadence Type from onboarding. +/// +/// @param typeIdentifier: The Cadence identifier of the type to block +/// +transaction(typeIdentifier: String) { + + let cadenceBlocklist: auth(FlowEVMBridgeConfig.Blocklist) &FlowEVMBridgeConfig.CadenceBlocklist + let type: Type + + prepare(signer: auth(BorrowValue) &Account) { + self.cadenceBlocklist = signer.storage.borrow( + from: /storage/cadenceBlocklist + ) ?? panic("Could not borrow FlowEVMBridgeConfig Admin reference") + self.type = CompositeType(typeIdentifier) ?? panic("Invalid type identifier ".concat(typeIdentifier)) + } + + execute { + self.cadenceBlocklist.unblock(self.type) + } + + post { + !FlowEVMBridgeConfig.isCadenceTypeBlocked(self.type): "Type was not unblocked" + } +}