diff --git a/cadence/contracts/bridge/FlowEVMBridge.cdc b/cadence/contracts/bridge/FlowEVMBridge.cdc index 0ca56abf..3b4639eb 100644 --- a/cadence/contracts/bridge/FlowEVMBridge.cdc +++ b/cadence/contracts/bridge/FlowEVMBridge.cdc @@ -42,7 +42,7 @@ contract FlowEVMBridge : IFlowEVMNFTBridge, IFlowEVMTokenBridge { /// Emitted any time a new asset type is onboarded to the bridge access(all) - event Onboarded(type: Type, cadenceContractAddress: Address, evmContractAddress: String) + event Onboarded(type: String, cadenceContractAddress: Address, evmContractAddress: String) /// Denotes a defining contract was deployed to the bridge account access(all) event BridgeDefiningContractDeployed( @@ -118,7 +118,7 @@ contract FlowEVMBridge : IFlowEVMNFTBridge, IFlowEVMTokenBridge { ) emit Onboarded( - type: type, + type: type.identifier, cadenceContractAddress: FlowEVMBridgeUtils.getContractAddress(fromType: type)!, evmContractAddress: onboardingValues.evmContractAddress.toString() ) diff --git a/cadence/contracts/bridge/FlowEVMBridgeConfig.cdc b/cadence/contracts/bridge/FlowEVMBridgeConfig.cdc index d327cb4e..be03a483 100644 --- a/cadence/contracts/bridge/FlowEVMBridgeConfig.cdc +++ b/cadence/contracts/bridge/FlowEVMBridgeConfig.cdc @@ -74,7 +74,7 @@ contract FlowEVMBridgeConfig { /// Emitted whenever a TokenHandler is configured /// access(all) - event HandlerConfigured(targetType: Type, targetEVMAddress: String?, isEnabled: Bool) + event HandlerConfigured(targetType: String, targetEVMAddress: String?, isEnabled: Bool) /// Emitted whenever the bridge is paused or unpaused globally - true for paused, false for unpaused /// access(all) @@ -82,11 +82,11 @@ contract FlowEVMBridgeConfig { /// Emitted whenever a specific asset is paused or unpaused - true for paused, false for unpaused /// access(all) - event AssetPauseStatusUpdated(paused: Bool, type: Type, evmAddress: String) + event AssetPauseStatusUpdated(paused: Bool, type: String, evmAddress: String) /// Emitted whenever an association is updated /// access(all) - event AssociationUpdated(type: Type, evmAddress: String) + event AssociationUpdated(type: String, evmAddress: String) /************* Getters @@ -143,7 +143,7 @@ contract FlowEVMBridgeConfig { let evmAddressHex = evmAddress.toString() self.evmAddressHexToType[evmAddressHex] = type - emit AssociationUpdated(type: type, evmAddress: evmAddressHex) + emit AssociationUpdated(type: type.identifier, evmAddress: evmAddressHex) } /// Returns whether the given Type has a TokenHandler configured @@ -186,7 +186,7 @@ contract FlowEVMBridgeConfig { } emit HandlerConfigured( - targetType: type, + targetType: type.identifier, targetEVMAddress: targetEVMAddressHex, isEnabled: handler.isEnabled() ) @@ -342,7 +342,7 @@ contract FlowEVMBridgeConfig { association.pause() let evmAddress = association.evmAddress.toString() - emit AssetPauseStatusUpdated(paused: true, type: type, evmAddress: evmAddress) + emit AssetPauseStatusUpdated(paused: true, type: type.identifier, evmAddress: evmAddress) } /// Unpauses all operations for a given asset type @@ -358,7 +358,7 @@ contract FlowEVMBridgeConfig { association.unpause() let evmAddress = association.evmAddress.toString() - emit AssetPauseStatusUpdated(paused: false, type: type, evmAddress: evmAddress) + emit AssetPauseStatusUpdated(paused: false, type: type.identifier, evmAddress: evmAddress) } /// Sets the target EVM contract address on the handler for a given Type, associating the Cadence type with the @@ -390,7 +390,7 @@ contract FlowEVMBridgeConfig { ) emit HandlerConfigured( - targetType: targetType, + targetType: targetType.identifier, targetEVMAddress: targetEVMAddress.toString(), isEnabled: handler.isEnabled() ) @@ -413,7 +413,7 @@ contract FlowEVMBridgeConfig { ?? panic("Handler cannot be enabled without a target EVM Address") emit HandlerConfigured( - targetType: handler.getTargetType()!, + targetType: handler.getTargetType()!.identifier, targetEVMAddress: targetEVMAddressHex, isEnabled: handler.isEnabled() ) diff --git a/cadence/contracts/bridge/interfaces/FlowEVMBridgeHandlerInterfaces.cdc b/cadence/contracts/bridge/interfaces/FlowEVMBridgeHandlerInterfaces.cdc index 3eac0873..0ab989d2 100644 --- a/cadence/contracts/bridge/interfaces/FlowEVMBridgeHandlerInterfaces.cdc +++ b/cadence/contracts/bridge/interfaces/FlowEVMBridgeHandlerInterfaces.cdc @@ -27,7 +27,19 @@ access(all) contract FlowEVMBridgeHandlerInterfaces { **************/ /// Event emitted when a handler is enabled between a Cadence type and an EVM address - access(all) event HandlerEnabled(handlerType: Type, targetType: Type, targetEVMAddress: EVM.EVMAddress) + access(all) event HandlerEnabled( + handlerType: String, + handlerUUID: UInt64, + targetType: String, + targetEVMAddress: String + ) + access(all) event MinterSet(handlerType: String, + handlerUUID: UInt64, + targetType: String?, + targetEVMAddress: String?, + minterType: String, + minterUUID: UInt64 + ) /**************** Constructs @@ -71,6 +83,15 @@ access(all) contract FlowEVMBridgeHandlerInterfaces { access(Admin) fun setMinter(_ minter: @{FlowEVMBridgeHandlerInterfaces.TokenMinter}) { pre { self.getExpectedMinterType() == minter.getType(): "Minter is not of the expected type" + minter.getMintedType() == self.getTargetType(): "Minter does not mint the target type" + emit MinterSet( + handlerType: self.getType().identifier, + handlerUUID: self.uuid, + targetType: self.getTargetType()?.identifier, + targetEVMAddress: self.getTargetEVMAddress()?.toString(), + minterType: minter.getType().identifier, + minterUUID: minter.uuid + ) } } /// Enables the Handler to fulfill bridge requests for the configured targets. If implementers utilize a minter, @@ -84,9 +105,10 @@ access(all) contract FlowEVMBridgeHandlerInterfaces { post { self.isEnabled(): "Problem enabling Handler" emit HandlerEnabled( - handlerType: self.getType(), - targetType: self.getTargetType()!, - targetEVMAddress: self.getTargetEVMAddress()! + handlerType: self.getType().identifier, + handlerUUID: self.uuid, + targetType: self.getTargetType()!.identifier, + targetEVMAddress: self.getTargetEVMAddress()!.toString() ) } } @@ -97,7 +119,7 @@ access(all) contract FlowEVMBridgeHandlerInterfaces { access(all) resource interface TokenMinter { /// Returns the Cadence type minted by this resource access(all) view fun getMintedType(): Type - /// Mints the specified amount of the Cadence + /// Mints the specified amount of tokens access(Mint) fun mint(amount: UFix64): @{FungibleToken.Vault} { pre { amount > 0.0: "Amount must be greater than 0" diff --git a/cadence/contracts/bridge/interfaces/IEVMBridgeNFTMinter.cdc b/cadence/contracts/bridge/interfaces/IEVMBridgeNFTMinter.cdc index 802c7e10..93908c9a 100644 --- a/cadence/contracts/bridge/interfaces/IEVMBridgeNFTMinter.cdc +++ b/cadence/contracts/bridge/interfaces/IEVMBridgeNFTMinter.cdc @@ -5,7 +5,7 @@ import "NonFungibleToken" access(all) contract interface IEVMBridgeNFTMinter { - access(all) event Minted(type: Type, id: UInt64, evmID: UInt256, tokenURI: String, minter: Address) + access(all) event Minted(type: String, id: UInt64, uuid: UInt64, evmID: UInt256, tokenURI: String, minter: Address) access(all) event TokenURIUpdated(evmID: UInt256, newURI: String, updater: Address) /// Account-only method to mint an NFT @@ -14,8 +14,9 @@ contract interface IEVMBridgeNFTMinter { fun mintNFT(id: UInt256, tokenURI: String): @{NonFungibleToken.NFT} { post { emit Minted( - type: result.getType(), + type: result.getType().identifier, id: result.id, + uuid: result.uuid, evmID: id, tokenURI: tokenURI, minter: self.account.address diff --git a/cadence/contracts/bridge/interfaces/IEVMBridgeTokenMinter.cdc b/cadence/contracts/bridge/interfaces/IEVMBridgeTokenMinter.cdc index 90409063..f5ce9120 100644 --- a/cadence/contracts/bridge/interfaces/IEVMBridgeTokenMinter.cdc +++ b/cadence/contracts/bridge/interfaces/IEVMBridgeTokenMinter.cdc @@ -6,7 +6,7 @@ access(all) contract interface IEVMBridgeTokenMinter { /// Emitted whenever tokens are minted, identifying the type, amount, and minter - access(all) event Minted(type: Type, amount: UFix64, minter: Address) + access(all) event Minted(type: String, amount: UFix64, mintedUUID: UInt64, minter: Address) /// Account-only method to mint a fungible token of the specified amount. /// @@ -14,7 +14,12 @@ contract interface IEVMBridgeTokenMinter { fun mintTokens(amount: UFix64): @{FungibleToken.Vault} { post { result.balance == amount: "Result does not contained specified amount" - emit Minted(type: result.getType(), amount: amount, minter: self.account.address) + emit Minted( + type: result.getType().identifier, + amount: amount, + mintedUUID: result.uuid, + minter: self.account.address + ) } } } diff --git a/cadence/contracts/bridge/interfaces/IFlowEVMNFTBridge.cdc b/cadence/contracts/bridge/interfaces/IFlowEVMNFTBridge.cdc index b0e403e2..1d766281 100644 --- a/cadence/contracts/bridge/interfaces/IFlowEVMNFTBridge.cdc +++ b/cadence/contracts/bridge/interfaces/IFlowEVMNFTBridge.cdc @@ -15,8 +15,9 @@ access(all) contract interface IFlowEVMNFTBridge { /// Broadcasts an NFT was bridged from Cadence to EVM access(all) event BridgedNFTToEVM( - type: Type, + type: String, id: UInt64, + uuid: UInt64, evmID: UInt256, to: String, evmContractAddress: String, @@ -25,8 +26,9 @@ access(all) contract interface IFlowEVMNFTBridge { /// Broadcasts an NFT was bridged from EVM to Cadence access(all) event BridgedNFTFromEVM( - type: Type, + type: String, id: UInt64, + uuid: UInt64, evmID: UInt256, caller: String, evmContractAddress: String, @@ -65,8 +67,9 @@ access(all) contract interface IFlowEVMNFTBridge { ) { pre { emit BridgedNFTToEVM( - type: token.getType(), + type: token.getType().identifier, id: token.id, + uuid: token.uuid, evmID: CrossVMNFT.getEVMID(from: &token as &{NonFungibleToken.NFT}) ?? UInt256(token.id), to: to.toString(), evmContractAddress: self.getAssociatedEVMAddress(with: token.getType())?.toString() @@ -99,8 +102,9 @@ access(all) contract interface IFlowEVMNFTBridge { ): @{NonFungibleToken.NFT} { post { emit BridgedNFTFromEVM( - type: result.getType(), + type: result.getType().identifier, id: result.id, + uuid: result.uuid, evmID: id, caller: owner.toString(), evmContractAddress: self.getAssociatedEVMAddress(with: result.getType())?.toString() diff --git a/cadence/contracts/bridge/interfaces/IFlowEVMTokenBridge.cdc b/cadence/contracts/bridge/interfaces/IFlowEVMTokenBridge.cdc index f4a87ba4..cb3ab53c 100644 --- a/cadence/contracts/bridge/interfaces/IFlowEVMTokenBridge.cdc +++ b/cadence/contracts/bridge/interfaces/IFlowEVMTokenBridge.cdc @@ -12,8 +12,9 @@ access(all) contract interface IFlowEVMTokenBridge { /// Broadcasts fungible tokens were bridged from Cadence to EVM access(all) event BridgedTokensToEVM( - type: Type, + type: String, amount: UFix64, + bridgedUUID: UInt64, to: String, evmContractAddress: String, bridgeAddress: Address @@ -21,8 +22,9 @@ access(all) contract interface IFlowEVMTokenBridge { /// Broadcasts fungible tokens were bridged from EVM to Cadence access(all) event BridgedTokensFromEVM( - type: Type, + type: String, amount: UInt256, + bridgedUUID: UInt64, caller: String, evmContractAddress: String, bridgeAddress: Address @@ -60,8 +62,9 @@ access(all) contract interface IFlowEVMTokenBridge { ) { pre { emit BridgedTokensToEVM( - type: vault.getType(), + type: vault.getType().identifier, amount: vault.balance, + bridgedUUID: vault.uuid, to: to.toString(), evmContractAddress: self.getAssociatedEVMAddress(with: vault.getType())?.toString() ?? panic("Could not find EVM Contract address associated with provided NFT"), @@ -93,8 +96,9 @@ access(all) contract interface IFlowEVMTokenBridge { ): @{FungibleToken.Vault} { post { emit BridgedTokensFromEVM( - type: result.getType(), + type: result.getType().identifier, amount: amount, + bridgedUUID: result.uuid, caller: owner.toString(), evmContractAddress: self.getAssociatedEVMAddress(with: result.getType())?.toString() ?? panic("Could not find EVM Contract address associated with provided Vault"), diff --git a/cadence/contracts/standards/EVM.cdc b/cadence/contracts/standards/EVM.cdc index 87e92adc..6c4172dc 100644 --- a/cadence/contracts/standards/EVM.cdc +++ b/cadence/contracts/standards/EVM.cdc @@ -50,6 +50,8 @@ contract EVM { payload: String, // code indicating a specific validation (201-300) or execution (301-400) error errorCode: UInt16, + // a human-readable message about the error (if any) + errorMessage: String, // the amount of gas transaction used gasConsumed: UInt64, // if transaction was a deployment contains a newly deployed contract address @@ -59,23 +61,44 @@ contract EVM { // block height in which transaction was inclued blockHeight: UInt64, // block hash in which transaction was included - blockHash: String + blockHash: String, + /// captures the hex encoded data that is returned from + /// the evm. For contract deployments + /// it returns the code deployed to + /// the address provided in the contractAddress field. + /// in case of revert, the smart contract custom error message + /// is also returned here (see EIP-140 for more details). + returnedData: String ) access(all) - event CadenceOwnedAccountCreated(addressBytes: [UInt8; 20]) + event CadenceOwnedAccountCreated(address: String) /// FLOWTokensDeposited is emitted when FLOW tokens is bridged /// into the EVM environment. Note that this event is not emitted /// for transfer of flow tokens between two EVM addresses. + /// Similar to the FungibleToken.Deposited event + /// this event includes a depositedUUID that captures the + /// uuid of the source vault. access(all) - event FLOWTokensDeposited(addressBytes: [UInt8; 20], amount: UFix64) + event FLOWTokensDeposited( + address: String, + amount: UFix64, + depositedUUID: UInt64 + ) /// FLOWTokensWithdrawn is emitted when FLOW tokens are bridged /// out of the EVM environment. Note that this event is not emitted /// for transfer of flow tokens between two EVM addresses. + /// similar to the FungibleToken.Withdrawn events + /// this event includes a withdrawnUUID that captures the + /// uuid of the returning vault. access(all) - event FLOWTokensWithdrawn(addressBytes: [UInt8; 20], amount: UFix64) + event FLOWTokensWithdrawn( + address: String, + amount: UFix64, + withdrawnUUID: UInt64 + ) /// BridgeAccessorUpdated is emitted when the BridgeAccessor Capability /// is updated in the stored BridgeRouter along with identifying @@ -143,11 +166,16 @@ contract EVM { if amount == 0.0 { panic("calling deposit function with an empty vault is not allowed") } + let depositedUUID = from.uuid InternalEVM.deposit( from: <-from, to: self.bytes ) - emit FLOWTokensDeposited(addressBytes: self.bytes, amount: amount) + emit FLOWTokensDeposited( + address: self.toString(), + amount: amount, + depositedUUID: depositedUUID + ) } /// Serializes the address to a hex string without the 0x prefix @@ -258,6 +286,10 @@ contract EVM { access(all) let errorCode: UInt64 + /// error message + access(all) + let errorMessage: String + /// returns the amount of gas metered during /// evm execution access(all) @@ -267,6 +299,8 @@ contract EVM { /// the evm for the call. For coa.deploy /// calls it returns the code deployed to /// the address provided in the contractAddress field. + /// in case of revert, the smart contract custom error message + /// is also returned here (see EIP-140 for more details). access(all) let data: [UInt8] @@ -279,12 +313,14 @@ contract EVM { init( status: Status, errorCode: UInt64, + errorMessage: String, gasUsed: UInt64, data: [UInt8], contractAddress: [UInt8; 20]? ) { self.status = status self.errorCode = errorCode + self.errorMessage = errorMessage self.gasUsed = gasUsed self.data = data @@ -366,7 +402,11 @@ contract EVM { from: self.addressBytes, amount: balance.attoflow ) as! @FlowToken.Vault - emit FLOWTokensWithdrawn(addressBytes: self.addressBytes, amount: balance.inFLOW()) + emit FLOWTokensWithdrawn( + address: self.address().toString(), + amount: balance.inFLOW(), + withdrawnUUID: vault.uuid + ) return <-vault } @@ -465,7 +505,8 @@ contract EVM { let acc <-create CadenceOwnedAccount() let addr = InternalEVM.createCadenceOwnedAccount(uuid: acc.uuid) acc.initAddress(addressBytes: addr) - emit CadenceOwnedAccountCreated(addressBytes: addr) + + emit CadenceOwnedAccountCreated(address: acc.address().toString()) return <-acc } @@ -608,8 +649,20 @@ contract EVM { // constructing key list let keyList = Crypto.KeyList() for signature in signatureSet { - let key = acc.keys.get(keyIndex: signature.keyIndex)! - assert(!key.isRevoked, message: "revoked key is used") + let keyRef = acc.keys.get(keyIndex: signature.keyIndex) + if keyRef == nil { + return ValidationResult( + isValid: false, + problem: "invalid key index" + ) + } + let key = keyRef! + if key.isRevoked { + return ValidationResult( + isValid: false, + problem: "account key is revoked" + ) + } keyList.add( key.publicKey, hashAlgorithm: key.hashAlgorithm, @@ -753,4 +806,4 @@ contract EVM { ?.borrowBridgeAccessor() ?? panic("Could not borrow reference to the EVM bridge") } -} +} \ No newline at end of file