diff --git a/cadence/contracts/bridge/FlowEVMBridge.cdc b/cadence/contracts/bridge/FlowEVMBridge.cdc index 0f83a2bf..7e3bcd95 100644 --- a/cadence/contracts/bridge/FlowEVMBridge.cdc +++ b/cadence/contracts/bridge/FlowEVMBridge.cdc @@ -143,6 +143,8 @@ contract FlowEVMBridge : IFlowEVMNFTBridge, IFlowEVMTokenBridge { ) { pre { !FlowEVMBridgeConfig.isPaused(): "Bridge operations are currently paused" + !FlowEVMBridgeConfig.isEVMAddressBlocked(address): + "This EVM contract 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 5818569d..7a18cec2 100644 --- a/cadence/contracts/bridge/FlowEVMBridgeConfig.cdc +++ b/cadence/contracts/bridge/FlowEVMBridgeConfig.cdc @@ -16,6 +16,7 @@ contract FlowEVMBridgeConfig { access(all) entitlement Gas access(all) entitlement Fee access(all) entitlement Pause + access(all) entitlement Blocklist /************* Fields @@ -128,6 +129,13 @@ contract FlowEVMBridgeConfig { return self.evmAddressHexToType[evmAddressHex] } + /// Returns whether the given EVMAddress is currently blocked from onboarding to the bridge + /// + access(all) + view fun isEVMAddressBlocked(_ evmAddress: EVM.EVMAddress): Bool { + return self.borrowBlocklist().isBlocked(evmAddress) + } + /**************************** Bridge Account Methods ****************************/ @@ -213,6 +221,14 @@ contract FlowEVMBridgeConfig { return &self.typeToTokenHandlers[type] } + /// Returns an entitled reference to the bridge EVMBlocklist + /// + access(self) + view fun borrowBlocklist(): auth(Blocklist) &EVMBlocklist { + return self.account.storage.borrow(from: /storage/evmBlocklist) + ?? panic("Missing or mis-typed Blocklist in storage") + } + /***************** Constructs *****************/ @@ -245,6 +261,42 @@ contract FlowEVMBridgeConfig { } } + /// EVMBlocklist resource stores a mapping of EVM addresses that are blocked from onboarding to the bridge + /// + access(all) resource EVMBlocklist { + /// Mapping of serialized EVM addresses to their blocked status + /// + access(all) let blockList: {String: Bool} + + init() { + self.blockList = {} + } + + /// Returns whether the given EVM address is blocked from onboarding to the bridge + /// + access(all) view fun isBlocked(_ evmAddress: EVM.EVMAddress): Bool { + return self.blockList[evmAddress.toString()] ?? false + } + + /// Blocks the given EVM address from onboarding to the bridge + /// + access(Blocklist) fun block(_ evmAddress: EVM.EVMAddress) { + self.blockList[evmAddress.toString()] = true + } + + /// Unblocks the given EVM address from onboarding to the bridge + /// + access(Blocklist) fun unblock(_ evmAddress: EVM.EVMAddress) { + self.blockList[evmAddress.toString()] = false + } + + /// Removes the given EVM address from the blocklist + /// + access(Blocklist) fun remove(_ evmAddress: EVM.EVMAddress) { + self.blockList.remove(key: evmAddress.toString()) + } + } + /***************** Config Admin *****************/ @@ -362,6 +414,27 @@ contract FlowEVMBridgeConfig { emit AssetPauseStatusUpdated(paused: false, type: type.identifier, evmAddress: evmAddress) } + /// Blocks the given EVM address from onboarding to the bridge + /// + access(Blocklist) + fun blockEVMAddress(_ evmAddress: EVM.EVMAddress) { + FlowEVMBridgeConfig.borrowBlocklist().block(evmAddress) + } + + /// Unblocks the given EVM address from onboarding to the bridge + /// + access(Blocklist) + fun unblockEVMAddress(_ evmAddress: EVM.EVMAddress) { + FlowEVMBridgeConfig.borrowBlocklist().unblock(evmAddress) + } + + /// Removes the given EVM address from the blocklist + /// + access(Blocklist) + fun removeEVMAddressFromBlocklist(_ evmAddress: EVM.EVMAddress) { + FlowEVMBridgeConfig.borrowBlocklist().remove(evmAddress) + } + /// Sets the target EVM contract address on the handler for a given Type, associating the Cadence type with the /// provided EVM address. If a TokenHandler does not exist for the given Type, the operation reverts. /// diff --git a/cadence/transactions/bridge/admin/blocklist/block_evm_address.cdc b/cadence/transactions/bridge/admin/blocklist/block_evm_address.cdc new file mode 100644 index 00000000..30eb9642 --- /dev/null +++ b/cadence/transactions/bridge/admin/blocklist/block_evm_address.cdc @@ -0,0 +1,28 @@ +import "EVM" + +import "FlowEVMBridgeConfig" + +/// Blocks the given EVM contract address from onboarding. +/// +/// @param evmContractHex: The EVM contract address to block from onboarding +/// +transaction(evmContractHex: String) { + + let admin: auth(FlowEVMBridgeConfig.Blocklist) &FlowEVMBridgeConfig.Admin + let evmAddress: EVM.EVMAddress + + prepare(signer: auth(BorrowValue) &Account) { + self.admin = signer.storage.borrow( + from: FlowEVMBridgeConfig.adminStoragePath + ) ?? panic("Could not borrow FlowEVMBridgeConfig Admin reference") + self.evmAddress = EVM.addressFromString(evmContractHex) + } + + execute { + self.admin.blockEVMAddress(self.evmAddress) + } + + post { + FlowEVMBridgeConfig.isEVMAddressBlocked(self.evmAddress): "Fee was not set correctly" + } +}