Skip to content
Open
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
6 changes: 6 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ jobs:
just semver-lock-no-build
git diff --exit-code snapshots/semver-lock.json

- name: Install Rust
uses: dtolnay/rust-toolchain@stable

- name: Check Rust bindings
run: just bindings-check

- name: Run Forge tests
run: just test
id: test
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# Artifacts and Cache
artifacts
!bindings/rust/artifacts/
forge-artifacts
target
Cargo.lock
cache
broadcast
kout-proofs
Expand Down
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion bindings/go.mod → bindings/go/go.mod
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module github.com/base/contracts/bindings
module github.com/base/contracts/bindings/go

go 1.23.0

Expand Down
File renamed without changes.
8 changes: 8 additions & 0 deletions bindings/rust/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[package]
name = "base-contracts-bindings"
version = "0.1.0"
edition = "2021"

[dependencies]
alloy-contract = "1.5.0"
alloy-sol-types = { version = "1.5.0", features = ["json"] }
118 changes: 118 additions & 0 deletions bindings/rust/artifacts/FlashblockIndex.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
{
"abi": [
{
"type": "constructor",
"inputs": [
{
"name": "builder",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "nonpayable"
},
{
"type": "fallback",
"stateMutability": "nonpayable"
},
{
"type": "function",
"name": "BUILDER",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "get",
"inputs": [],
"outputs": [
{
"name": "flashblockIndex",
"type": "uint8",
"internalType": "uint8"
},
{
"name": "blockNumber",
"type": "uint48",
"internalType": "uint48"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "initialize",
"inputs": [],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"type": "function",
"name": "version",
"inputs": [],
"outputs": [
{
"name": "",
"type": "string",
"internalType": "string"
}
],
"stateMutability": "view"
},
{
"type": "event",
"name": "FlashblockIndexUpdated",
"inputs": [
{
"name": "flashblockIndex",
"type": "uint8",
"indexed": true,
"internalType": "uint8"
},
{
"name": "blockNumber",
"type": "uint48",
"indexed": true,
"internalType": "uint48"
}
],
"anonymous": false
},
{
"type": "event",
"name": "Initialized",
"inputs": [
{
"name": "version",
"type": "uint8",
"indexed": false,
"internalType": "uint8"
}
],
"anonymous": false
},
{
"type": "error",
"name": "InvalidCalldata",
"inputs": []
},
{
"type": "error",
"name": "OnlyBuilder",
"inputs": []
}
],
"bytecode": {
"object": "0x60a060405234801561001057600080fd5b506040516105dc3803806105dc83398101604081905261002f9161010a565b6001600160a01b03811660805261004461004a565b5061013a565b600054610100900460ff16156100b65760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff9081161015610108576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b60006020828403121561011c57600080fd5b81516001600160a01b038116811461013357600080fd5b9392505050565b60805161048161015b60003960008181606401526101fd01526104816000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c806354fd4d50146101745780636d4ce63c146101c65780638129fc1c146101ee578063ecfd1b63146101f8575b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146100bb576040517f357a555d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600136146100f5576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000366000818110610109576101096103d2565b9091013560f81c43600881901b66ffffffffffff00169190911760015565ffffffffffff1690506000368181610141576101416103d2565b60405192013560f81c917f9e31f0bef6b07087c9e7d21830c330cc2d87343d2915024f0a0f832f45cf25779150600090a3005b6101b06040518060400160405280600581526020017f312e302e3000000000000000000000000000000000000000000000000000000081525081565b6040516101bd9190610401565b60405180910390f35b600154600881901c6040805160ff909316835265ffffffffffff9091166020830152016101bd565b6101f6610244565b005b61021f7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101bd565b600054610100900460ff16158080156102645750600054600160ff909116105b8061027e5750303b15801561027e575060005460ff166001145b61030e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840160405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055801561036c57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b80156103cf57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208083528351808285015260005b8181101561042e57858101830151858201604001528201610412565b81811115610440576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01692909201604001939250505056fea164736f6c634300080f000a"
},
"deployedBytecode": {
"object": "0x608060405234801561001057600080fd5b506004361061004c5760003560e01c806354fd4d50146101745780636d4ce63c146101c65780638129fc1c146101ee578063ecfd1b63146101f8575b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146100bb576040517f357a555d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600136146100f5576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000366000818110610109576101096103d2565b9091013560f81c43600881901b66ffffffffffff00169190911760015565ffffffffffff1690506000368181610141576101416103d2565b60405192013560f81c917f9e31f0bef6b07087c9e7d21830c330cc2d87343d2915024f0a0f832f45cf25779150600090a3005b6101b06040518060400160405280600581526020017f312e302e3000000000000000000000000000000000000000000000000000000081525081565b6040516101bd9190610401565b60405180910390f35b600154600881901c6040805160ff909316835265ffffffffffff9091166020830152016101bd565b6101f6610244565b005b61021f7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101bd565b600054610100900460ff16158080156102645750600054600160ff909116105b8061027e5750303b15801561027e575060005460ff166001145b61030e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840160405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055801561036c57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b80156103cf57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208083528351808285015260005b8181101561042e57858101830151858201604001528201610412565b81811115610440576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01692909201604001939250505056fea164736f6c634300080f000a"
}
}
10 changes: 10 additions & 0 deletions bindings/rust/src/l2/flashblock_index.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use alloy_sol_types::sol;

sol!(
#[sol(rpc, abi)]
FlashblockIndex,
concat!(
env!("CARGO_MANIFEST_DIR"),
"/artifacts/FlashblockIndex.json"
)
);
2 changes: 2 additions & 0 deletions bindings/rust/src/l2/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
mod flashblock_index;
pub use flashblock_index::FlashblockIndex;
1 change: 1 addition & 0 deletions bindings/rust/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod l2;
84 changes: 83 additions & 1 deletion justfile
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,72 @@ snapshots-no-build: snapshots-abi-storage-no-build semver-lock-no-build
snapshots: build-source snapshots-no-build



########################################################
# BINDINGS #
########################################################

# Adds a new Rust binding for a Solidity contract.
# Usage: just bindings-add src/L2/FlashblockIndex.sol
bindings-add SOL_PATH: build-source
#!/bin/bash
set -euo pipefail

sol_path="{{SOL_PATH}}"

# Extract contract name (e.g. FlashblockIndex from src/L2/FlashblockIndex.sol)
contract=$(basename "$sol_path" .sol)

# Extract module (e.g. l2 from src/L2/FlashblockIndex.sol)
module=$(echo "$sol_path" | sed 's|^src/||' | xargs dirname | tr '[:upper:]' '[:lower:]')

# Convert PascalCase to snake_case by inserting _ at lower|upper and acronym|word boundaries
snake=$(echo "$contract" | sed -E 's/([a-z0-9])([A-Z])/\1_\2/g' | sed -E 's/([A-Z]+)([A-Z][a-z])/\1_\2/g' | tr '[:upper:]' '[:lower:]')

rust_dir="bindings/rust/src/${module}"
rust_file="${rust_dir}/${snake}.rs"
mod_file="${rust_dir}/mod.rs"
artifact="bindings/rust/artifacts/${contract}.json"

# 1. Strip artifact
jq '{abi, bytecode: {object: .bytecode.object}, deployedBytecode: {object: .deployedBytecode.object}}' \
"forge-artifacts/${contract}.sol/${contract}.json" > "$artifact"

# 2. Create module directory if needed
mkdir -p "$rust_dir"

# 3. Create .rs file
cat > "$rust_file" << EOF
use alloy_sol_types::sol;

sol!(
#[sol(rpc, abi)]
${contract},
concat!(
env!("CARGO_MANIFEST_DIR"),
"/artifacts/${contract}.json"
)
);
EOF

# 4. Add to mod.rs (skip if already present)
if ! grep -q "mod ${snake};" "$mod_file" 2>/dev/null; then
echo "" >> "$mod_file"
echo "mod ${snake};" >> "$mod_file"
echo "pub use ${snake}::${contract};" >> "$mod_file"
fi

# 5. Add module to lib.rs (skip if already present)
if ! grep -q "pub mod ${module};" "bindings/rust/src/lib.rs" 2>/dev/null; then
echo "pub mod ${module};" >> "bindings/rust/src/lib.rs"
fi

# 6. Format generated code
cd bindings/rust && cargo fmt

echo "Added binding: ${contract} -> ${rust_file}"


########################################################
# CHECKS #
########################################################
Expand All @@ -232,6 +298,21 @@ snapshots-check-no-build: snapshots-no-build
# Checks if the snapshots are up to date.
snapshots-check: build snapshots-check-no-build

# Checks that the Rust bindings crate compiles.
bindings-check:
cd bindings/rust && cargo check

# Checks that committed Rust binding artifacts match forge-artifacts.
bindings-artifacts-check-no-build:
#!/bin/bash
set -euo pipefail
for src in bindings/rust/artifacts/*.json; do
name=$(basename "$src" .json)
jq '{abi, bytecode: {object: .bytecode.object}, deployedBytecode: {object: .deployedBytecode.object}}' \
"forge-artifacts/${name}.sol/${name}.json" > "$src"
done
git diff --exit-code bindings/rust/artifacts/

# Checks interface correctness without building.
interfaces-check-no-build:
go run ./scripts/checks/interfaces
Expand Down Expand Up @@ -338,7 +419,8 @@ check:
validate-spacers-no-build \
reinitializer-check-no-build \
interfaces-check-no-build \
lint-forge-tests-check-no-build
lint-forge-tests-check-no-build \
bindings-artifacts-check-no-build

########################################################
# DEV TOOLS #
Expand Down
4 changes: 4 additions & 0 deletions snapshots/semver-lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@
"initCodeHash": "0xdaae3903628f760e36da47c8f8d75d20962d1811fb5129cb09eb01803e67c095",
"sourceCodeHash": "0x95dd8da08e907fa398c98710bb12fda9fb50d9688c5d2144fd9a424c99e672c5"
},
"src/L2/FlashblockIndex.sol:FlashblockIndex": {
"initCodeHash": "0x16c2bc1f2e6526eac40de3636464f8f3899f087773cb63106f5ebea38ea2160e",
"sourceCodeHash": "0x71c264e6ef9cbcd9f82dcbddcda6ad8b253ab23b10b317caead4a0d6efa94b2c"
},
"src/L2/GasPriceOracle.sol:GasPriceOracle": {
"initCodeHash": "0xf72c23d9c3775afd7b645fde429d09800622d329116feb5ff9829634655123ca",
"sourceCodeHash": "0xb4d1bf3669ba87bbeaf4373145c7e1490478c4a05ba4838a524aa6f0ce7348a6"
Expand Down
Loading