diff --git a/README.md b/README.md index acc92ea2..316b7efd 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,6 @@ To run a happy path test of the on-chain contracts plus the off-chain services, b. `per_contract` to the value stored in MULTICALL c. `adapter_contract` to the value stored in ADAPTER 6. Run `cargo run -- run --per-private-key ${OPERATOR_SK}` from `auction-server/`. This should start up the auction server. -7. Run `python3 -m per_sdk.protocols.token_vault_monitor --chain-id development --rpc-url ${ANVIL_RPC_URL} --vault-contract ${TOKEN_VAULT} --weth-contract ${WETH} --liquidation-server-url http://localhost:9000/liquidation/submit_opportunity --mock-pyth`. This should start up the monitor script that exposes liquidatable vaults to the liquidation monitor server. +7. Run `python3 -m per_sdk.protocols.token_vault_monitor --chain-id development --rpc-url ${ANVIL_RPC_URL} --vault-contract ${TOKEN_VAULT} --weth-contract ${WETH} --liquidation-server-url http://localhost:9000/v1/liquidation/opportunities --mock-pyth`. This should start up the monitor script that exposes liquidatable vaults to the liquidation monitor server. 8. Run `python3 -m per_sdk.searcher.simple_searcher --private-key ${SEARCHER_SK} --chain-id development --verbose --liquidation-server-url http://localhost:9000`. 9. Run `forge script script/Vault.s.sol --via-ir --fork-url ${ANVIL_RPC_URL} --private-key ${SK_TX_SENDER} -vvv --sig 'getVault(uint256)' 0 --broadcast` from `per_multicall/`. Confirm that the logged vault amounts are now 0--this indicates that the vault was properly liquidated. diff --git a/auction-server/src/api.rs b/auction-server/src/api.rs index 039258b2..2540533e 100644 --- a/auction-server/src/api.rs +++ b/auction-server/src/api.rs @@ -4,7 +4,7 @@ use { bid::BidResult, liquidation::OpportunityParamsWithMetadata, ws::{ - APIResposne, + APIResponse, ClientMessage, ClientRequest, ServerResultMessage, @@ -21,6 +21,7 @@ use { }, state::{ BidStatus, + BidStatusWithId, OpportunityParams, OpportunityParamsV1, Store, @@ -147,9 +148,10 @@ pub async fn start_api(run_options: RunOptions, store: Arc) -> Result<()> ), components( schemas( - APIResposne, + APIResponse, Bid, BidStatus, + BidStatusWithId, BidResult, OpportunityParamsV1, OpportunityBid, diff --git a/auction-server/src/api/ws.rs b/auction-server/src/api/ws.rs index 68d2cb1c..f61493e4 100644 --- a/auction-server/src/api/ws.rs +++ b/auction-server/src/api/ws.rs @@ -19,7 +19,7 @@ use { }, state::{ BidId, - BidStatus, + BidStatusWithId, OpportunityId, Store, }, @@ -112,23 +112,19 @@ pub enum ServerUpdateResponse { opportunity: OpportunityParamsWithMetadata, }, #[serde(rename = "bid_status_update")] - BidStatusUpdate { - #[schema(value_type = String)] - id: BidId, - status: BidStatus, - }, + BidStatusUpdate { status: BidStatusWithId }, } #[derive(Serialize, Clone, ToSchema)] #[serde(untagged)] -pub enum APIResposne { +pub enum APIResponse { BidResult(BidResult), } #[derive(Serialize, Clone, ToSchema)] #[serde(tag = "status", content = "result")] pub enum ServerResultMessage { #[serde(rename = "success")] - Success(Option), + Success(Option), #[serde(rename = "error")] Err(String), } @@ -161,7 +157,7 @@ async fn websocket_handler(stream: WebSocket, state: Arc) { #[derive(Clone)] pub enum UpdateEvent { NewOpportunity(OpportunityParamsWithMetadata), - BidStatusUpdate { id: BidId, status: BidStatus }, + BidStatusUpdate(BidStatusWithId), } pub type SubscriberId = usize; @@ -260,13 +256,13 @@ impl Subscriber { serde_json::to_string(&ServerUpdateResponse::NewOpportunity { opportunity })?; self.sender.send(message.into()).await?; } - UpdateEvent::BidStatusUpdate { id, status } => { - if !self.bid_ids.contains(&id) { + UpdateEvent::BidStatusUpdate(status) => { + if !self.bid_ids.contains(&status.id) { // Irrelevant update return Ok(()); } let message = - serde_json::to_string(&ServerUpdateResponse::BidStatusUpdate { id, status })?; + serde_json::to_string(&ServerUpdateResponse::BidStatusUpdate { status })?; self.sender.send(message.into()).await?; } } @@ -347,7 +343,7 @@ impl Subscriber { ServerResultResponse { id: Some(id.clone()), result: ServerResultMessage::Success(Some( - APIResposne::BidResult(bid_result.0), + APIResponse::BidResult(bid_result.0), )), } } @@ -373,7 +369,7 @@ impl Subscriber { ServerResultResponse { id: Some(id.clone()), result: ServerResultMessage::Success(Some( - APIResposne::BidResult(bid_result.0), + APIResponse::BidResult(bid_result.0), )), } } diff --git a/auction-server/src/auction.rs b/auction-server/src/auction.rs index d3c932b7..6c68fc5b 100644 --- a/auction-server/src/auction.rs +++ b/auction-server/src/auction.rs @@ -8,6 +8,7 @@ use { }, state::{ BidStatus, + BidStatusWithId, SimulatedBid, Store, }, @@ -254,11 +255,11 @@ pub async fn run_submission_loop(store: Arc) -> Result<()> { tracing::debug!("Submitted transaction: {:?}", receipt); let winner_ids:Vec = winner_bids.iter().map(|b| b.id).collect(); for bid in cloned_bids { - let status = match winner_ids.contains(&bid.id) { + let bid_status = match winner_ids.contains(&bid.id) { true => BidStatus::Submitted(receipt.transaction_hash), false => BidStatus::Lost }; - store.bid_status_store.set_and_broadcast(bid.id, status).await; + store.bid_status_store.set_and_broadcast(BidStatusWithId { id: bid.id, bid_status }).await; } chain_store.bids.write().await.remove(&permission_key); } @@ -349,7 +350,10 @@ pub async fn handle_bid(store: Arc, bid: Bid) -> result::Result>, pub event_sender: broadcast::Sender, @@ -152,12 +162,12 @@ impl BidStatusStore { self.bids_status.read().await.get(id).cloned() } - pub async fn set_and_broadcast(&self, id: BidId, status: BidStatus) { - self.bids_status.write().await.insert(id, status.clone()); - match self - .event_sender - .send(UpdateEvent::BidStatusUpdate { id, status }) - { + pub async fn set_and_broadcast(&self, update: BidStatusWithId) { + self.bids_status + .write() + .await + .insert(update.id, update.bid_status.clone()); + match self.event_sender.send(UpdateEvent::BidStatusUpdate(update)) { Ok(_) => (), Err(e) => tracing::error!("Failed to send bid status update: {}", e), }; diff --git a/per_multicall/src/LiquidationAdapter.sol b/per_multicall/src/LiquidationAdapter.sol index 94ccb4d6..0b6e22a1 100644 --- a/per_multicall/src/LiquidationAdapter.sol +++ b/per_multicall/src/LiquidationAdapter.sol @@ -78,7 +78,7 @@ contract LiquidationAdapter is SigVerify { if (!validSignature) { revert InvalidSearcherSignature(); } - if (block.number > params.validUntil) { + if (block.timestamp > params.validUntil) { revert ExpiredSignature(); } if (_signatureUsed[params.signatureLiquidator]) { diff --git a/per_multicall/src/SearcherVault.sol b/per_multicall/src/SearcherVault.sol index f645ed82..8863bda0 100644 --- a/per_multicall/src/SearcherVault.sol +++ b/per_multicall/src/SearcherVault.sol @@ -40,7 +40,7 @@ contract SearcherVault is SigVerify { * * @param vaultID: ID of the vault to be liquidated * @param bid: size of the bid to pay to PER operator - * @param validUntil: block number until which signatureSearcher is valid + * @param validUntil: timestamp at which signatureSearcher is no longer valid * @param updateData: data to update price feed with * @param signatureSearcher: signature of the vaultID and bid, signed by the searcher's EOA, to be verified if msg.sender is PER Multicall */ @@ -64,7 +64,7 @@ contract SearcherVault is SigVerify { if (!validSignatureSearcher) { revert InvalidSearcherSignature(); } - if (block.number > validUntil) { + if (block.timestamp > validUntil) { revert ExpiredSignature(); } if (_signatureUsed[signatureSearcher]) { diff --git a/per_multicall/test/PERIntegration.t.sol b/per_multicall/test/PERIntegration.t.sol index b636f24e..89fac6f2 100644 --- a/per_multicall/test/PERIntegration.t.sol +++ b/per_multicall/test/PERIntegration.t.sol @@ -596,7 +596,7 @@ contract PERIntegrationTest is bytes memory signatureSearcher; - uint256 validUntil = 1_000_000_000_000; + uint256 validUntil = UINT256_MAX; AccountBalance memory balancesAPre = getBalances( address(searcherA), @@ -642,7 +642,7 @@ contract PERIntegrationTest is bytes memory signatureSearcher; - uint256 validUntil = 1_000_000_000_000; + uint256 validUntil = UINT256_MAX; vm.expectRevert(abi.encodeWithSelector(InvalidLiquidation.selector)); vm.prank(searcherAOwnerAddress, searcherAOwnerAddress); @@ -1065,7 +1065,7 @@ contract PERIntegrationTest is contracts[0] = address(liquidationAdapter); bidInfos[0] = makeBidInfo(15, searcherAOwnerSk); - bidInfos[0].validUntil = block.number - 1; // use old block number for the validUntil field to create expired signature + bidInfos[0].validUntil = block.timestamp - 1; // use old timestamp for the validUntil field to create expired signature ( bytes memory permission,