refactor(server): removed grpc adapter and replaced with concrete implementations

This commit is contained in:
hdbg
2026-03-15 23:11:07 +01:00
parent 4db102b3d1
commit 549a0f5f52
29 changed files with 1002 additions and 1620 deletions

View File

@@ -117,9 +117,7 @@ async fn check_shared_constraints(
let now = Utc::now();
// Validity window
if shared.valid_from.is_some_and(|t| now < t)
|| shared.valid_until.is_some_and(|t| now > t)
{
if shared.valid_from.is_some_and(|t| now < t) || shared.valid_until.is_some_and(|t| now > t) {
violations.push(EvalViolation::InvalidTime);
}
@@ -127,9 +125,9 @@ async fn check_shared_constraints(
let fee_exceeded = shared
.max_gas_fee_per_gas
.is_some_and(|cap| U256::from(context.max_fee_per_gas) > cap);
let priority_exceeded = shared.max_priority_fee_per_gas.is_some_and(|cap| {
U256::from(context.max_priority_fee_per_gas) > cap
});
let priority_exceeded = shared
.max_priority_fee_per_gas
.is_some_and(|cap| U256::from(context.max_priority_fee_per_gas) > cap);
if fee_exceeded || priority_exceeded {
violations.push(EvalViolation::GasLimitExceeded {
max_gas_fee_per_gas: shared.max_gas_fee_per_gas,

View File

@@ -73,7 +73,6 @@ pub struct Grant<PolicySettings> {
pub settings: PolicySettings,
}
pub trait Policy: Sized {
type Settings: Send + Sync + 'static + Into<SpecificGrant>;
type Meaning: Display + std::fmt::Debug + Send + Sync + 'static + Into<SpecificMeaning>;

View File

@@ -9,9 +9,7 @@ use crate::db::{
schema::{evm_basic_grant, evm_transaction_log},
};
use crate::evm::{
policies::{
EvalContext, EvalViolation, Grant, Policy, SharedGrantSettings, VolumeRateLimit,
},
policies::{EvalContext, EvalViolation, Grant, Policy, SharedGrantSettings, VolumeRateLimit},
utils,
};

View File

@@ -140,10 +140,18 @@ async fn evaluate_rejects_nonzero_eth_value() {
let mut context = ctx(DAI, calldata);
context.value = U256::from(1u64); // ETH attached to an ERC-20 call
let m = TokenTransfer::analyze(&EvalContext { value: U256::ZERO, ..context.clone() })
let m = TokenTransfer::analyze(&EvalContext {
value: U256::ZERO,
..context.clone()
})
.unwrap();
let v = TokenTransfer::evaluate(&context, &m, &grant, &mut *conn)
.await
.unwrap();
let v = TokenTransfer::evaluate(&context, &m, &grant, &mut *conn).await.unwrap();
assert!(v.iter().any(|e| matches!(e, EvalViolation::InvalidTransactionType)));
assert!(
v.iter()
.any(|e| matches!(e, EvalViolation::InvalidTransactionType))
);
}
#[tokio::test]
@@ -160,7 +168,9 @@ async fn evaluate_passes_any_recipient_when_no_restriction() {
let calldata = transfer_calldata(RECIPIENT, U256::from(100u64));
let context = ctx(DAI, calldata);
let m = TokenTransfer::analyze(&context).unwrap();
let v = TokenTransfer::evaluate(&context, &m, &grant, &mut *conn).await.unwrap();
let v = TokenTransfer::evaluate(&context, &m, &grant, &mut *conn)
.await
.unwrap();
assert!(v.is_empty());
}
@@ -178,7 +188,9 @@ async fn evaluate_passes_matching_restricted_recipient() {
let calldata = transfer_calldata(RECIPIENT, U256::from(100u64));
let context = ctx(DAI, calldata);
let m = TokenTransfer::analyze(&context).unwrap();
let v = TokenTransfer::evaluate(&context, &m, &grant, &mut *conn).await.unwrap();
let v = TokenTransfer::evaluate(&context, &m, &grant, &mut *conn)
.await
.unwrap();
assert!(v.is_empty());
}
@@ -196,8 +208,13 @@ async fn evaluate_rejects_wrong_restricted_recipient() {
let calldata = transfer_calldata(OTHER, U256::from(100u64));
let context = ctx(DAI, calldata);
let m = TokenTransfer::analyze(&context).unwrap();
let v = TokenTransfer::evaluate(&context, &m, &grant, &mut *conn).await.unwrap();
assert!(v.iter().any(|e| matches!(e, EvalViolation::InvalidTarget { .. })));
let v = TokenTransfer::evaluate(&context, &m, &grant, &mut *conn)
.await
.unwrap();
assert!(
v.iter()
.any(|e| matches!(e, EvalViolation::InvalidTarget { .. }))
);
}
#[tokio::test]
@@ -207,7 +224,9 @@ async fn evaluate_passes_volume_within_limit() {
let basic = insert_basic(&mut conn, false).await;
let settings = make_settings(None, Some(1_000));
let grant_id = TokenTransfer::create_grant(&basic, &settings, &mut *conn).await.unwrap();
let grant_id = TokenTransfer::create_grant(&basic, &settings, &mut *conn)
.await
.unwrap();
// Record a past transfer of 500 (within 1000 limit)
use crate::db::{models::NewEvmTokenTransferLog, schema::evm_token_transfer_log};
@@ -224,12 +243,22 @@ async fn evaluate_passes_volume_within_limit() {
.await
.unwrap();
let grant = Grant { id: grant_id, shared_grant_id: basic.id, shared: shared(), settings };
let grant = Grant {
id: grant_id,
shared_grant_id: basic.id,
shared: shared(),
settings,
};
let calldata = transfer_calldata(RECIPIENT, U256::from(100u64));
let context = ctx(DAI, calldata);
let m = TokenTransfer::analyze(&context).unwrap();
let v = TokenTransfer::evaluate(&context, &m, &grant, &mut *conn).await.unwrap();
assert!(!v.iter().any(|e| matches!(e, EvalViolation::VolumetricLimitExceeded)));
let v = TokenTransfer::evaluate(&context, &m, &grant, &mut *conn)
.await
.unwrap();
assert!(
!v.iter()
.any(|e| matches!(e, EvalViolation::VolumetricLimitExceeded))
);
}
#[tokio::test]
@@ -239,7 +268,9 @@ async fn evaluate_rejects_volume_over_limit() {
let basic = insert_basic(&mut conn, false).await;
let settings = make_settings(None, Some(1_000));
let grant_id = TokenTransfer::create_grant(&basic, &settings, &mut *conn).await.unwrap();
let grant_id = TokenTransfer::create_grant(&basic, &settings, &mut *conn)
.await
.unwrap();
use crate::db::{models::NewEvmTokenTransferLog, schema::evm_token_transfer_log};
insert_into(evm_token_transfer_log::table)
@@ -255,12 +286,22 @@ async fn evaluate_rejects_volume_over_limit() {
.await
.unwrap();
let grant = Grant { id: grant_id, shared_grant_id: basic.id, shared: shared(), settings };
let grant = Grant {
id: grant_id,
shared_grant_id: basic.id,
shared: shared(),
settings,
};
let calldata = transfer_calldata(RECIPIENT, U256::from(100u64));
let context = ctx(DAI, calldata);
let m = TokenTransfer::analyze(&context).unwrap();
let v = TokenTransfer::evaluate(&context, &m, &grant, &mut *conn).await.unwrap();
assert!(v.iter().any(|e| matches!(e, EvalViolation::VolumetricLimitExceeded)));
let v = TokenTransfer::evaluate(&context, &m, &grant, &mut *conn)
.await
.unwrap();
assert!(
v.iter()
.any(|e| matches!(e, EvalViolation::VolumetricLimitExceeded))
);
}
#[tokio::test]
@@ -277,8 +318,13 @@ async fn evaluate_no_volume_limits_always_passes() {
let calldata = transfer_calldata(RECIPIENT, U256::from(u64::MAX));
let context = ctx(DAI, calldata);
let m = TokenTransfer::analyze(&context).unwrap();
let v = TokenTransfer::evaluate(&context, &m, &grant, &mut *conn).await.unwrap();
assert!(!v.iter().any(|e| matches!(e, EvalViolation::VolumetricLimitExceeded)));
let v = TokenTransfer::evaluate(&context, &m, &grant, &mut *conn)
.await
.unwrap();
assert!(
!v.iter()
.any(|e| matches!(e, EvalViolation::VolumetricLimitExceeded))
);
}
// ── try_find_grant ───────────────────────────────────────────────────────
@@ -290,7 +336,9 @@ async fn try_find_grant_roundtrip() {
let basic = insert_basic(&mut conn, false).await;
let settings = make_settings(Some(RECIPIENT), Some(5_000));
TokenTransfer::create_grant(&basic, &settings, &mut *conn).await.unwrap();
TokenTransfer::create_grant(&basic, &settings, &mut *conn)
.await
.unwrap();
let calldata = transfer_calldata(RECIPIENT, U256::from(100u64));
let found = TokenTransfer::try_find_grant(&ctx(DAI, calldata), &mut *conn)
@@ -312,7 +360,9 @@ async fn try_find_grant_revoked_returns_none() {
let basic = insert_basic(&mut conn, true).await;
let settings = make_settings(None, None);
TokenTransfer::create_grant(&basic, &settings, &mut *conn).await.unwrap();
TokenTransfer::create_grant(&basic, &settings, &mut *conn)
.await
.unwrap();
let calldata = transfer_calldata(RECIPIENT, U256::from(1u64));
let found = TokenTransfer::try_find_grant(&ctx(DAI, calldata), &mut *conn)
@@ -328,7 +378,9 @@ async fn try_find_grant_unknown_token_returns_none() {
let basic = insert_basic(&mut conn, false).await;
let settings = make_settings(None, None);
TokenTransfer::create_grant(&basic, &settings, &mut *conn).await.unwrap();
TokenTransfer::create_grant(&basic, &settings, &mut *conn)
.await
.unwrap();
// Query with a different token contract
let calldata = transfer_calldata(RECIPIENT, U256::from(1u64));
@@ -355,9 +407,13 @@ async fn find_all_grants_excludes_revoked() {
let settings = make_settings(None, Some(1_000));
let active = insert_basic(&mut conn, false).await;
TokenTransfer::create_grant(&active, &settings, &mut *conn).await.unwrap();
TokenTransfer::create_grant(&active, &settings, &mut *conn)
.await
.unwrap();
let revoked = insert_basic(&mut conn, true).await;
TokenTransfer::create_grant(&revoked, &settings, &mut *conn).await.unwrap();
TokenTransfer::create_grant(&revoked, &settings, &mut *conn)
.await
.unwrap();
let all = TokenTransfer::find_all_grants(&mut *conn).await.unwrap();
assert_eq!(all.len(), 1);
@@ -370,12 +426,17 @@ async fn find_all_grants_loads_volume_limits() {
let basic = insert_basic(&mut conn, false).await;
let settings = make_settings(None, Some(9_999));
TokenTransfer::create_grant(&basic, &settings, &mut *conn).await.unwrap();
TokenTransfer::create_grant(&basic, &settings, &mut *conn)
.await
.unwrap();
let all = TokenTransfer::find_all_grants(&mut *conn).await.unwrap();
assert_eq!(all.len(), 1);
assert_eq!(all[0].settings.volume_limits.len(), 1);
assert_eq!(all[0].settings.volume_limits[0].max_volume, U256::from(9_999u64));
assert_eq!(
all[0].settings.volume_limits[0].max_volume,
U256::from(9_999u64)
);
}
#[tokio::test]
@@ -388,9 +449,13 @@ async fn find_all_grants_multiple_grants_batch_loaded() {
.await
.unwrap();
let b2 = insert_basic(&mut conn, false).await;
TokenTransfer::create_grant(&b2, &make_settings(Some(RECIPIENT), Some(2_000)), &mut *conn)
.await
.unwrap();
TokenTransfer::create_grant(
&b2,
&make_settings(Some(RECIPIENT), Some(2_000)),
&mut *conn,
)
.await
.unwrap();
let all = TokenTransfer::find_all_grants(&mut *conn).await.unwrap();
assert_eq!(all.len(), 2);

View File

@@ -3,11 +3,11 @@ use std::sync::Mutex;
use alloy::{
consensus::SignableTransaction,
network::{TxSigner, TxSignerSync},
primitives::{Address, ChainId, Signature, B256},
primitives::{Address, B256, ChainId, Signature},
signers::{Error, Result, Signer, SignerSync, utils::secret_key_to_address},
};
use async_trait::async_trait;
use k256::ecdsa::{self, signature::hazmat::PrehashSigner, RecoveryId, SigningKey};
use k256::ecdsa::{self, RecoveryId, SigningKey, signature::hazmat::PrehashSigner};
use memsafe::MemSafe;
/// An Ethereum signer that stores its secp256k1 secret key inside a
@@ -90,10 +90,7 @@ impl SafeSigner {
Ok(sig.into())
}
fn sign_tx_inner(
&self,
tx: &mut dyn SignableTransaction<Signature>,
) -> Result<Signature> {
fn sign_tx_inner(&self, tx: &mut dyn SignableTransaction<Signature>) -> Result<Signature> {
if let Some(chain_id) = self.chain_id
&& !tx.set_chain_id_checked(chain_id)
{
@@ -102,7 +99,8 @@ impl SafeSigner {
tx: tx.chain_id().unwrap(),
});
}
self.sign_hash_inner(&tx.signature_hash()).map_err(Error::other)
self.sign_hash_inner(&tx.signature_hash())
.map_err(Error::other)
}
}