Building a DSL for Modular RETH Transaction Middleware

Isaac Patka - Shield3


With RETH we can extend the RPC api and add middleware


With RETH we can extend the RPC api and add security middleware


With RETH we can extend the RPC api and add modular security middleware


Building a DSL for modular middleware

  • Make decisions based on transaction context
  • Without doing simulations
  • Customizable with minimal code

What can we reuse from the Rust ecosystem

  • Cedar Policy Language
  • Recently open sourced by AWS
  • Written in Rust

But Cedar was not built for crypto

permit (
  principal == User::"alice",
  action == Action::"view",
  resource in Album::"jane_vacation"
)
unless { resource.tags.contains("private") } ;


By combining Cedar with ethers-rs (todo alloy) we can help it understand Ethereum transaction context

permit (
  principal,
  action == Action::"EOATransaction",
  resource
)
when { context.value.u256LessThan(principal.valueLimit) };

And we can define routing for the node to execute

@name("WARN-NATIVE-ASSET-THRESHOLD")
@advice("Warn when sending funds over X threshold")
@trigger("WEBHOOK-e03a0aa1")
forbid (
  principal,
  action == Action::"EOATransaction",
  resource
)
when { context.value.u256GreaterThan(principal.valueLimit) };

Policy Engine Execution

The Policy Engine needs the following data to make a decision:

  • extensions for transaction datatypes
  • schema for all referenced entities, actions, relationships, contexts
  • action data of the requested operation
  • entities data defined for the resources affected by the action
  • policy statements to evaluate

Extensions (ex. U256)

use ethers::prelude::U256;

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
struct UINT256 {
    value: U256,
}

mod names {
    use super::{Name, EXTENSION_NAME};
    lazy_static::lazy_static! {
        pub static ref UINT256_FROM_STR_NAME : Name = Name::parse_unqualified_name(EXTENSION_NAME).expect("should be a valid identifier");
        pub static ref LESS_THAN : Name = Name::parse_unqualified_name("u256LessThan").expect("should be a valid identifier");
        pub static ref LESS_THAN_OR_EQUAL : Name = Name::parse_unqualified_name("u256LessThanOrEqual").expect("should be a valid identifier");
        pub static ref GREATER_THAN : Name = Name::parse_unqualified_name("u256GreaterThan").expect("should be a valid identifier");
        pub static ref GREATER_THAN_OR_EQUAL : Name = Name::parse_unqualified_name("u256GreaterThanOrEqual").expect("should be a valid identifier");
    }
}

Schema

JSON Schema defining the shape of contracts, addresses, networks, transactions

{
    "entityTypes": {
        "Contract": {
            "memberOfTypes": [
                "Network"
            ],
            "shape": {
                "type": "Record",
                "attributes": {
                    "abi": {
                        "type": "String"
                    }
                }
            }
        },
        "EOA": {
            "memberOfTypes": [
                "Network"
            ],
            "shape": {
                "type": "Record",
                "attributes": {
                    "valueLimit": {
                        "type": "Extension",
                        "name": "u256",
                        "required": false
                    }
                }
            }
        },
        "Network": {
            "memberOfTypes": [],
            "shape": {
                "type": "Record",
                "attributes": {
                    "name": {
                        "type": "String"
                    },
                    "chainId": {
                        "type": "Long"
                    }
                }
            }
        }
    },
    "actions": {
        "EOATransaction": {
            "appliesTo": {
                "resourceTypes": [
                    "EOA"
                ],
                "principalTypes": [
                    "EOA"
                ],
                "context": {
                    "type": "ReusedContext"
                }
            }
        },
        "ContractTransaction": {
            "appliesTo": {
                "resourceTypes": [
                    "Contract"
                ],
                "principalTypes": [
                    "EOA"
                ],
                "context": {
                    "type": "ReusedContext"
                }
            }
        }
    },
    "commonTypes": {
        "ReusedContext": {
            "type": "Record",
            "attributes": {
                "transaction": {
                    "type": "String"
                },
                "value": {
                    "type": "Extension",
                    "name": "u256",
                    "required": true
                }
            }
        }
    }
}

Actions

{
    "principal": "EOA::\"0x0000000000000000000000000000000000000001\"",
    "action": "Action::\"ContractTransaction\"",
    "resource": "Contract::\"0x0000000000000000000000000000000000000002\"",
    "context": {
        "value": {
            "__expr": "u256(\"100\")"
        }
    }
}

Entities

[
    {
        "uid": {
            "type": "EOA",
            "id": "0x0000000000000000000000000000000000000001"
        },
        "attrs": {},
        "parents": [
            {
                "type": "Network",
                "id": "mainnet"
            }
        ]
    },
    {
        "uid": {
            "type": "EOA",
            "id": "0x0000000000000000000000000000000000000111"
        },
        "attrs": {
            "valueLimit": {
                "__expr": "u256(\"100\")"
            }
        },
        "parents": [
            {
                "type": "Network",
                "id": "mainnet"
            }
        ]
    },
    {
        "uid": {
            "type": "EOA",
            "id": "0x0000000000000000000000000000000000000011"
        },
        "attrs": {},
        "parents": [
            {
                "type": "Network",
                "id": "mainnet"
            }
        ]
    },
    {
        "uid": {
            "type": "Contract",
            "id": "0x0000000000000000000000000000000000000002"
        },
        "attrs": {
            "abi": "DEMOABI"
        },
        "parents": [
            {
                "type": "Network",
                "id": "mainnet"
            }
        ]
    },
    {
        "uid": {
            "type": "Network",
            "id": "mainnet"
        },
        "attrs": {
            "chainId": 1
        },
    }
]

Policies

@name("WARN-NATIVE-ASSET-THRESHOLD")
@advice("Warn when sending funds over X threshold")
@notification("WEBHOOK-e03a0aa1")
forbid (
  principal,
  action == Action::"EOATransaction",
  resource
)
when { context.value.u256GreaterThan(principal.valueLimit) };

Build modular, customizable, composable middleware


Read More

Select a repo