feat(evm): add grant management and transaction signing

This commit is contained in:
hdbg
2026-03-09 21:04:13 +01:00
parent 43c7b211c3
commit 5dfe390ac3
3 changed files with 185 additions and 12 deletions

View File

@@ -87,6 +87,15 @@ pub enum CreationError {
Database(#[from] diesel::result::Error),
}
/// Controls whether a transaction should be executed or only validated
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RunKind {
/// Validate and record the transaction
Execution,
/// Validate only, do not record
CheckOnly,
}
// Supporting only EIP-1559 transactions for now, but we can easily extend this to support legacy transactions if needed
pub struct Engine {
db: db::DatabasePool,
@@ -97,7 +106,7 @@ impl Engine {
&self,
context: EvalContext,
meaning: &P::Meaning,
dry_run: bool,
run_kind: RunKind,
) -> Result<(), PolicyError> {
let mut conn = self.db.get().await?;
@@ -108,7 +117,7 @@ impl Engine {
let violations = P::evaluate(&context, meaning, &grant, &mut conn).await?;
if !violations.is_empty() {
return Err(PolicyError::Violations(violations));
} else if !dry_run {
} else if run_kind == RunKind::Execution {
conn.transaction(|conn| {
Box::pin(async move {
let log_id: i32 = insert_into(evm_transaction_log::table)
@@ -192,13 +201,12 @@ impl Engine {
Ok(id)
}
pub async fn evaluate_transaction<P: Policy>(
pub async fn evaluate_transaction(
&self,
wallet_id: i32,
client_id: i32,
transaction: TxEip1559,
// don't log
dry_run: bool,
run_kind: RunKind,
) -> Result<SpecificMeaning, VetError> {
let TxKind::Call(to) = transaction.to else {
return Err(VetError::ContractCreationNotSupported);
@@ -214,7 +222,7 @@ impl Engine {
if let Some(meaning) = EtherTransfer::analyze(&context) {
return match self
.vet_transaction::<EtherTransfer>(context, &meaning, dry_run)
.vet_transaction::<EtherTransfer>(context, &meaning, run_kind)
.await
{
Ok(()) => Ok(meaning.into()),
@@ -223,7 +231,7 @@ impl Engine {
}
if let Some(meaning) = TokenTransfer::analyze(&context) {
return match self
.vet_transaction::<TokenTransfer>(context, &meaning, dry_run)
.vet_transaction::<TokenTransfer>(context, &meaning, run_kind)
.await
{
Ok(()) => Ok(meaning.into()),

View File

@@ -59,6 +59,18 @@ pub fn generate(rng: &mut impl rand::Rng) -> (MemSafe<[u8; 32]>, Address) {
}
impl SafeSigner {
/// Reconstructs a `SafeSigner` from key material held in a [`MemSafe`] buffer.
///
/// The key bytes are read from protected memory, parsed as a secp256k1
/// scalar, and immediately moved into a new [`MemSafe`] cell. The raw
/// bytes are never exposed outside this function.
pub fn from_memsafe(mut cell: MemSafe<Vec<u8>>) -> Result<Self> {
let reader = cell.read().map_err(Error::other)?;
let sk = SigningKey::from_slice(reader.as_slice()).map_err(Error::other)?;
drop(reader);
Self::new(sk)
}
/// Creates a new `SafeSigner` by moving the signing key into a protected
/// memory region.
pub fn new(key: SigningKey) -> Result<Self> {