mirror of
https://github.com/serai-dex/serai.git
synced 2024-12-24 20:49:27 +00:00
Add selector collisions to Router to make it IRouter compatible
This commit is contained in:
parent
8de42cc2d4
commit
2f5c0c68d0
5 changed files with 65 additions and 36 deletions
|
@ -20,7 +20,9 @@ workspace = true
|
|||
group = { version = "0.13", default-features = false }
|
||||
|
||||
alloy-core = { version = "0.8", default-features = false }
|
||||
|
||||
alloy-sol-types = { version = "0.8", default-features = false }
|
||||
alloy-sol-macro = { version = "0.8", default-features = false }
|
||||
|
||||
alloy-consensus = { version = "0.3", default-features = false }
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ fn main() {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
// This cannot be handled with the sol! macro. The Solidity requires an import
|
||||
// This cannot be handled with the sol! macro. The Router requires an import
|
||||
// https://github.com/alloy-rs/core/issues/602
|
||||
sol(
|
||||
&[
|
||||
|
|
|
@ -171,10 +171,14 @@ contract Router {
|
|||
}
|
||||
|
||||
/// @notice Update the key representing Serai's Ethereum validators
|
||||
/// @dev This assumes the key is correct. No checks on it are performed
|
||||
/**
|
||||
* @dev This assumes the key is correct. No checks on it are performed.
|
||||
*
|
||||
* The hex bytes are to cause a collision with `IRouter.updateSeraiKey`.
|
||||
*/
|
||||
// @param signature The signature by the current key authorizing this update
|
||||
// @param newSeraiKey The key to update to
|
||||
function updateSeraiKey() external {
|
||||
function updateSeraiKey5A8542A2() external {
|
||||
(uint256 nonceUsed, bytes memory args,) = verifySignature();
|
||||
/*
|
||||
We could replace this with a length check (if we don't simply assume the calldata is valid as
|
||||
|
@ -341,7 +345,9 @@ contract Router {
|
|||
/// @notice Execute a batch of `OutInstruction`s
|
||||
/**
|
||||
* @dev All `OutInstruction`s in a batch are only for a single coin to simplify handling of the
|
||||
* fee
|
||||
* fee.
|
||||
*
|
||||
* The hex bytes are to cause a function selector collision with `IRouter.execute`.
|
||||
*/
|
||||
// @param signature The signature by the current key for Serai's Ethereum validators
|
||||
// @param coin The coin all of these `OutInstruction`s are for
|
||||
|
@ -349,7 +355,7 @@ contract Router {
|
|||
// @param outs The `OutInstruction`s to act on
|
||||
// Each individual call is explicitly metered to ensure there isn't a DoS here
|
||||
// slither-disable-next-line calls-loop
|
||||
function execute() external {
|
||||
function execute4DE42904() external {
|
||||
(uint256 nonceUsed, bytes memory args, bytes32 message) = verifySignature();
|
||||
(,, address coin, uint256 fee, IRouter.OutInstruction[] memory outs) =
|
||||
abi.decode(args, (bytes32, bytes32, address, uint256, IRouter.OutInstruction[]));
|
||||
|
@ -418,10 +424,14 @@ contract Router {
|
|||
}
|
||||
|
||||
/// @notice Escapes to a new smart contract
|
||||
/// @dev This should be used upon an invariant being reached or new functionality being needed
|
||||
/**
|
||||
* @dev This should be used upon an invariant being reached or new functionality being needed.
|
||||
*
|
||||
* The hex bytes are to cause a collision with `IRouter.updateSeraiKey`.
|
||||
*/
|
||||
// @param signature The signature by the current key for Serai's Ethereum validators
|
||||
// @param escapeTo The address to escape to
|
||||
function escapeHatch() external {
|
||||
function escapeHatchDCDD91CC() external {
|
||||
// Verify the signature
|
||||
(, bytes memory args,) = verifySignature();
|
||||
|
||||
|
|
|
@ -28,15 +28,23 @@ use serai_client::networks::ethereum::Address as SeraiAddress;
|
|||
#[expect(clippy::all)]
|
||||
#[expect(clippy::ignored_unit_patterns)]
|
||||
#[expect(clippy::redundant_closure_for_method_calls)]
|
||||
mod _abi {
|
||||
pub mod _irouter_abi {
|
||||
alloy_sol_macro::sol!("contracts/IRouter.sol");
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[expect(warnings)]
|
||||
#[expect(needless_pass_by_value)]
|
||||
#[expect(clippy::all)]
|
||||
#[expect(clippy::ignored_unit_patterns)]
|
||||
#[expect(clippy::redundant_closure_for_method_calls)]
|
||||
mod _router_abi {
|
||||
include!(concat!(env!("OUT_DIR"), "/serai-processor-ethereum-router/router.rs"));
|
||||
}
|
||||
|
||||
mod abi {
|
||||
pub use super::_abi::IRouter::{
|
||||
Signature, DestinationType, CodeDestination, OutInstruction, SeraiKeyUpdated, InInstruction,
|
||||
Executed, EscapeHatch, Escaped,
|
||||
};
|
||||
pub use super::_abi::Router::*;
|
||||
pub use super::_router_abi::IRouter::*;
|
||||
pub use super::_router_abi::Router::constructorCall;
|
||||
}
|
||||
use abi::{
|
||||
SeraiKeyUpdated as SeraiKeyUpdatedEvent, InInstruction as InInstructionEvent,
|
||||
|
@ -315,23 +323,22 @@ impl Router {
|
|||
|
||||
/// Get the message to be signed in order to update the key for Serai.
|
||||
pub fn update_serai_key_message(nonce: u64, key: &PublicKey) -> Vec<u8> {
|
||||
[
|
||||
abi::updateSeraiKeyCall::SELECTOR.as_slice(),
|
||||
&(U256::try_from(nonce).unwrap(), U256::ZERO, key.eth_repr()).abi_encode_params(),
|
||||
]
|
||||
.concat()
|
||||
abi::updateSeraiKeyCall::new((
|
||||
abi::Signature { c: U256::try_from(nonce).unwrap().into(), s: U256::ZERO.into() },
|
||||
key.eth_repr().into(),
|
||||
))
|
||||
.abi_encode()
|
||||
}
|
||||
|
||||
/// Construct a transaction to update the key representing Serai.
|
||||
pub fn update_serai_key(&self, public_key: &PublicKey, sig: &Signature) -> TxLegacy {
|
||||
TxLegacy {
|
||||
to: TxKind::Call(self.1),
|
||||
input: [
|
||||
abi::updateSeraiKeyCall::SELECTOR.as_slice(),
|
||||
&(abi::Signature::from(sig), public_key.eth_repr()).abi_encode_params(),
|
||||
]
|
||||
.concat()
|
||||
.into(),
|
||||
input: abi::updateSeraiKeyCall::new((
|
||||
abi::Signature::from(sig),
|
||||
public_key.eth_repr().into(),
|
||||
))
|
||||
.abi_encode().into(),
|
||||
gas_limit: 40_889 * 120 / 100,
|
||||
..Default::default()
|
||||
}
|
||||
|
@ -339,12 +346,13 @@ impl Router {
|
|||
|
||||
/// Get the message to be signed in order to execute a series of `OutInstruction`s.
|
||||
pub fn execute_message(nonce: u64, coin: Coin, fee: U256, outs: OutInstructions) -> Vec<u8> {
|
||||
[
|
||||
abi::executeCall::SELECTOR.as_slice(),
|
||||
&(U256::try_from(nonce).unwrap(), U256::ZERO, coin.address(), fee, outs.0)
|
||||
.abi_encode_params(),
|
||||
]
|
||||
.concat()
|
||||
abi::executeCall::new((
|
||||
abi::Signature { c: U256::try_from(nonce).unwrap().into(), s: U256::ZERO.into() },
|
||||
coin.address(),
|
||||
fee,
|
||||
outs.0,
|
||||
))
|
||||
.abi_encode()
|
||||
}
|
||||
|
||||
/// Construct a transaction to execute a batch of `OutInstruction`s.
|
||||
|
@ -352,12 +360,9 @@ impl Router {
|
|||
let outs_len = outs.0.len();
|
||||
TxLegacy {
|
||||
to: TxKind::Call(self.1),
|
||||
input: [
|
||||
abi::executeCall::SELECTOR.as_slice(),
|
||||
&(abi::Signature::from(sig), coin.address(), fee, outs.0).abi_encode_params(),
|
||||
]
|
||||
.concat()
|
||||
.into(),
|
||||
input: abi::executeCall::new((abi::Signature::from(sig), coin.address(), fee, outs.0))
|
||||
.abi_encode()
|
||||
.into(),
|
||||
// TODO
|
||||
gas_limit: (45_501 + ((200_000 + 10_000) * u128::try_from(outs_len).unwrap())) * 120 / 100,
|
||||
..Default::default()
|
||||
|
|
|
@ -22,6 +22,18 @@ use ethereum_deployer::Deployer;
|
|||
|
||||
use crate::{Coin, OutInstructions, Router};
|
||||
|
||||
#[test]
|
||||
fn selector_collisions() {
|
||||
assert_eq!(
|
||||
crate::_irouter_abi::IRouter::executeCall::SELECTOR,
|
||||
crate::_router_abi::Router::execute4DE42904Call::SELECTOR
|
||||
);
|
||||
assert_eq!(
|
||||
crate::_irouter_abi::IRouter::updateSeraiKeyCall::SELECTOR,
|
||||
crate::_router_abi::Router::updateSeraiKey5A8542A2Call::SELECTOR
|
||||
);
|
||||
}
|
||||
|
||||
pub(crate) fn test_key() -> (Scalar, PublicKey) {
|
||||
loop {
|
||||
let key = Scalar::random(&mut OsRng);
|
||||
|
|
Loading…
Reference in a new issue