diff --git a/crates/autopilot/src/arguments.rs b/crates/autopilot/src/arguments.rs index 00062dfd94..8ea3903270 100644 --- a/crates/autopilot/src/arguments.rs +++ b/crates/autopilot/src/arguments.rs @@ -26,7 +26,7 @@ pub struct Arguments { #[clap( long, env, - default_value = "0x26c3801b4840dab317cedfd7aeaf9f45fdd22830" + default_value = "0x76aAf674848311C7F21fc691B0b952f016dA49F3" )] pub ethflow_contract: H160, diff --git a/crates/autopilot/src/database/events.rs b/crates/autopilot/src/database/events.rs index 9e84e5887a..b009340a89 100644 --- a/crates/autopilot/src/database/events.rs +++ b/crates/autopilot/src/database/events.rs @@ -99,7 +99,7 @@ pub fn meta_to_event_index(meta: &EventMetadata) -> EventIndex { } } -fn bytes_to_order_uid(bytes: &[u8]) -> Result { +pub fn bytes_to_order_uid(bytes: &[u8]) -> Result { bytes .try_into() .context("order_uid has wrong number of bytes") diff --git a/crates/autopilot/src/database/onchain_order_events.rs b/crates/autopilot/src/database/onchain_order_events.rs index 4c31c6cb30..b2af6d7469 100644 --- a/crates/autopilot/src/database/onchain_order_events.rs +++ b/crates/autopilot/src/database/onchain_order_events.rs @@ -1,9 +1,13 @@ pub mod ethflow_events; -use super::{events::meta_to_event_index, Metrics, Postgres}; +use super::{ + events::{bytes_to_order_uid, meta_to_event_index}, + Metrics, Postgres, +}; use anyhow::{anyhow, bail, Context, Result}; use contracts::cowswap_onchain_orders::{ - event_data::OrderPlacement as ContractOrderPlacement, Event as ContractEvent, + event_data::{OrderInvalidation, OrderPlacement as ContractOrderPlacement}, + Event as ContractEvent, }; use database::{ byte_array::ByteArray, @@ -134,11 +138,14 @@ impl EventStoring range: RangeInclusive, ) -> Result<()> { let order_placement_events = events + .clone() .into_iter() .filter(|EthContractEvent { data, .. }| { matches!(data, ContractEvent::OrderPlacement(_)) }) .collect(); + let invalidation_events = get_invalidation_events(events)?; + let invalided_order_uids = extract_invalidated_order_uids(invalidation_events)?; let (custom_onchain_data, quotes, broadcasted_order_data, orders) = self .extract_custom_and_general_order_data(order_placement_events) .await?; @@ -157,6 +164,20 @@ impl EventStoring .await .context("mark_onchain_order_events failed")?; + database::onchain_invalidations::delete_invalidations( + &mut transaction, + *range.start() as i64, + ) + .await + .context("invalidating_onchain_order_events failed")?; + + database::onchain_invalidations::insert_onchain_invalidations( + &mut transaction, + invalided_order_uids.as_slice(), + ) + .await + .context("insert_onchain_invalidations failed")?; + self.custom_onchain_data_parser .append_custom_order_info_to_db(&mut transaction, custom_onchain_data) .await @@ -182,11 +203,14 @@ impl EventStoring async fn append_events(&mut self, events: Vec>) -> Result<()> { let order_placement_events = events + .clone() .into_iter() .filter(|EthContractEvent { data, .. }| { matches!(data, ContractEvent::OrderPlacement(_)) }) .collect(); + let invalidation_events = get_invalidation_events(events)?; + let invalided_order_uids = extract_invalidated_order_uids(invalidation_events)?; let (custom_order_data, quotes, broadcasted_order_data, orders) = self .extract_custom_and_general_order_data(order_placement_events) .await?; @@ -197,6 +221,12 @@ impl EventStoring .start_timer(); let mut transaction = self.db.0.begin().await?; + database::onchain_invalidations::insert_onchain_invalidations( + &mut transaction, + invalided_order_uids.as_slice(), + ) + .await + .context("insert_onchain_invalidations failed")?; database::onchain_broadcasted_orders::append( &mut transaction, broadcasted_order_data.as_slice(), @@ -294,6 +324,45 @@ impl OnchainOrderParser { } } +fn get_invalidation_events( + events: Vec>, +) -> Result> { + events + .into_iter() + .filter_map(|EthContractEvent { data, meta }| { + let meta = match meta { + Some(meta) => meta, + None => return Some(Err(anyhow!("invalidation event without metadata"))), + }; + let data = match data { + ContractEvent::OrderInvalidation(event) => event, + _ => { + return None; + } + }; + Some(Ok((meta_to_event_index(&meta), data))) + }) + .collect() +} + +fn extract_invalidated_order_uids( + invalidations: Vec<(EventIndex, OrderInvalidation)>, +) -> Result> { + invalidations + .into_iter() + .map(|(event_index, invalidation)| { + Ok(( + event_index, + // The following conversion should not error, as the contract + // enforces that the enough bytes are send. + // If the error hpapens anyways, we want to stop indexing and + // hence escalate the error + bytes_to_order_uid(invalidation.order_uid.0.as_slice())?, + )) + }) + .collect() +} + type GeneralOnchainOrderPlacementData = ( EventIndex, database::orders::Quote, diff --git a/crates/contracts/artifacts/CoWSwapEthFlow.json b/crates/contracts/artifacts/CoWSwapEthFlow.json index 675dcd40f6..df860d60a6 100644 --- a/crates/contracts/artifacts/CoWSwapEthFlow.json +++ b/crates/contracts/artifacts/CoWSwapEthFlow.json @@ -1 +1 @@ -{"abi":[{"inputs":[{"internalType":"contract ICoWSwapSettlement","name":"_cowSwapSettlement","type":"address"},{"internalType":"contract IWrappedNativeToken","name":"_wrappedNativeToken","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"EthTransferFailed","type":"error"},{"inputs":[],"name":"IncorrectEthAmount","type":"error"},{"inputs":[{"internalType":"bytes32","name":"orderHash","type":"bytes32"}],"name":"NotAllowedToInvalidateOrder","type":"error"},{"inputs":[],"name":"NotAllowedZeroSellAmount","type":"error"},{"inputs":[{"internalType":"bytes32","name":"orderHash","type":"bytes32"}],"name":"OrderIsAlreadyOwned","type":"error"},{"inputs":[],"name":"ReceiverMustBeSet","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes","name":"orderUid","type":"bytes"}],"name":"OrderInvalidation","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"components":[{"internalType":"contract IERC20","name":"sellToken","type":"address"},{"internalType":"contract IERC20","name":"buyToken","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"sellAmount","type":"uint256"},{"internalType":"uint256","name":"buyAmount","type":"uint256"},{"internalType":"uint32","name":"validTo","type":"uint32"},{"internalType":"bytes32","name":"appData","type":"bytes32"},{"internalType":"uint256","name":"feeAmount","type":"uint256"},{"internalType":"bytes32","name":"kind","type":"bytes32"},{"internalType":"bool","name":"partiallyFillable","type":"bool"},{"internalType":"bytes32","name":"sellTokenBalance","type":"bytes32"},{"internalType":"bytes32","name":"buyTokenBalance","type":"bytes32"}],"indexed":false,"internalType":"struct GPv2Order.Data","name":"order","type":"tuple"},{"components":[{"internalType":"enum ICoWSwapOnchainOrders.OnchainSigningScheme","name":"scheme","type":"uint8"},{"internalType":"bytes","name":"data","type":"bytes"}],"indexed":false,"internalType":"struct ICoWSwapOnchainOrders.OnchainSignature","name":"signature","type":"tuple"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"OrderPlacement","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes","name":"orderUid","type":"bytes"},{"indexed":true,"internalType":"address","name":"refunder","type":"address"}],"name":"OrderRefund","type":"event"},{"inputs":[],"name":"cowSwapSettlement","outputs":[{"internalType":"contract ICoWSwapSettlement","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"contract IERC20","name":"buyToken","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"sellAmount","type":"uint256"},{"internalType":"uint256","name":"buyAmount","type":"uint256"},{"internalType":"bytes32","name":"appData","type":"bytes32"},{"internalType":"uint256","name":"feeAmount","type":"uint256"},{"internalType":"uint32","name":"validTo","type":"uint32"},{"internalType":"bool","name":"partiallyFillable","type":"bool"},{"internalType":"int64","name":"quoteId","type":"int64"}],"internalType":"struct EthFlowOrder.Data","name":"order","type":"tuple"}],"name":"createOrder","outputs":[{"internalType":"bytes32","name":"orderHash","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"contract IERC20","name":"buyToken","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"sellAmount","type":"uint256"},{"internalType":"uint256","name":"buyAmount","type":"uint256"},{"internalType":"bytes32","name":"appData","type":"bytes32"},{"internalType":"uint256","name":"feeAmount","type":"uint256"},{"internalType":"uint32","name":"validTo","type":"uint32"},{"internalType":"bool","name":"partiallyFillable","type":"bool"},{"internalType":"int64","name":"quoteId","type":"int64"}],"internalType":"struct EthFlowOrder.Data","name":"order","type":"tuple"}],"name":"invalidateOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"contract IERC20","name":"buyToken","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"sellAmount","type":"uint256"},{"internalType":"uint256","name":"buyAmount","type":"uint256"},{"internalType":"bytes32","name":"appData","type":"bytes32"},{"internalType":"uint256","name":"feeAmount","type":"uint256"},{"internalType":"uint32","name":"validTo","type":"uint32"},{"internalType":"bool","name":"partiallyFillable","type":"bool"},{"internalType":"int64","name":"quoteId","type":"int64"}],"internalType":"struct EthFlowOrder.Data[]","name":"orderArray","type":"tuple[]"}],"name":"invalidateOrdersIgnoringNotAllowed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"orderHash","type":"bytes32"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"isValidSignature","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"orders","outputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint32","name":"validTo","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"unwrap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"wrap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"wrapAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"wrappedNativeToken","outputs":[{"internalType":"contract IWrappedNativeToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]} \ No newline at end of file +{"abi":[{"inputs":[{"internalType":"contract ICoWSwapSettlement","name":"_cowSwapSettlement","type":"address"},{"internalType":"contract IWrappedNativeToken","name":"_wrappedNativeToken","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"EthTransferFailed","type":"error"},{"inputs":[],"name":"IncorrectEthAmount","type":"error"},{"inputs":[{"internalType":"bytes32","name":"orderHash","type":"bytes32"}],"name":"NotAllowedToInvalidateOrder","type":"error"},{"inputs":[],"name":"NotAllowedZeroSellAmount","type":"error"},{"inputs":[{"internalType":"bytes32","name":"orderHash","type":"bytes32"}],"name":"OrderIsAlreadyOwned","type":"error"},{"inputs":[],"name":"ReceiverMustBeSet","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"orderUid","type":"bytes"}],"name":"OrderInvalidation","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"components":[{"internalType":"contract IERC20","name":"sellToken","type":"address"},{"internalType":"contract IERC20","name":"buyToken","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"sellAmount","type":"uint256"},{"internalType":"uint256","name":"buyAmount","type":"uint256"},{"internalType":"uint32","name":"validTo","type":"uint32"},{"internalType":"bytes32","name":"appData","type":"bytes32"},{"internalType":"uint256","name":"feeAmount","type":"uint256"},{"internalType":"bytes32","name":"kind","type":"bytes32"},{"internalType":"bool","name":"partiallyFillable","type":"bool"},{"internalType":"bytes32","name":"sellTokenBalance","type":"bytes32"},{"internalType":"bytes32","name":"buyTokenBalance","type":"bytes32"}],"indexed":false,"internalType":"struct GPv2Order.Data","name":"order","type":"tuple"},{"components":[{"internalType":"enum ICoWSwapOnchainOrders.OnchainSigningScheme","name":"scheme","type":"uint8"},{"internalType":"bytes","name":"data","type":"bytes"}],"indexed":false,"internalType":"struct ICoWSwapOnchainOrders.OnchainSignature","name":"signature","type":"tuple"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"OrderPlacement","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"orderUid","type":"bytes"},{"indexed":true,"internalType":"address","name":"refunder","type":"address"}],"name":"OrderRefund","type":"event"},{"inputs":[],"name":"cowSwapSettlement","outputs":[{"internalType":"contract ICoWSwapSettlement","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"contract IERC20","name":"buyToken","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"sellAmount","type":"uint256"},{"internalType":"uint256","name":"buyAmount","type":"uint256"},{"internalType":"bytes32","name":"appData","type":"bytes32"},{"internalType":"uint256","name":"feeAmount","type":"uint256"},{"internalType":"uint32","name":"validTo","type":"uint32"},{"internalType":"bool","name":"partiallyFillable","type":"bool"},{"internalType":"int64","name":"quoteId","type":"int64"}],"internalType":"struct EthFlowOrder.Data","name":"order","type":"tuple"}],"name":"createOrder","outputs":[{"internalType":"bytes32","name":"orderHash","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"contract IERC20","name":"buyToken","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"sellAmount","type":"uint256"},{"internalType":"uint256","name":"buyAmount","type":"uint256"},{"internalType":"bytes32","name":"appData","type":"bytes32"},{"internalType":"uint256","name":"feeAmount","type":"uint256"},{"internalType":"uint32","name":"validTo","type":"uint32"},{"internalType":"bool","name":"partiallyFillable","type":"bool"},{"internalType":"int64","name":"quoteId","type":"int64"}],"internalType":"struct EthFlowOrder.Data","name":"order","type":"tuple"}],"name":"invalidateOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"contract IERC20","name":"buyToken","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"sellAmount","type":"uint256"},{"internalType":"uint256","name":"buyAmount","type":"uint256"},{"internalType":"bytes32","name":"appData","type":"bytes32"},{"internalType":"uint256","name":"feeAmount","type":"uint256"},{"internalType":"uint32","name":"validTo","type":"uint32"},{"internalType":"bool","name":"partiallyFillable","type":"bool"},{"internalType":"int64","name":"quoteId","type":"int64"}],"internalType":"struct EthFlowOrder.Data[]","name":"orderArray","type":"tuple[]"}],"name":"invalidateOrdersIgnoringNotAllowed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"orderHash","type":"bytes32"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"isValidSignature","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"orders","outputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint32","name":"validTo","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"unwrap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"wrap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"wrapAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"wrappedNativeToken","outputs":[{"internalType":"contract IWrappedNativeToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]} \ No newline at end of file diff --git a/crates/contracts/artifacts/CoWSwapOnchainOrders.json b/crates/contracts/artifacts/CoWSwapOnchainOrders.json index e834de9d2c..39359dbe9f 100644 --- a/crates/contracts/artifacts/CoWSwapOnchainOrders.json +++ b/crates/contracts/artifacts/CoWSwapOnchainOrders.json @@ -1 +1 @@ -{"abi":[{"inputs":[{"internalType":"address","name":"settlementContractAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes","name":"orderUid","type":"bytes"}],"name":"OrderInvalidation","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"components":[{"internalType":"contract IERC20","name":"sellToken","type":"address"},{"internalType":"contract IERC20","name":"buyToken","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"sellAmount","type":"uint256"},{"internalType":"uint256","name":"buyAmount","type":"uint256"},{"internalType":"uint32","name":"validTo","type":"uint32"},{"internalType":"bytes32","name":"appData","type":"bytes32"},{"internalType":"uint256","name":"feeAmount","type":"uint256"},{"internalType":"bytes32","name":"kind","type":"bytes32"},{"internalType":"bool","name":"partiallyFillable","type":"bool"},{"internalType":"bytes32","name":"sellTokenBalance","type":"bytes32"},{"internalType":"bytes32","name":"buyTokenBalance","type":"bytes32"}],"indexed":false,"internalType":"struct GPv2Order.Data","name":"order","type":"tuple"},{"components":[{"internalType":"enum ICoWSwapOnchainOrders.OnchainSigningScheme","name":"scheme","type":"uint8"},{"internalType":"bytes","name":"data","type":"bytes"}],"indexed":false,"internalType":"struct ICoWSwapOnchainOrders.OnchainSignature","name":"signature","type":"tuple"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"OrderPlacement","type":"event"}]} \ No newline at end of file +{"abi":[{"inputs":[{"internalType":"address","name":"settlementContractAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"orderUid","type":"bytes"}],"name":"OrderInvalidation","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"components":[{"internalType":"contract IERC20","name":"sellToken","type":"address"},{"internalType":"contract IERC20","name":"buyToken","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"sellAmount","type":"uint256"},{"internalType":"uint256","name":"buyAmount","type":"uint256"},{"internalType":"uint32","name":"validTo","type":"uint32"},{"internalType":"bytes32","name":"appData","type":"bytes32"},{"internalType":"uint256","name":"feeAmount","type":"uint256"},{"internalType":"bytes32","name":"kind","type":"bytes32"},{"internalType":"bool","name":"partiallyFillable","type":"bool"},{"internalType":"bytes32","name":"sellTokenBalance","type":"bytes32"},{"internalType":"bytes32","name":"buyTokenBalance","type":"bytes32"}],"indexed":false,"internalType":"struct GPv2Order.Data","name":"order","type":"tuple"},{"components":[{"internalType":"enum ICoWSwapOnchainOrders.OnchainSigningScheme","name":"scheme","type":"uint8"},{"internalType":"bytes","name":"data","type":"bytes"}],"indexed":false,"internalType":"struct ICoWSwapOnchainOrders.OnchainSignature","name":"signature","type":"tuple"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"OrderPlacement","type":"event"}]} \ No newline at end of file diff --git a/crates/contracts/src/bin/vendor.rs b/crates/contracts/src/bin/vendor.rs index f65f60fed5..f15e35f934 100644 --- a/crates/contracts/src/bin/vendor.rs +++ b/crates/contracts/src/bin/vendor.rs @@ -124,12 +124,12 @@ fn run() -> Result<()> { )? .github( "CoWSwapOnchainOrders", - "cowprotocol/ethflowcontract/v0.0.0-rc.1\ + "cowprotocol/ethflowcontract/0.0.0-rc.2\ -artifacts/artifacts/CoWSwapOnchainOrders.sol/CoWSwapOnchainOrders.json" )? .github( "CoWSwapEthFlow", - "cowprotocol/ethflowcontract/v0.0.0-rc.1\ + "cowprotocol/ethflowcontract/0.0.0-rc.2\ -artifacts/artifacts/CoWSwapEthFlow.sol/CoWSwapEthFlow.json" )? .npm( diff --git a/crates/refunder/src/arguments.rs b/crates/refunder/src/arguments.rs index 9a68180051..8678addd29 100644 --- a/crates/refunder/src/arguments.rs +++ b/crates/refunder/src/arguments.rs @@ -41,7 +41,7 @@ pub struct Arguments { #[clap( long, env, - default_value = "0x26c3801b4840dab317cedfd7aeaf9f45fdd22830" + default_value = "0x76aAf674848311C7F21fc691B0b952f016dA49F3" )] pub ethflow_contract: H160, }