Created
June 23, 2024 16:44
-
-
Save mfw78/98d1e8839de72d9f1889348a5ce43dbe to your computer and use it in GitHub Desktop.
Eth Flow Refunder
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use alloy::{ | |
network::{EthereumWallet, TransactionBuilder}, | |
primitives::bytes::Buf, | |
providers::{Provider, ProviderBuilder}, | |
rpc::types::TransactionRequest, | |
signers::local::PrivateKeySigner, | |
sol, | |
sol_types::{SolCall, SolEvent}, | |
}; | |
use CoWSwapOnchainOrders::{invalidateOrderCall, EthFlowOrderData}; | |
#[tokio::main] | |
async fn main() -> eyre::Result<()> { | |
let rpc_url = match std::env::var("RPC_URL") { | |
Ok(url) => match url.parse() { | |
Ok(url) => url, | |
Err(_) => { | |
eprintln!("Invalid URL: {}", url); | |
std::process::exit(1); | |
} | |
}, | |
Err(_) => { | |
eprintln!("Environment variable `RPC_URL` is not set"); | |
eprintln!("Usage: RPC_URL=<URL> indexer"); | |
std::process::exit(1); | |
} | |
}; | |
let signer: PrivateKeySigner = std::env::var("PRIVATE_KEY") | |
.expect("Must supply PRIVATE_KEY via env variable") | |
.parse() | |
.expect("Failed to parse private key"); | |
let wallet = EthereumWallet::from(signer); | |
let provider = ProviderBuilder::new() | |
.with_recommended_fillers() | |
.wallet(wallet) | |
.on_http(rpc_url); | |
let receipts = provider | |
.get_transaction_receipt( | |
std::env::var("TX_HASH") | |
.expect("Must specify TX_HASH via env variable") | |
.parse() | |
.expect("Invalid TX_HASH specified"), | |
) | |
.await | |
.unwrap() | |
.unwrap(); | |
// Get the first (and only) log from the transaction | |
let log = receipts.inner.logs().iter().next().unwrap(); | |
let event = CoWSwapOnchainOrders::OrderPlacement::decode_log_data(&log.data(), true)?; | |
// Reassemble the on-chain order data | |
let order = EthFlowOrderData { | |
buyToken: event.order.buyToken, | |
receiver: event.order.receiver, | |
sellAmount: event.order.sellAmount, | |
buyAmount: event.order.buyAmount, | |
appData: event.order.appData, | |
feeAmount: event.order.feeAmount, | |
validTo: event.order.validTo, | |
partiallyFillable: event.order.partiallyFillable, | |
// quoteId is tightly packed in `event.data` | |
quoteId: event.data.slice(..8).get_i64(), | |
}; | |
// Build the transaction to invalidate the order | |
let tx = TransactionRequest::default() | |
.with_to(log.address()) | |
.with_call(&invalidateOrderCall::new((order,))); | |
println!("{:?}", tx); | |
let tx_hash = provider.send_transaction(tx).await?.watch().await?; | |
println!("Sent transaction: {}", tx_hash); | |
Ok(()) | |
} | |
sol! { | |
#[allow(missing_docs)] | |
#[derive(Debug)] | |
contract CoWSwapOnchainOrders { | |
enum OnchainSigningScheme { | |
Eip1271, | |
PreSign | |
} | |
struct OnchainSignature { | |
/// @dev The signing scheme used by the signature data. | |
OnchainSigningScheme scheme; | |
/// @dev The data used as an order signature. | |
bytes data; | |
} | |
event OrderPlacement( | |
address indexed sender, | |
Data order, | |
OnchainSignature signature, | |
bytes data | |
); | |
struct Data { | |
address sellToken; | |
address buyToken; | |
address receiver; | |
uint256 sellAmount; | |
uint256 buyAmount; | |
uint32 validTo; | |
bytes32 appData; | |
uint256 feeAmount; | |
bytes32 kind; | |
bool partiallyFillable; | |
bytes32 sellTokenBalance; | |
bytes32 buyTokenBalance; | |
} | |
struct EthFlowOrderData { | |
address buyToken; | |
address receiver; | |
uint256 sellAmount; | |
uint256 buyAmount; | |
bytes32 appData; | |
uint256 feeAmount; | |
uint32 validTo; | |
bool partiallyFillable; | |
int64 quoteId; | |
} | |
function invalidateOrder(EthFlowOrderData calldata order) public { | |
_invalidateOrder(order, true); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment