diff --git a/processor/ethereum/router/contracts/IRouter.sol b/processor/ethereum/router/contracts/IRouter.sol index 57994f8d..c22bef3c 100644 --- a/processor/ethereum/router/contracts/IRouter.sol +++ b/processor/ethereum/router/contracts/IRouter.sol @@ -45,6 +45,8 @@ interface IRouterWithoutCollisions { /// @param amount The amount which escaped event Escaped(address indexed coin, uint256 amount); + /// @notice The Serai key verifying the signature wasn't set + error SeraiKeyWasNone(); /// @notice The key for Serai was invalid /// @dev This is incomplete and not always guaranteed to be thrown upon an invalid key error InvalidSeraiKey(); diff --git a/processor/ethereum/router/contracts/Router.sol b/processor/ethereum/router/contracts/Router.sol index e0bc77bb..c3f6befa 100644 --- a/processor/ethereum/router/contracts/Router.sol +++ b/processor/ethereum/router/contracts/Router.sol @@ -137,7 +137,7 @@ contract Router is IRouterWithoutCollisions { The Schnorr contract should already reject this public key yet it's best to be explicit. */ if (key == bytes32(0)) { - revert InvalidSignature(); + revert SeraiKeyWasNone(); } message = msg.data; @@ -266,7 +266,7 @@ contract Router is IRouterWithoutCollisions { function inInstruction(address coin, uint256 amount, bytes memory instruction) external payable { // Check there is an active key if (_seraiKey == bytes32(0)) { - revert InvalidSeraiKey(); + revert SeraiKeyWasNone(); } // Don't allow further InInstructions once the escape hatch has been invoked diff --git a/processor/ethereum/router/src/tests/mod.rs b/processor/ethereum/router/src/tests/mod.rs index f66a70f8..da79e956 100644 --- a/processor/ethereum/router/src/tests/mod.rs +++ b/processor/ethereum/router/src/tests/mod.rs @@ -367,10 +367,46 @@ async fn test_constructor() { #[tokio::test] async fn test_confirm_next_serai_key() { let mut test = Test::new().await; - // TODO: Check all calls fail at this time, including inInstruction test.confirm_next_serai_key().await; } +#[tokio::test] +async fn test_no_serai_key() { + // Before we confirm a key, any operations requiring a signature shouldn't work + { + let mut test = Test::new().await; + + // Corrupt the test's state so we can obtain signed TXs + test.state.key = Some(test_key()); + + assert!(matches!( + test.call_and_decode_err(test.update_serai_key_tx().1).await, + IRouterErrors::SeraiKeyWasNone(IRouter::SeraiKeyWasNone {}) + )); + /* TODO + assert!(matches!( + test.call_and_decode_err(test.execute_tx()).await, + IRouterErrors::SeraiKeyWasNone(IRouter::SeraiKeyWasNone {}) + )); + */ + assert!(matches!( + test.call_and_decode_err(test.escape_hatch_tx(Address::ZERO)).await, + IRouterErrors::SeraiKeyWasNone(IRouter::SeraiKeyWasNone {}) + )); + } + + // And if there's no key to confirm, any operations requiring a signature shouldn't work + { + let mut test = Test::new().await; + test.confirm_next_serai_key().await; + test.state.next_key = Some(test_key()); + assert!(matches!( + test.call_and_decode_err(test.confirm_next_serai_key_tx()).await, + IRouterErrors::SeraiKeyWasNone(IRouter::SeraiKeyWasNone {}) + )); + } +} + #[tokio::test] async fn test_update_serai_key() { let mut test = Test::new().await; @@ -421,7 +457,7 @@ async fn test_no_in_instruction_before_key() { let (_coin, _amount, _shorthand, tx) = test.eth_in_instruction_tx(); assert!(matches!( test.call_and_decode_err(tx).await, - IRouterErrors::InvalidSeraiKey(IRouter::InvalidSeraiKey {}) + IRouterErrors::SeraiKeyWasNone(IRouter::SeraiKeyWasNone {}) )); }