mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-10 21:19:24 +00:00
Have the Ethereum scheduler create Batches as necessary
Also introduces the fee logic, despite it being stubbed.
This commit is contained in:
@@ -1,6 +1,11 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use alloy_core::primitives::U256;
|
||||
|
||||
use serai_client::primitives::{NetworkId, Coin, Balance};
|
||||
use serai_client::{
|
||||
primitives::{NetworkId, Coin, Balance},
|
||||
networks::ethereum::Address,
|
||||
};
|
||||
|
||||
use serai_db::Db;
|
||||
|
||||
@@ -53,27 +58,86 @@ impl<D: Db> smart_contract_scheduler::SmartContract<Rpc<D>> for SmartContract {
|
||||
|
||||
fn fulfill(
|
||||
&self,
|
||||
nonce: u64,
|
||||
mut nonce: u64,
|
||||
_key: KeyFor<Rpc<D>>,
|
||||
payments: Vec<Payment<AddressFor<Rpc<D>>>>,
|
||||
) -> Vec<(Self::SignableTransaction, EventualityFor<Rpc<D>>)> {
|
||||
let mut outs = Vec::with_capacity(payments.len());
|
||||
// Sort by coin
|
||||
let mut outs = HashMap::<_, _>::new();
|
||||
for payment in payments {
|
||||
outs.push((
|
||||
payment.address().clone(),
|
||||
(
|
||||
coin_to_ethereum_coin(payment.balance().coin),
|
||||
balance_to_ethereum_amount(payment.balance()),
|
||||
),
|
||||
));
|
||||
let coin = payment.balance().coin;
|
||||
outs
|
||||
.entry(coin)
|
||||
.or_insert_with(|| Vec::with_capacity(1))
|
||||
.push((payment.address().clone(), balance_to_ethereum_amount(payment.balance())));
|
||||
}
|
||||
|
||||
// TODO: Per-batch gas limit
|
||||
// TODO: Create several batches
|
||||
// TODO: Handle fees
|
||||
let action = Action::Batch { chain_id: self.chain_id, nonce, outs };
|
||||
let mut res = vec![];
|
||||
for coin in [Coin::Ether, Coin::Dai] {
|
||||
let Some(outs) = outs.remove(&coin) else { continue };
|
||||
assert!(!outs.is_empty());
|
||||
|
||||
vec![(action.clone(), action.eventuality())]
|
||||
let fee_per_gas: U256 = todo!("TODO");
|
||||
|
||||
// The gas required to perform any interaction with the Router.
|
||||
const BASE_GAS: u32 = 0; // TODO
|
||||
|
||||
// The gas required to handle an additional payment to an address, in the worst case.
|
||||
const ADDRESS_PAYMENT_GAS: u32 = 0; // TODO
|
||||
|
||||
// The gas required to handle an additional payment to an smart contract, in the worst case.
|
||||
// This does not include the explicit gas budget defined within the address specification.
|
||||
const CONTRACT_PAYMENT_GAS: u32 = 0; // TODO
|
||||
|
||||
// The maximum amount of gas for a batch.
|
||||
const BATCH_GAS_LIMIT: u32 = 10_000_000;
|
||||
|
||||
// Split these outs into batches, respecting BATCH_GAS_LIMIT
|
||||
let mut batches = vec![vec![]];
|
||||
let mut current_gas = BASE_GAS;
|
||||
for out in outs {
|
||||
let payment_gas = match out.0 {
|
||||
Address::Address(_) => ADDRESS_PAYMENT_GAS,
|
||||
Address::Contract(deployment) => CONTRACT_PAYMENT_GAS + deployment.gas_limit(),
|
||||
};
|
||||
if (current_gas + payment_gas) > BATCH_GAS_LIMIT {
|
||||
assert!(!batches.last().unwrap().is_empty());
|
||||
batches.push(vec![]);
|
||||
current_gas = BASE_GAS;
|
||||
}
|
||||
batches.last_mut().unwrap().push(out);
|
||||
current_gas += payment_gas;
|
||||
}
|
||||
|
||||
// Push each batch onto the result
|
||||
for outs in batches {
|
||||
let base_gas = BASE_GAS.div_ceil(u32::try_from(outs.len()).unwrap());
|
||||
// Deduce the fee from each out
|
||||
for out in &mut outs {
|
||||
let payment_gas = base_gas +
|
||||
match out.0 {
|
||||
Address::Address(_) => ADDRESS_PAYMENT_GAS,
|
||||
Address::Contract(deployment) => CONTRACT_PAYMENT_GAS + deployment.gas_limit(),
|
||||
};
|
||||
|
||||
let payment_gas_cost = fee_per_gas * U256::try_from(payment_gas).unwrap();
|
||||
out.1 -= payment_gas_cost;
|
||||
}
|
||||
|
||||
res.push(Action::Batch {
|
||||
chain_id: self.chain_id,
|
||||
nonce,
|
||||
coin: coin_to_ethereum_coin(coin),
|
||||
fee_per_gas,
|
||||
outs,
|
||||
});
|
||||
nonce += 1;
|
||||
}
|
||||
}
|
||||
// Ensure we handled all payments we're supposed to
|
||||
assert!(outs.is_empty());
|
||||
|
||||
res.into_iter().map(|action| (action.clone(), action.eventuality())).collect()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user