diff --git a/cadence/contracts/connectors/evm/ERC4626SinkConnectors.cdc b/cadence/contracts/connectors/evm/ERC4626SinkConnectors.cdc index 70c2832a..8eac1d4b 100644 --- a/cadence/contracts/connectors/evm/ERC4626SinkConnectors.cdc +++ b/cadence/contracts/connectors/evm/ERC4626SinkConnectors.cdc @@ -132,15 +132,16 @@ access(all) contract ERC4626SinkConnectors { // approve the ERC4626 vault to spend the assets on deposit let uintAmount = FlowEVMBridgeUtils.convertCadenceAmountToERC20Amount(amount, erc20Address: self.assetEVMAddress) let approveRes = self._call( - to: self.assetEVMAddress, - signature: "approve(address,uint256)", - args: [self.vault, uintAmount], - gasLimit: 500_000 - )! - if approveRes.status != EVM.Status.successful { - // Cadence panic reverts all EVM state changes in this transaction, so no need to bridge token back. - panic(self._approveErrorMessage(ufixAmount: amount, uintAmount: uintAmount, approveRes: approveRes)) - } + to: self.assetEVMAddress, + signature: "approve(address,uint256)", + args: [self.vault, uintAmount], + gasLimit: 500_000 + )! + // Cadence panic reverts all EVM state changes in this transaction, so no need to bridge token back. + assert( + approveRes.status == EVM.Status.successful, + message: self._approveErrorMessage(ufixAmount: amount, uintAmount: uintAmount, approveRes: approveRes) + ) // deposit the assets to the ERC4626 vault let depositRes = self._call( @@ -149,11 +150,12 @@ access(all) contract ERC4626SinkConnectors { args: [uintAmount, self.coa.borrow()!.address()], gasLimit: 1_000_000 )! - if depositRes.status != EVM.Status.successful { - // No need to revoke the approval: a Cadence panic atomically reverts all EVM - // state changes made in this transaction, including the approve() call above. - panic(self._depositErrorMessage(ufixAmount: amount, uintAmount: uintAmount, depositRes: depositRes)) - } + // No need to revoke the approval: a Cadence panic atomically reverts all EVM + // state changes made in this transaction, including the approve() call above. + assert( + depositRes.status == EVM.Status.successful, + message: self._depositErrorMessage(ufixAmount: amount, uintAmount: uintAmount, depositRes: depositRes) + ) } /// Returns a ComponentInfo struct containing information about this component and a list of ComponentInfo for /// each inner component in the stack. diff --git a/cadence/contracts/interfaces/DeFiActions.cdc b/cadence/contracts/interfaces/DeFiActions.cdc index 22fdc3c1..2c7e11eb 100644 --- a/cadence/contracts/interfaces/DeFiActions.cdc +++ b/cadence/contracts/interfaces/DeFiActions.cdc @@ -258,9 +258,12 @@ access(all) contract DeFiActions { /// A Sink Connector (or just “Sink”) is analogous to the Fungible Token Receiver interface that accepts deposits of /// funds. It differs from the standard Receiver interface in that it is a struct interface (instead of resource /// interface) and allows for the graceful handling of Sinks that have a limited capacity on the amount they can - /// accept for deposit. Implementations should therefore avoid the possibility of reversion with graceful fallback - /// on unexpected conditions, executing no-ops instead of reverting. - /// + /// accept for deposit. Implementations should therefore favor graceful fallback on unexpected conditions, executing + /// no-ops instead of reverting. + /// - A Sink should prioritize liveness where possible, and not panic, for example if it has no funds or cannot + /// access funds. + /// - A sink should only panic if not panicking would cause the Sink to have an inconsistent internal state + /// (unsafe or undefined for the Sink to continue in this state). access(all) struct interface Sink : IdentifiableStruct { /// Returns the Vault type accepted by this Sink access(all) view fun getSinkType(): Type