Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions contracts/blake2f/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# BLAKE2F

BLAKE2f (EIP-152) precompile wrapper. Exposes the BLAKE2 F compression function with the same input/output and gas rules
as Ethereum.

- Entrypoint: main_entry (single entry). Reads full input, executes revm_precompile::blake2::run, syncs gas, writes
output.
- Input (213 bytes): rounds(4) || h(64) || m(128) || t(16) || f(1). Any other size is rejected.
- Output: 64-byte state after applying F.
- Gas: Charged identically to EVM via sdk.sync_evm_gas(result.gas_used, 0).
- Host: Uses SharedAPI for I/O and fuel; deterministic and byte-for-byte compatible with EVM precompile.

Usage

- Link this crate and call its entrypoint as a precompile. Provide the exact 213-byte payload; the result buffer is the
64-byte digest state.
13 changes: 13 additions & 0 deletions contracts/bls12381/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# BLS12-381

BLS12-381 precompile-style wrappers. Provides group operations and pairing checks over BLS12-381 for environments that
expose these as host functions.

- Entrypoint: main_entry (router in-crate dispatches ops if present).
- Ops: G1/G2 add, G1/G2 mul, pairing check; exact encoding follows crate implementation (affine coordinates,
big-endian).
- Output: points encoded in affine (x||y), pairing returns 32-byte 0/1.
- Gas: Mirrors configured host schedule; charged via sdk.sync_evm_gas.

Note: BLS12-381 is not part of Ethereum’s main precompile set; ensure your host enables and documents the encodings used
here.
12 changes: 12 additions & 0 deletions contracts/bn256/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# BN256

alt_bn128 (BN256) precompile wrappers (EIP-196/197). Implements G1 add, G1 mul, and pairing check with EVM-compatible
I/O and gas.

- Entrypoint: main_entry (router inside the crate dispatches to the selected op if applicable).
- Ops and Inputs:
- ADD (0x06): two points in affine (x,y) over Fq; 64 bytes per point; output is 64-byte point.
- MUL (0x07): point (64 bytes) and scalar (32 bytes); output is 64-byte point.
- PAIRING (0x08): sequence of (G1,G2) tuples; input multiple of 192 bytes; output 32-byte 0/1.
- Gas: Matches EVM precompile schedule; charged via sdk.sync_evm_gas.
- Validation: Points/scalars must be in field/subgroup; invalid encodings yield failure per spec.
12 changes: 12 additions & 0 deletions contracts/ecrecover/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# ECRECOVER

secp256k1 ecrecover precompile wrapper (0x01). Recovers the Ethereum address from a message hash and ECDSA signature.

- Entrypoint: main_entry. Reads input, executes revm_precompile::secp256k1::ec_recover_run, syncs gas, writes output.
- Input: 128 bytes per the Ethereum precompile (hash(32) || v(32) || r(32) || s(32)). Non-standard sizes are rejected.
- Output: 32 bytes; the right-most 20 bytes hold the recovered address (left-padded with zeros) or empty on failure.
- Gas: EVM-compatible flat cost via sdk.sync_evm_gas.

Notes

- v must be 27/28 (or have low/high bits matching EVM rules). Invalid s or v yields empty output.
11 changes: 11 additions & 0 deletions contracts/eip2935/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# EIP-2935

EIP-2935 system contract wrapper: access to historical block hashes (or related consensus data) via a host-provided
interface.

- Entrypoint: main_entry. Decodes method selector and arguments, queries host, writes result.
- Methods: get_block_hash(number) -> B256; exact ABI follows crate implementation.
- Gas: Mirrors EVM rules for the corresponding op; charged via sdk.sync_evm_gas or final settlement.

Note: Behavior depends on host-maintained history length and pruning policy; ensure alignment with your network’s
parameters.
22 changes: 22 additions & 0 deletions contracts/erc20/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# ERC20

ERC‑20 contract implemented for Fluentbase with an SDK-first design and optional features (mintable/pausable). The crate
exposes a single WASM entrypoint that routes calls by 4‑byte function selectors (Solidity‑style).

- Entrypoint: main_entry. Dispatches using known selectors; non-matching calls revert.
- Supported functions (subset):
- name() -> string, symbol() -> string, decimals() -> uint8
- totalSupply() -> uint256, balanceOf(address) -> uint256
- transfer(address,uint256) -> bool, transferFrom(address,address,uint256) -> bool
- approve(address,uint256) -> bool, allowance(address,address) -> uint256
- Optional: mint(address,uint256), pause(), unpause() (guarded by settings)
- Events: Transfer, Approval, Pause/Unpause (topic layout compatible with EVM logs).
- Storage: Keyed by addresses; balances, allowances, and config live in contract metadata via SharedAPI storage helpers.
- Host integration: Uses SharedAPI for caller/context, storage, and I/O. On SVM targets, bindings bridge to Solana
Token‑2022 via fluentbase‑svm.

Notes

- ABI is Solidity-like; selectors and encodings are defined in fluentbase_erc20. See lib.rs for offsets and exact
packing.
- Gas/fuel is accounted by the host; state changes are deterministic and independent of the runtime backend.
86 changes: 49 additions & 37 deletions contracts/evm/README.md
Original file line number Diff line number Diff line change
@@ -1,53 +1,65 @@
# EVM

This project provides an implementation of an execution environment that interfaces with the EVM or executes
WebAssembly-based smart contracts. It manages interactions between smart contracts and their
operational environment, handling deployment, execution, gas costs, and storage synchronization. The primary focus is on
ensuring compatibility with Ethereum standards while enabling seamless contract workflows.
A minimal contract wrapper that embeds the fluentbase-evm interpreter into a smart-contract friendly entrypoint. It
handles two flows:

The primary entry points of the codebase are the **`main`** and **`deploy`** functions. These drive the core logic for
executing smart contracts and deploying them into the blockchain-like environment.
- deploy_entry: runs EVM init code and commits the resulting runtime bytecode to metadata.
- main_entry: executes previously deployed bytecode with the provided call data.

## **Deploy**
This crate does not implement EVM itself — it wires the host (SharedAPI) to the interpreter from crates/evm and applies
basic network rules relevant to deployment.

The **`deploy`** function is used to deploy smart contracts. It includes setting initial storage or balances depending
on the specific deployment requirements.
## Architecture

1. **Fetch Input**:
- Read input data (typically the smart contract's initialization bytecode or parameters).
- Interpreter: provided by fluentbase-evm (an interruptible, bytecode-compatible EVM engine).
- Host: provided by SharedAPI (I/O, fuel charging, metadata access). Calls, storage, logs, etc. are executed via
interruptions and resumed transparently by the VM.
- Metadata: contract-local storage used to persist code hash and raw bytecode.

2. **Validation**:
- Perform checks such as:
- EVM-specific limits like code size restrictions (**EIP-170**).
- Input validity or compliance with a protocol like rejecting bytecodes starting with `0xEF`.
## Entrypoints

3. **Execution**:
- Execute the bytecode using the EVM.
- If execution fails, terminate the deployment early.
- deploy_entry: executes init bytecode, enforces EIP-3541 (no 0xEF prefix) and EIP-170 (code size), charges CODEDEPOSIT,
then stores code hash (offset 0) and raw bytecode (offset 32) in metadata.
- main_entry: loads analyzed bytecode from metadata, runs the interpreter with call data, settles fuel delta, and writes
return data.

4. **Storage/State Updates**:
- If execution is successful:
- Store deployed bytecode.
- Record initial balances or other state data using the SDK.
Relevant functions in lib.rs:

## **Main**
- commit_evm_bytecode: persist code hash and raw bytecode in metadata.
- load_evm_bytecode: read code hash + bytes from metadata and return AnalyzedBytecode.
- handle_not_ok_result: charge final fuel delta, write output, and exit with Err/Panic for non-success.

The **`main`** function is the entry point for executing contract bytecode. It handles reading input data, managing gas,
and writing results back after execution.
## Bytecode lifecycle

1. **Contextual Setup**:
- Retrieve the gas limit via the SDK.
- Calculate the gas cost of the incoming transaction based on the input size.
1) Deployment (deploy_entry)
- Input: init bytecode (Bytes) from sdk.input().
- Run EthVM once; the output is the runtime bytecode.
- Validate: reject 0xEF prefix (EIP-3541) and limit size to EVM_MAX_CODE_SIZE (EIP-170).
- Charge CODEDEPOSIT = len(runtime) * gas::CODEDEPOSIT.
- Commit: write keccak256(runtime) to metadata at offset 0; write runtime bytes at offset 32.

2. **Gas Check**:
- If the required gas exceeds the available gas limit, the execution terminates with an **OutOfFuel** error.
2) Execution (main_entry)
- Load AnalyzedBytecode from metadata (code hash + byte array).
- Run EthVM with call data (sdk.bytes_input()).
- Settle fuel delta via ExecutionResult::chargeable_fuel_and_refund and write output.

3. **Execution**:
- Input data is read and processed.
- The function writes the processed data (in this case, identical to the input) back to the output.
## Gas/fuel model

---
- The interpreter tracks EVM gas; the host may charge “fuel”. fluentbase-evm keeps both in sync using FUEL_DENOM_RATE.
- This crate only settles the final delta at the end of each entrypoint via ExecutionResult::chargeable_fuel_and_refund.

P.S:
Tha EVM interpreter is based on modified revm's interpreter with replaced system calls and adjusted gas calculation
policy
## Host expectations (SharedAPI)

- metadata_write, metadata_copy, metadata_size for persisting bytecode and its hash.
- context() for addresses and limits; bytes_input()/input() for calldata and initcode.
- charge_fuel_manually and native_exit for accounting and termination.

## Usage

- Include this crate in contracts/* workspace.
- Call deploy_entry on creation, main_entry on calls. The entrypoint! macro at the bottom of lib.rs wires both.

## Notes

- The EVM specification and gas semantics are provided by fluentbase-evm (Prague by default). This crate only manages
the bytecode lifecycle and host boundary.
148 changes: 12 additions & 136 deletions contracts/evm/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,8 @@ use fluentbase_sdk::{
EVM_MAX_CODE_SIZE, KECCAK_EMPTY,
};

/// Commits EVM bytecode to persistent storage and updates the corresponding code hash.
///
/// This function performs the following operations:
/// 1. Write the provided bytecode (`evm_bytecode`) to preimage storage using the SDK, which returns
/// a hash of the preimage.
/// 2. Takes the resulting code hash and writes it to a predefined storage slot identified by
/// `EVM_CODE_HASH_SLOT`.
///
/// # Arguments
/// - `sdk`: A mutable reference to the SDK instance implementing the `SharedAPI` trait, which
/// provides the methods required for interactions with storage.
/// - `evm_bytecode`: A `Bytes` object containing the EVM bytecode to be stored.
/// Store EVM bytecode and its keccak256 hash in contract metadata.
/// Hash is written at offset 0, raw bytecode at offset 32.
pub(crate) fn commit_evm_bytecode<SDK: SharedAPI>(sdk: &mut SDK, evm_bytecode: Bytes) {
let contract_address = sdk.context().contract_address();
let evm_code_hash = keccak256(evm_bytecode.as_ref());
Expand All @@ -32,22 +22,8 @@ pub(crate) fn commit_evm_bytecode<SDK: SharedAPI>(sdk: &mut SDK, evm_bytecode: B
.unwrap();
}

/// Loads the EVM bytecode associated with the contract using the provided SDK.
///
/// This function retrieves the EVM bytecode for a contract from the state storage
/// using a delegated storage mechanism. The process involves fetching the contract's
/// bytecode address, locating the storage slot for its EVM code hash, and verifying
/// if the bytecode exists (i.e., it is not empty). If valid bytecode is found, it is loaded
/// and returned as a `Bytecode` object.
///
/// # Arguments
/// - `sdk`: A reference to an implementation of the `SharedAPI` trait that provides access to
/// storage, context, and pre-image retrieval methods required for handling contract data.
///
/// # Returns
/// An `Option<Bytecode>`.
/// - `Some(Bytecode)`: If a valid bytecode exists and is successfully retrieved.
/// - `None`: If the bytecode is empty or not present in the storage.
/// Load analyzed EVM bytecode from contract metadata.
/// Returns None if metadata is empty or code hash is zero/KECCAK_EMPTY.
pub(crate) fn load_evm_bytecode<SDK: SharedAPI>(sdk: &SDK) -> Option<AnalyzedBytecode> {
// we use bytecode address because contract can be called using DELEGATECALL
let bytecode_address = sdk.context().contract_bytecode_address();
Expand Down Expand Up @@ -76,26 +52,8 @@ pub(crate) fn load_evm_bytecode<SDK: SharedAPI>(sdk: &SDK) -> Option<AnalyzedByt
Some(analyzed_bytecode)
}

/// Handles non-OK results from the EVM interpreter.
///
/// This function performs the following:
/// 1. Synchronizes the remaining and refunded gas with the `SharedAPI` instance.
/// 2. Write the output of the interpreter result to the `SharedAPI` instance.
/// 3. If the result is a revert, immediately exits with a panic exit code.
/// 4. Determine the final exit code based on the `InstructionResult` value and exits accordingly.
///
/// ## Parameters:
/// - `sdk`: A mutable instance of a type implementing the `SharedAPI` trait to interface with the
/// environment.
/// - `result`: The `InterpreterResult` containing the gas usage, output, and result status.
///
/// ## Exit Codes:
/// - `ExitCode::Ok` (0) for successful instructions.
/// - `ExitCode::Panic` (-1) for revert cases.
/// - `ExitCode::Err` (-2) for any other error conditions.
///
/// By interpreting and mapping results appropriately, this function ensures
/// the correct handling and propagation of results from the EVM context.
/// Propagate a non-successful interpreter result to the host:
/// charge final fuel delta, write output, and exit with Err/Panic.
fn handle_not_ok_result<SDK: SharedAPI>(mut sdk: SDK, result: ExecutionResult) {
let (consumed_diff, refund_diff) = result.chargeable_fuel_and_refund();
sdk.charge_fuel_manually(consumed_diff, refund_diff);
Expand All @@ -107,60 +65,9 @@ fn handle_not_ok_result<SDK: SharedAPI>(mut sdk: SDK, result: ExecutionResult) {
});
}

/// Deploys an EVM smart contract using the provided bytecode input.
///
/// This function handles the deployment process for EVM-compatible smart contracts,
/// including executing the contract bytecode, ensuring compliance with EVM specifications,
/// and committing the deployed bytecode if the deployment is successful.
///
/// # Steps:
/// 1. **Fetch Input and Context**:
/// - Retrieves the input bytecode for contract deployment using the SDK.
/// - Obtains the gas limit for the deployment from the context.
///
/// 2. **Execute EVM Bytecode**:
/// - Executes the provided bytecode via the `exec_evm_bytecode` function.
/// - If the execution fails, the non-success result is processed by `handle_not_ok_result` and
/// the function terminates early.
///
/// 3. **EIP-3541 (Disallow Code Starting with 0xEF)**:
/// - Checks if the executed contract output begins with the byte `0xEF` (non-standard prefix).
/// - If so, exits with the error code `InstructionResult::CreateContractStartingWithEF`.
///
/// 4. **EIP-170 (Code Size Limit)**:
/// - Verifies if the length of the generated bytecode exceeds 24KB, specified by
/// `MAX_CODE_SIZE`.
/// - Exits with `InstructionResult::CreateContractSizeLimit` error if the limit is exceeded.
///
/// 5. **Gas Cost for Code Deposit**:
/// - Calculates the gas cost for storing the deployed bytecode based on `CODEDEPOSIT` (a
/// predefined gas constant) and the bytecode size.
/// - If the cost cannot be recorded (due to insufficient gas), charge the maximum fuel and exits
/// accordingly.
///
/// 6. **Synchronize Gas Information**:
/// - Updates the EVM gas state (remaining and refunded gas) in the SDK to keep it synchronized
/// with the deployment process.
///
/// 7. **Commit Bytecode**:
/// - Saves the deployed contract bytecode to persistent storage using `commit_evm_bytecode`.
///
/// This function ensures compatibility with fundamental Ethereum standards and handles
/// gas calculations, runtime checks, and storage updates as part of the deployment flow.
///
/// # Parameters
/// - `sdk`: A mutable reference to the SDK instance that implements the `SharedAPI` trait.
///
/// # Errors
/// The function can exit under various error conditions:
/// - Non-successful EVM bytecode execution.
/// - Code starting with 0xEF (EIP-3541 violation).
/// - Code exceeding the size limit (EIP-170 violation).
/// - Insufficient gas for code deposit.
///
/// # Gas Mechanics
/// - Gas is deducted during the bytecode execution and additional deployment steps.
/// - Compatibility with EVM gas mechanisms is maintained to ensure Ethereum-like behavior.
/// Deploy entry for EVM contracts.
/// Runs init bytecode, enforces EIP-3541 and EIP-170, charges CODEDEPOSIT gas,
/// then commits the resulting runtime bytecode to metadata.
pub fn deploy_entry<SDK: SharedAPI>(mut sdk: SDK) {
let input: Bytes = sdk.input().into();
let analyzed_bytecode = AnalyzedBytecode::new(input, B256::ZERO);
Expand Down Expand Up @@ -190,40 +97,9 @@ pub fn deploy_entry<SDK: SharedAPI>(mut sdk: SDK) {
commit_evm_bytecode(&mut sdk, result.output);
}

/// The main entry point function of the application that processes EVM-based contract bytecode.
///
/// This function interacts with an environment (`SharedAPI`) to execute EVM bytecode
/// with input data under a specified gas limit.
/// The results are then processed, handled, and written back to the environment.
///
/// ### Key Steps:
/// 1. Load the EVM bytecode for the specific contract using `load_evm_bytecode`.
/// - If the bytecode is not available (e.g., invalid or absent), the function terminates early.
/// 2. Retrieve the input data provided by the environment via `sdk.input()`.
/// 3. Fetch the gas limit for the contract execution from the environment's `contract_gas_limit`.
/// 4. Execute EVM bytecode with `exec_evm_bytecode`, passing:
/// - Loaded bytecode
/// - Input data
/// - Gas limit
/// 5. Check the result of the execution:
/// - If unsuccessful, handle the failure gracefully using `handle_not_ok_result`.
/// - If successful, sync gas usage (`remaining` and `refunded` gas) via `sdk.sync_evm_gas`, and
/// write the execution output back with `sdk.write`.
///
/// ### Parameters:
/// - `sdk`: An instance implementing `SharedAPI` to provide runtime functionality, such as
/// input/output handling, gas synchronization, and context details.
///
/// ### Detailed Behavior:
/// This function ensures that gas usage and execution outputs are synchronously managed
/// between the SDK environment and the virtual machine.
/// The error-handling mechanism ensures
/// that non-successful results terminate the function with appropriate actions, such as panic
/// (`revert`) or error logging.
///
/// ### Assumptions:
/// - The SDK instance conforms to the `SharedAPI` interface.
/// - Bytecode is preloaded and valid for the specific context where the function is executed.
/// Main entry for executing deployed EVM bytecode.
/// Loads analyzed code from metadata, runs EthVM with call input, settles fuel,
/// and writes the returned data.
pub fn main_entry<SDK: SharedAPI>(mut sdk: SDK) {
let Some(analyzed_bytecode) = load_evm_bytecode(&sdk) else {
return;
Expand Down
10 changes: 10 additions & 0 deletions contracts/identity/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# IDENTITY

Identity precompile wrapper (0x04). Returns the input unchanged, following EVM gas rules.

- Entrypoint: main_entry. Reads input, executes revm_precompile::identity::run, syncs gas, writes output.
- Input: arbitrary bytes.
- Output: identical bytes.
- Gas: EVM-compatible (base + word copy) via sdk.sync_evm_gas.

Use this for efficient memory copy within the precompile address space.
Loading
Loading