├── .editorconfig ├── .github ├── actions-rs │ └── grcov.yml ├── dependabot.yml └── workflows │ └── ci.yml ├── .gitignore ├── .gitmodules ├── .rustfmt.toml ├── CONTRIBUTING.md ├── Cargo.lock ├── Cargo.toml ├── Makefile ├── README.md ├── codecov.yml ├── contracts ├── blake2f │ ├── Cargo.toml │ ├── build.rs │ └── src │ │ ├── lib.rs │ │ └── main.rs ├── bls12381 │ ├── Cargo.toml │ ├── build.rs │ └── src │ │ ├── lib.rs │ │ └── main.rs ├── bn256 │ ├── Cargo.toml │ ├── build.rs │ └── src │ │ ├── lib.rs │ │ └── main.rs ├── ecrecover │ ├── Cargo.toml │ ├── build.rs │ └── src │ │ ├── lib.rs │ │ └── main.rs ├── erc20 │ ├── Cargo.toml │ ├── build.rs │ └── src │ │ ├── lib.rs │ │ └── main.rs ├── evm │ ├── Cargo.toml │ ├── README.md │ ├── build.rs │ └── src │ │ ├── lib.rs │ │ └── main.rs ├── fairblock │ ├── Cargo.toml │ ├── README.md │ ├── build.rs │ ├── fallback.wasm │ ├── go.mod │ ├── go.sum │ ├── lib.rs │ └── main.go ├── identity │ ├── Cargo.toml │ ├── build.rs │ └── src │ │ ├── lib.rs │ │ └── main.rs ├── kzg │ ├── Cargo.toml │ ├── build.rs │ └── src │ │ ├── lib.rs │ │ └── main.rs ├── modexp │ ├── Cargo.toml │ ├── build.rs │ └── src │ │ ├── lib.rs │ │ └── main.rs ├── multicall │ ├── Cargo.toml │ ├── build.rs │ └── src │ │ ├── lib.rs │ │ └── main.rs ├── nitro │ ├── Cargo.toml │ ├── attestation-example.hex │ ├── build.rs │ └── src │ │ ├── attestation.rs │ │ ├── lib.rs │ │ ├── main.rs │ │ └── nitro.pem ├── oauth2 │ ├── Cargo.toml │ ├── build.rs │ └── src │ │ ├── lib.rs │ │ └── main.rs ├── ripemd160 │ ├── Cargo.toml │ ├── build.rs │ └── src │ │ ├── lib.rs │ │ └── main.rs ├── secp256r1 │ ├── Cargo.toml │ ├── build.rs │ └── src │ │ ├── lib.rs │ │ └── main.rs ├── sha256 │ ├── Cargo.toml │ ├── build.rs │ └── src │ │ ├── lib.rs │ │ └── main.rs └── webauthn │ ├── Cargo.toml │ ├── README.md │ ├── build.rs │ └── src │ ├── lib.rs │ ├── main.rs │ └── webauthn.rs ├── crates ├── build │ ├── Cargo.toml │ └── src │ │ ├── config.rs │ │ └── lib.rs ├── codec-derive │ ├── Cargo.toml │ └── src │ │ ├── lib.rs │ │ └── snapshots │ │ ├── fluentbase_codec_derive__tests__empty_struct.snap │ │ ├── fluentbase_codec_derive__tests__generic_struct.snap │ │ ├── fluentbase_codec_derive__tests__simple_struct.snap │ │ └── fluentbase_codec_derive__tests__single_field_struct.snap ├── codec │ ├── Cargo.toml │ ├── README.md │ ├── src │ │ ├── bytes_codec.rs │ │ ├── empty.rs │ │ ├── encoder.rs │ │ ├── error.rs │ │ ├── evm.rs │ │ ├── hash.rs │ │ ├── lib.rs │ │ ├── primitive.rs │ │ ├── test_utils.rs │ │ ├── tests.rs │ │ ├── tuple.rs │ │ └── vec.rs │ └── tests │ │ ├── common │ │ └── mod.rs │ │ ├── lib.rs │ │ └── roundtrip │ │ ├── mod.rs │ │ ├── structs.rs │ │ └── tuples.rs ├── evm │ ├── Cargo.toml │ └── src │ │ ├── bytecode.rs │ │ ├── evm.rs │ │ ├── evm │ │ ├── arithmetic.rs │ │ ├── bitwise.rs │ │ ├── context.rs │ │ ├── contract.rs │ │ ├── control.rs │ │ ├── host.rs │ │ ├── i256.rs │ │ ├── memory.rs │ │ ├── stack.rs │ │ └── system.rs │ │ ├── gas.rs │ │ ├── lib.rs │ │ ├── macros.rs │ │ ├── memory.rs │ │ ├── result.rs │ │ ├── stack.rs │ │ └── utils.rs ├── genesis │ ├── Cargo.toml │ ├── assets │ │ └── genesis-devnet-v0.1.0-dev.10.json │ ├── build.rs │ └── src │ │ └── lib.rs ├── runtime │ ├── Cargo.toml │ └── src │ │ ├── context.rs │ │ ├── context_wrapper.rs │ │ ├── instruction.rs │ │ ├── instruction │ │ ├── charge_fuel.rs │ │ ├── charge_fuel_manually.rs │ │ ├── debug_log.rs │ │ ├── ed_add.rs │ │ ├── ed_decompress.rs │ │ ├── exec.rs │ │ ├── exit.rs │ │ ├── forward_output.rs │ │ ├── fp2_addsub.rs │ │ ├── fp2_mul.rs │ │ ├── fp_op.rs │ │ ├── fuel.rs │ │ ├── input_size.rs │ │ ├── keccak256.rs │ │ ├── keccak256_permute.rs │ │ ├── output_size.rs │ │ ├── preimage_copy.rs │ │ ├── preimage_size.rs │ │ ├── read.rs │ │ ├── read_output.rs │ │ ├── resume.rs │ │ ├── secp256k1_recover.rs │ │ ├── sha256_compress.rs │ │ ├── sha256_extend.rs │ │ ├── state.rs │ │ ├── uint256_mul.rs │ │ ├── weierstrass_add.rs │ │ ├── weierstrass_decompress.rs │ │ ├── weierstrass_double.rs │ │ └── write.rs │ │ ├── lib.rs │ │ ├── runtime.rs │ │ ├── storage.rs │ │ ├── tests.rs │ │ ├── utils.rs │ │ └── wasmtime.rs ├── sdk-derive │ ├── Cargo.toml │ ├── derive-core │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── abi │ │ │ ├── contract.rs │ │ │ ├── error.rs │ │ │ ├── function.rs │ │ │ ├── mod.rs │ │ │ ├── parameter.rs │ │ │ └── types │ │ │ │ ├── conversion │ │ │ │ ├── mod.rs │ │ │ │ ├── rust_to_sol.rs │ │ │ │ ├── sol_to_rust.rs │ │ │ │ └── syn_sol_to_internal.rs │ │ │ │ ├── mod.rs │ │ │ │ └── sol.rs │ │ │ ├── attr │ │ │ ├── artifacts_dir.rs │ │ │ ├── function_id.rs │ │ │ ├── mod.rs │ │ │ └── mode.rs │ │ │ ├── client.rs │ │ │ ├── codec.rs │ │ │ ├── lib.rs │ │ │ ├── method.rs │ │ │ ├── router.rs │ │ │ ├── signature.rs │ │ │ ├── snapshots │ │ │ ├── fluentbase_sdk_derive_core__client__tests__generate_client.snap │ │ │ ├── fluentbase_sdk_derive_core__codec__tests__complex_function.snap │ │ │ ├── fluentbase_sdk_derive_core__codec__tests__empty_return.snap │ │ │ ├── fluentbase_sdk_derive_core__codec__tests__multiple_returns.snap │ │ │ ├── fluentbase_sdk_derive_core__codec__tests__no_params.snap │ │ │ ├── fluentbase_sdk_derive_core__codec__tests__simple_transfer_fluent.snap │ │ │ ├── fluentbase_sdk_derive_core__codec__tests__simple_transfer_solidity.snap │ │ │ ├── fluentbase_sdk_derive_core__codec__tests__single_dynamic_param.snap │ │ │ ├── fluentbase_sdk_derive_core__router__tests__trait_router_generation.snap │ │ │ ├── fluentbase_sdk_derive_core__sol_input__tests__sol_struct_to_rust_tokens.snap │ │ │ ├── fluentbase_sdk_derive_core__sol_input__tests__sol_to_rust_trait_nested_struct.snap │ │ │ ├── fluentbase_sdk_derive_core__sol_input__tests__sol_to_sol_client_nested_struct.snap │ │ │ ├── fluentbase_sdk_derive_core__storage__tests__array_storage.snap │ │ │ ├── fluentbase_sdk_derive_core__storage__tests__direct_storage_types.snap │ │ │ ├── fluentbase_sdk_derive_core__storage__tests__fixed_bytes_storage.snap │ │ │ ├── fluentbase_sdk_derive_core__storage__tests__mapping_storage.snap │ │ │ └── fluentbase_sdk_derive_core__storage__tests__primitive_storage.snap │ │ │ ├── sol_input.rs │ │ │ ├── storage.rs │ │ │ └── utils │ │ │ ├── mod.rs │ │ │ └── selector.rs │ ├── docs │ │ ├── client.md │ │ ├── router.md │ │ ├── solidity_client.md │ │ ├── solidity_trait.md │ │ ├── storage.md │ │ └── type_conversion.md │ ├── src │ │ ├── contract.rs │ │ ├── lib.rs │ │ └── utils.rs │ └── tests │ │ ├── ui.rs │ │ └── ui │ │ └── router │ │ ├── fail │ │ ├── function_id_type_mismatch.rs │ │ ├── function_id_type_mismatch.stderr │ │ ├── incorrect_fallback_signature.rs │ │ ├── incorrect_fallback_signature.stderr │ │ ├── invalid_selector_validation.rs │ │ ├── invalid_selector_validation.stderr │ │ ├── no_public_methods_direct_impl.rs │ │ ├── no_public_methods_direct_impl.stderr │ │ ├── without_mode.rs │ │ └── without_mode.stderr │ │ └── pass │ │ ├── direct_impl.rs │ │ └── trait_impl.rs ├── sdk-testing │ ├── Cargo.toml │ └── src │ │ ├── evm.rs │ │ ├── host.rs │ │ └── lib.rs ├── sdk │ ├── Cargo.toml │ └── src │ │ ├── allocator.rs │ │ ├── bindings.rs │ │ ├── constructor.rs │ │ ├── entrypoint.rs │ │ ├── leb128.rs │ │ ├── lib.rs │ │ ├── macros.rs │ │ ├── panic.rs │ │ ├── rwasm.rs │ │ ├── shared.rs │ │ ├── shared │ │ └── context.rs │ │ └── storage.rs └── types │ ├── Cargo.toml │ └── src │ ├── address.rs │ ├── bytecode_type.rs │ ├── context.rs │ ├── context │ ├── v1.rs │ └── v1 │ │ ├── block_context.rs │ │ ├── contract_context.rs │ │ └── tx_context.rs │ ├── evm.rs │ ├── exit_code.rs │ ├── fuel_procedures.rs │ ├── genesis.rs │ ├── lib.rs │ ├── linker.rs │ ├── native_api.rs │ ├── preimage.rs │ ├── rwasm.rs │ ├── sdk.rs │ ├── sys_func_idx.rs │ └── syscall.rs ├── e2e ├── .gitignore ├── Cargo.toml ├── Makefile ├── assets │ ├── CallWasm.bin │ ├── CallWasm.sol │ ├── CertManager.bin │ ├── CertManager.sol │ ├── ContractDeployer.bin │ ├── ContractDeployer.sol │ ├── DelegateCaller.bin │ ├── DelegateCaller.sol │ ├── ERC20.bin │ ├── ERC20.sol │ ├── HelloWorld.bin │ ├── HelloWorld.sol │ ├── Multicall.bin │ ├── Multicall.sol │ ├── NitroValidator.bin │ ├── NitroValidator.sol │ ├── Router.bin │ ├── Router.sol │ ├── Storage.bin │ └── Storage.sol └── src │ ├── bench │ ├── bench.md │ ├── erc20.rs │ ├── greeting.rs │ ├── mod.rs │ └── multicall.rs │ ├── bridge.rs │ ├── builtins.rs │ ├── constructor.rs │ ├── deployer.rs │ ├── evm.rs │ ├── gas.rs │ ├── lib.rs │ ├── multicall.rs │ ├── nitro.rs │ ├── router.rs │ ├── stateless.rs │ └── wasm.rs ├── examples ├── README.md ├── abi-solidity │ ├── Cargo.toml │ ├── build.rs │ └── src │ │ ├── lib.rs │ │ └── main.rs ├── checkmate │ ├── Cargo.toml │ ├── README.md │ ├── build.rs │ └── src │ │ ├── lib.rs │ │ └── main.rs ├── client-solidity │ ├── Cargo.toml │ ├── README.md │ ├── build.rs │ └── src │ │ ├── lib.rs │ │ └── main.rs ├── constructor-params │ ├── Cargo.toml │ ├── build.rs │ └── src │ │ ├── lib.rs │ │ └── main.rs ├── erc20 │ ├── Cargo.toml │ ├── README.md │ ├── build.rs │ └── src │ │ ├── lib.rs │ │ └── main.rs ├── greeting │ ├── Cargo.toml │ ├── README.md │ ├── build.rs │ └── src │ │ ├── lib.rs │ │ └── main.rs ├── json │ ├── Cargo.toml │ ├── build.rs │ └── src │ │ ├── lib.rs │ │ └── main.rs ├── keccak │ ├── Cargo.toml │ ├── build.rs │ └── src │ │ ├── lib.rs │ │ └── main.rs ├── panic │ ├── Cargo.toml │ ├── README.md │ ├── build.rs │ └── src │ │ ├── lib.rs │ │ └── main.rs ├── router-solidity │ ├── Cargo.toml │ ├── README.md │ ├── build.rs │ └── src │ │ ├── lib.rs │ │ └── main.rs ├── rwasm │ ├── Cargo.toml │ ├── README.md │ ├── build.rs │ └── src │ │ ├── lib.rs │ │ └── main.rs ├── secp256k1 │ ├── Cargo.toml │ ├── README.md │ ├── build.rs │ └── src │ │ ├── lib.rs │ │ └── main.rs ├── simple-storage │ ├── Cargo.toml │ ├── build.rs │ └── src │ │ ├── lib.rs │ │ └── main.rs ├── storage │ ├── Cargo.toml │ ├── README.md │ ├── build.rs │ └── src │ │ ├── lib.rs │ │ └── main.rs └── tiny-keccak │ ├── Cargo.toml │ ├── README.md │ ├── build.rs │ └── src │ ├── lib.rs │ └── main.rs └── rust-toolchain /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | [*] 3 | indent_style=space 4 | indent_size = 4 5 | end_of_line=lf 6 | charset=utf-8 7 | trim_trailing_whitespace=true 8 | max_line_length=120 9 | insert_final_newline=true 10 | -------------------------------------------------------------------------------- /.github/actions-rs/grcov.yml: -------------------------------------------------------------------------------- 1 | output-type: lcov 2 | output-file: ./lcov.info -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: github-actions 4 | directory: '/' 5 | schedule: 6 | interval: daily 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | /target/ 3 | **/*.rs.bk 4 | crates/rwasm/Cargo.lock 5 | crates/rwasm/spec/target 6 | 7 | **/fuzz/corpus/ 8 | **/fuzz/target/ 9 | **/fuzz/artifacts/ 10 | 11 | /.idea 12 | .vscode 13 | .DS_Store 14 | libzktrie.so 15 | .wake 16 | 17 | /tmp/* 18 | !/tmp/.gitkeep 19 | 20 | # exclude all wat, wasm and genesis files 21 | *.wat 22 | contracts/**/lib.wasm 23 | examples/**/lib.wasm 24 | 25 | revm/e2e/Cargo.lock 26 | revm/e2e/tests 27 | 28 | genesis-devnet.json 29 | node_modules 30 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "revm"] 2 | path = revm 3 | url = https://github.com/fluentlabs-xyz/revm-rwasm.git 4 | [submodule "crates/rwasm/e2e/testsuite"] 5 | path = crates/rwasm/e2e/testsuite 6 | url = https://github.com/fluentlabs-xyz/testsuite-rwasm.git 7 | -------------------------------------------------------------------------------- /.rustfmt.toml: -------------------------------------------------------------------------------- 1 | edition = "2021" 2 | group_imports = "One" 3 | ignore = ["revm/*"] 4 | imports_granularity = "Crate" 5 | imports_layout = "HorizontalVertical" 6 | 7 | comment_width = 100 8 | max_width = 100 9 | newline_style = "Unix" 10 | normalize_comments = false 11 | reorder_imports = true 12 | unstable_features = true 13 | wrap_comments = true 14 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: build 2 | 3 | .PHONY: build 4 | build: 5 | # build examples & contracts by triggering "build.rs" 6 | cargo check --lib #--exclude fluentbase-genesis --workspace --lib 7 | # build genesis files 8 | #cd crates/genesis && $(MAKE) # build genesis 9 | 10 | .PHONY: examples 11 | examples: 12 | cd examples && $(MAKE) 13 | 14 | .PHONY: clean 15 | clean: 16 | if [ "$(SKIP_EXAMPLES)" = "n" ]; then cd examples && $(MAKE) clean; fi 17 | cargo clean 18 | 19 | .PHONY: test 20 | test: 21 | cargo test --no-fail-fast -q -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | ignore: 2 | - "crates/build" # build crate 3 | - "crates/rwasm/e2e" # rwasm e2e testing suite 4 | - "e2e" # e2e tests for runtime 5 | - "examples" # examples 6 | - "revm/e2e" # revm e2e testing suite 7 | -------------------------------------------------------------------------------- /contracts/blake2f/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fluentbase-contracts-blake2f" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | fluentbase-sdk = { workspace = true } 8 | revm-precompile = { workspace = true } 9 | 10 | [dev-dependencies] 11 | fluentbase-sdk-testing = { workspace = true } 12 | 13 | [build-dependencies] 14 | fluentbase-build = { workspace = true } 15 | fluentbase-sdk = { workspace = true } 16 | revm-precompile = { workspace = true } 17 | 18 | [features] 19 | default = ["std"] 20 | std = ["fluentbase-sdk/std", "revm-precompile/std"] 21 | -------------------------------------------------------------------------------- /contracts/blake2f/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | fluentbase_build::build_default_genesis_contract() 3 | } 4 | -------------------------------------------------------------------------------- /contracts/blake2f/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(target_arch = "wasm32"))] 2 | include!(concat!(env!("OUT_DIR"), "/build_output.rs")); 3 | -------------------------------------------------------------------------------- /contracts/bls12381/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fluentbase-contracts-bls12381" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | fluentbase-sdk = { workspace = true } 8 | revm-precompile = { workspace = true, features = ["blst"] } 9 | 10 | [dev-dependencies] 11 | fluentbase-sdk-testing = { workspace = true } 12 | 13 | [build-dependencies] 14 | fluentbase-build = { workspace = true } 15 | fluentbase-sdk = { workspace = true } 16 | revm-precompile = { workspace = true, features = ["blst"] } 17 | 18 | [features] 19 | default = ["std"] 20 | std = ["fluentbase-sdk/std", "revm-precompile/std"] 21 | -------------------------------------------------------------------------------- /contracts/bls12381/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | fluentbase_build::build_default_genesis_contract() 3 | } 4 | -------------------------------------------------------------------------------- /contracts/bls12381/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(target_arch = "wasm32"))] 2 | include!(concat!(env!("OUT_DIR"), "/build_output.rs")); 3 | -------------------------------------------------------------------------------- /contracts/bn256/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fluentbase-contracts-bn256" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | fluentbase-sdk = { workspace = true } 8 | revm-precompile = { workspace = true } 9 | 10 | [dev-dependencies] 11 | fluentbase-sdk-testing = { workspace = true } 12 | 13 | [build-dependencies] 14 | fluentbase-build = { workspace = true } 15 | fluentbase-sdk = { workspace = true } 16 | revm-precompile = { workspace = true } 17 | 18 | [features] 19 | default = ["std"] 20 | std = ["fluentbase-sdk/std", "revm-precompile/std"] 21 | -------------------------------------------------------------------------------- /contracts/bn256/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | fluentbase_build::build_default_genesis_contract() 3 | } 4 | -------------------------------------------------------------------------------- /contracts/bn256/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(target_arch = "wasm32"))] 2 | include!(concat!(env!("OUT_DIR"), "/build_output.rs")); 3 | -------------------------------------------------------------------------------- /contracts/ecrecover/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fluentbase-contracts-ecrecover" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | fluentbase-sdk = { workspace = true } 8 | revm-precompile = { workspace = true } 9 | 10 | [dev-dependencies] 11 | fluentbase-sdk-testing = { workspace = true } 12 | 13 | [build-dependencies] 14 | fluentbase-build = { workspace = true } 15 | fluentbase-sdk = { workspace = true } 16 | revm-precompile = { workspace = true } 17 | 18 | [features] 19 | default = ["std"] 20 | std = ["fluentbase-sdk/std", "revm-precompile/std"] 21 | -------------------------------------------------------------------------------- /contracts/ecrecover/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | fluentbase_build::build_default_genesis_contract() 3 | } 4 | -------------------------------------------------------------------------------- /contracts/ecrecover/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(target_arch = "wasm32"))] 2 | include!(concat!(env!("OUT_DIR"), "/build_output.rs")); 3 | -------------------------------------------------------------------------------- /contracts/erc20/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fluentbase-contracts-erc20" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | fluentbase-sdk = { workspace = true } 8 | 9 | [dev-dependencies] 10 | fluentbase-sdk-testing = { workspace = true } 11 | 12 | [build-dependencies] 13 | fluentbase-build = { workspace = true } 14 | fluentbase-sdk = { workspace = true } 15 | 16 | [features] 17 | default = ["std"] 18 | std = ["fluentbase-sdk/std"] 19 | -------------------------------------------------------------------------------- /contracts/erc20/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | fluentbase_build::build_default_genesis_contract() 3 | } 4 | -------------------------------------------------------------------------------- /contracts/erc20/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(target_arch = "wasm32"))] 2 | include!(concat!(env!("OUT_DIR"), "/build_output.rs")); 3 | -------------------------------------------------------------------------------- /contracts/erc20/src/main.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(target_arch = "wasm32", no_std, no_main)] 2 | use fluentbase_sdk::{entrypoint, SharedAPI}; 3 | 4 | pub fn main_entry(_sdk: impl SharedAPI) { 5 | todo!("not implemented") 6 | } 7 | 8 | entrypoint!(main_entry); 9 | -------------------------------------------------------------------------------- /contracts/evm/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fluentbase-contracts-evm" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | fluentbase-sdk = { workspace = true, default-features = false } 8 | fluentbase-evm = { workspace = true, default-features = false } 9 | 10 | [dev-dependencies] 11 | fluentbase-sdk-testing = { workspace = true } 12 | 13 | [build-dependencies] 14 | fluentbase-build = { workspace = true } 15 | fluentbase-sdk = { workspace = true, default-features = false } 16 | fluentbase-evm = { workspace = true, default-features = false } 17 | 18 | [features] 19 | default = ["std"] 20 | std = ["fluentbase-sdk/std", "fluentbase-evm/std"] 21 | -------------------------------------------------------------------------------- /contracts/evm/README.md: -------------------------------------------------------------------------------- 1 | # EVM 2 | 3 | This project provides an implementation of an execution environment that interfaces with the EVM or executes 4 | WebAssembly-based smart contracts. It manages interactions between smart contracts and their 5 | operational environment, handling deployment, execution, gas costs, and storage synchronization. The primary focus is on 6 | ensuring compatibility with Ethereum standards while enabling seamless contract workflows. 7 | 8 | The primary entry points of the codebase are the **`main`** and **`deploy`** functions. These drive the core logic for 9 | executing smart contracts and deploying them into the blockchain-like environment. 10 | 11 | ## **Deploy** 12 | 13 | The **`deploy`** function is used to deploy smart contracts. It includes setting initial storage or balances depending 14 | on the specific deployment requirements. 15 | 16 | 1. **Fetch Input**: 17 | - Read input data (typically the smart contract's initialization bytecode or parameters). 18 | 19 | 2. **Validation**: 20 | - Perform checks such as: 21 | - EVM-specific limits like code size restrictions (**EIP-170**). 22 | - Input validity or compliance with a protocol like rejecting bytecodes starting with `0xEF`. 23 | 24 | 3. **Execution**: 25 | - Execute the bytecode using the EVM. 26 | - If execution fails, terminate the deployment early. 27 | 28 | 4. **Storage/State Updates**: 29 | - If execution is successful: 30 | - Store deployed bytecode. 31 | - Record initial balances or other state data using the SDK. 32 | 33 | ## **Main** 34 | 35 | The **`main`** function is the entry point for executing contract bytecode. It handles reading input data, managing gas, 36 | and writing results back after execution. 37 | 38 | 1. **Contextual Setup**: 39 | - Retrieve the gas limit via the SDK. 40 | - Calculate the gas cost of the incoming transaction based on the input size. 41 | 42 | 2. **Gas Check**: 43 | - If the required gas exceeds the available gas limit, the execution terminates with an **OutOfFuel** error. 44 | 45 | 3. **Execution**: 46 | - Input data is read and processed. 47 | - The function writes the processed data (in this case, identical to the input) back to the output. 48 | 49 | --- 50 | 51 | P.S: 52 | Tha EVM interpreter is based on modified revm's interpreter with replaced system calls and adjusted gas calculation 53 | policy -------------------------------------------------------------------------------- /contracts/evm/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | fluentbase_build::build_default_genesis_contract() 3 | } 4 | -------------------------------------------------------------------------------- /contracts/evm/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(target_arch = "wasm32"))] 2 | include!(concat!(env!("OUT_DIR"), "/build_output.rs")); 3 | -------------------------------------------------------------------------------- /contracts/fairblock/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fluentbase-contracts-fairblock" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [lib] 7 | path = "lib.rs" 8 | 9 | [dependencies] 10 | fluentbase-sdk = { workspace = true } 11 | 12 | [dev-dependencies] 13 | fluentbase-sdk-testing = { workspace = true } 14 | 15 | [build-dependencies] 16 | fluentbase-build = { workspace = true } 17 | fluentbase-sdk = { workspace = true } 18 | 19 | [features] 20 | default = ["std"] 21 | std = ["fluentbase-sdk/std"] -------------------------------------------------------------------------------- /contracts/fairblock/build.rs: -------------------------------------------------------------------------------- 1 | use fluentbase_build::{ 2 | copy_wasm_and_wat, 3 | generate_build_output_file, 4 | go_to_wasm, 5 | is_tinygo_installed, 6 | wasm_to_rwasm, 7 | wasm_to_wasmtime, 8 | }; 9 | use fluentbase_sdk::default_compilation_config; 10 | use std::{env, fs}; 11 | 12 | fn main() { 13 | if env::var("TARGET").unwrap() == "wasm32-unknown-unknown" { 14 | return; 15 | } 16 | 17 | println!("cargo:rerun-if-changed=lib.rs"); 18 | println!("cargo:rerun-if-changed=Cargo.toml"); 19 | println!("cargo:rerun-if-changed=main.go"); 20 | println!("cargo:rerun-if-changed=go.mod"); 21 | println!("cargo:rerun-if-changed=go.sum"); 22 | println!("cargo:rerun-if-changed=fallback.wasm"); 23 | 24 | let wasm_path = if is_tinygo_installed() { 25 | go_to_wasm() 26 | } else { 27 | fs::canonicalize("fallback.wasm").unwrap() 28 | }; 29 | 30 | copy_wasm_and_wat(&wasm_path); 31 | let mut rwasm_config = default_compilation_config(); 32 | rwasm_config.builtins_consume_fuel(false); 33 | let rwasm_path = wasm_to_rwasm(&wasm_path, rwasm_config); 34 | let wasmtime_path = wasm_to_wasmtime(&wasm_path); 35 | 36 | println!( 37 | "cargo:rustc-env=FLUENTBASE_WASM_ARTIFACT_PATH={}", 38 | wasm_path.to_str().unwrap() 39 | ); 40 | 41 | generate_build_output_file(&wasm_path, &rwasm_path, &wasmtime_path); 42 | } 43 | -------------------------------------------------------------------------------- /contracts/fairblock/fallback.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluentlabs-xyz/fluentbase/0f58af75093bf191c121e8d75c3a6debbe9930d8/contracts/fairblock/fallback.wasm -------------------------------------------------------------------------------- /contracts/fairblock/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/fluentlabs-xyz/fluentbase/examples/fairblock 2 | 3 | go 1.21.4 4 | 5 | require ( 6 | filippo.io/age v1.1.1 // indirect 7 | github.com/FairBlock/DistributedIBE v0.0.0-20231211202607-d457df6869db // indirect 8 | github.com/drand/kyber v1.2.0 // indirect 9 | github.com/drand/kyber-bls12381 v0.2.5 // indirect 10 | github.com/kilic/bls12-381 v0.1.0 // indirect 11 | golang.org/x/crypto v0.7.0 // indirect 12 | golang.org/x/sys v0.6.0 // indirect 13 | ) 14 | -------------------------------------------------------------------------------- /contracts/fairblock/go.sum: -------------------------------------------------------------------------------- 1 | filippo.io/age v1.1.1 h1:pIpO7l151hCnQ4BdyBujnGP2YlUo0uj6sAVNHGBvXHg= 2 | filippo.io/age v1.1.1/go.mod h1:l03SrzDUrBkdBx8+IILdnn2KZysqQdbEBUQ4p3sqEQE= 3 | github.com/FairBlock/DistributedIBE v0.0.0-20231211202607-d457df6869db h1:wmRvJRPDm8nXZzRjzgPzbhGHhEX5TbXUBiZkAieUNMA= 4 | github.com/FairBlock/DistributedIBE v0.0.0-20231211202607-d457df6869db/go.mod h1:qXpLBzZiSdWoweJkE/lAIPedf6GOl7WsYM8rxrZCCDk= 5 | github.com/drand/kyber v1.2.0 h1:22SbBxsKbgQnJUoyYKIfG909PhBsj0vtANeu4BX5xgE= 6 | github.com/drand/kyber v1.2.0/go.mod h1:6TqFlCc7NGOiNVTF9pF2KcDRfllPd9XOkExuG5Xtwfo= 7 | github.com/drand/kyber-bls12381 v0.2.5 h1:4ugiCmXQsvgAuylSk929rK49WGFxCxT/7ArH2vw6Tlg= 8 | github.com/drand/kyber-bls12381 v0.2.5/go.mod h1:8fm2tmRaAdYRGMTh5tjF7qrGHywC+rmM5hrUFL+9fCI= 9 | github.com/kilic/bls12-381 v0.1.0 h1:encrdjqKMEvabVQ7qYOKu1OvhqpK4s47wDYtNiPtlp4= 10 | github.com/kilic/bls12-381 v0.1.0/go.mod h1:vDTTHJONJ6G+P2R74EhnyotQDTliQDnFEwhdmfzw1ig= 11 | golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= 12 | golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= 13 | golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 14 | golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= 15 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 16 | -------------------------------------------------------------------------------- /contracts/fairblock/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(target_arch = "wasm32"))] 2 | include!(concat!(env!("OUT_DIR"), "/build_output.rs")); 3 | -------------------------------------------------------------------------------- /contracts/fairblock/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "C" 4 | import ( 5 | "bytes" 6 | enc "github.com/FairBlock/DistributedIBE/encryption" 7 | //"bytes" 8 | //"fmt" 9 | bls "github.com/drand/kyber-bls12381" 10 | "unsafe" 11 | ) 12 | 13 | //go:wasm-module fluentbase_v1preview 14 | //export _read 15 | func _read(*C.char, C.uint, C.uint) 16 | 17 | //go:wasm-module fluentbase_v1preview 18 | //export _write 19 | func _write(*C.char, C.uint) 20 | 21 | //go:wasm-module fluentbase_v1preview 22 | //export _input_size 23 | func _input_size() C.uint 24 | 25 | //go:wasm-module fluentbase_v1preview 26 | //export _exit 27 | func _exit(C.int) 28 | 29 | //export deploy 30 | func deploy() { 31 | } 32 | 33 | //export main 34 | func main() { 35 | headerLen := 374 36 | pkLen := 48 37 | skLen := 96 38 | inputSize := _input_size() 39 | 40 | input := make([]C.char, inputSize) 41 | ptr := (*C.char)(&input[0]) 42 | 43 | _read(ptr, C.uint(380), inputSize) 44 | 45 | rawPk := C.GoBytes(unsafe.Pointer(&input[headerLen]), C.int(pkLen)) 46 | pk := bls.NullKyberG1() 47 | err := pk.UnmarshalBinary(rawPk) 48 | 49 | if err != nil { 50 | print_err(err) 51 | return 52 | } 53 | 54 | rawSk := C.GoBytes(unsafe.Pointer(&input[headerLen+pkLen]), C.int(skLen)) 55 | 56 | sk := bls.NullKyberG2() 57 | 58 | err = sk.UnmarshalBinary(rawSk) 59 | 60 | if err != nil { 61 | print_err(err) 62 | return 63 | } 64 | 65 | chiperData := C.GoBytes(unsafe.Pointer(&input[headerLen+pkLen+skLen]), C.int(inputSize)-C.int(pkLen)-C.int(skLen)-C.int(headerLen)) 66 | 67 | var plainData bytes.Buffer 68 | 69 | err = enc.Decrypt(pk, sk, &plainData, bytes.NewReader(chiperData)) 70 | if err != nil { 71 | print_err(err) 72 | return 73 | } 74 | 75 | resultLen := C.uint(len(plainData.Bytes())) 76 | resultPtr := (*C.char)(unsafe.Pointer(&plainData.Bytes()[0])) 77 | 78 | _write(resultPtr, resultLen) 79 | _exit(0) 80 | } 81 | 82 | func print_err(err error) { 83 | errBytes := []byte(err.Error()) 84 | 85 | resultLen := C.uint(len(errBytes)) 86 | resultPtr := (*C.char)(unsafe.Pointer(&errBytes[0])) 87 | 88 | _write(resultPtr, resultLen) 89 | _exit(-1) 90 | } -------------------------------------------------------------------------------- /contracts/identity/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fluentbase-contracts-identity" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | fluentbase-sdk = { workspace = true } 8 | revm-precompile = { workspace = true } 9 | 10 | [dev-dependencies] 11 | fluentbase-sdk-testing = { workspace = true } 12 | 13 | [build-dependencies] 14 | fluentbase-build = { workspace = true } 15 | fluentbase-sdk = { workspace = true } 16 | revm-precompile = { workspace = true } 17 | 18 | [features] 19 | default = ["std"] 20 | std = ["fluentbase-sdk/std", "revm-precompile/std"] 21 | -------------------------------------------------------------------------------- /contracts/identity/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | fluentbase_build::build_default_genesis_contract() 3 | } 4 | -------------------------------------------------------------------------------- /contracts/identity/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(target_arch = "wasm32"))] 2 | include!(concat!(env!("OUT_DIR"), "/build_output.rs")); 3 | -------------------------------------------------------------------------------- /contracts/identity/src/main.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(target_arch = "wasm32", no_std, no_main)] 2 | extern crate alloc; 3 | extern crate core; 4 | extern crate fluentbase_sdk; 5 | 6 | use fluentbase_sdk::{alloc_slice, entrypoint, ContractContextReader, ExitCode, SharedAPI}; 7 | use revm_precompile::{ 8 | calc_linear_cost_u32, 9 | identity::{IDENTITY_BASE, IDENTITY_PER_WORD}, 10 | }; 11 | 12 | pub fn main_entry(mut sdk: impl SharedAPI) { 13 | let gas_limit = sdk.context().contract_gas_limit(); 14 | let input_length = sdk.input_size(); 15 | // fail fast if we don't have enough fuel for the call 16 | let gas_used = calc_linear_cost_u32(input_length as usize, IDENTITY_BASE, IDENTITY_PER_WORD); 17 | if gas_used > gas_limit { 18 | sdk.exit(ExitCode::OutOfFuel); 19 | } 20 | sdk.sync_evm_gas(gas_used, 0); 21 | let mut input = alloc_slice(input_length as usize); 22 | sdk.read(&mut input, 0); 23 | // write an identical output 24 | sdk.write(input); 25 | } 26 | 27 | entrypoint!(main_entry); 28 | 29 | #[cfg(test)] 30 | mod tests { 31 | use super::*; 32 | use fluentbase_sdk::{Bytes, ContractContextV1, FUEL_DENOM_RATE}; 33 | use fluentbase_sdk_testing::HostTestingContext; 34 | 35 | fn exec_evm_precompile(inputs: &[u8], expected: &[u8], expected_gas: u64) { 36 | let gas_limit = 100_000; 37 | let sdk = HostTestingContext::default() 38 | .with_input(Bytes::copy_from_slice(inputs)) 39 | .with_contract_context(ContractContextV1 { 40 | gas_limit, 41 | ..Default::default() 42 | }) 43 | .with_gas_limit(gas_limit); 44 | main_entry(sdk.clone()); 45 | let output = sdk.take_output(); 46 | assert_eq!(output, expected); 47 | let gas_remaining = sdk.fuel() / FUEL_DENOM_RATE; 48 | assert_eq!(gas_limit - gas_remaining, expected_gas); 49 | } 50 | 51 | #[test] 52 | fn test_hello_world_works() { 53 | exec_evm_precompile("Hello, World".as_bytes(), "Hello, World".as_bytes(), 18); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /contracts/kzg/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fluentbase-contracts-kzg" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | fluentbase-sdk = { workspace = true } 8 | revm-precompile = { workspace = true, features = ["kzg-rs"] } 9 | 10 | [dev-dependencies] 11 | fluentbase-sdk-testing = { workspace = true } 12 | 13 | [build-dependencies] 14 | fluentbase-build = { workspace = true } 15 | fluentbase-sdk = { workspace = true } 16 | revm-precompile = { workspace = true, features = ["kzg-rs"] } 17 | 18 | [features] 19 | default = ["std"] 20 | std = ["fluentbase-sdk/std", "revm-precompile/std"] 21 | -------------------------------------------------------------------------------- /contracts/kzg/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | fluentbase_build::build_default_genesis_contract() 3 | } 4 | -------------------------------------------------------------------------------- /contracts/kzg/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(target_arch = "wasm32"))] 2 | include!(concat!(env!("OUT_DIR"), "/build_output.rs")); 3 | -------------------------------------------------------------------------------- /contracts/modexp/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fluentbase-contracts-modexp" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | fluentbase-sdk = { workspace = true } 8 | revm-precompile = { workspace = true } 9 | 10 | [dev-dependencies] 11 | fluentbase-sdk-testing = { workspace = true } 12 | 13 | [build-dependencies] 14 | fluentbase-build = { workspace = true } 15 | fluentbase-sdk = { workspace = true } 16 | revm-precompile = { workspace = true } 17 | 18 | [features] 19 | default = ["std"] 20 | std = ["fluentbase-sdk/std", "revm-precompile/std"] 21 | -------------------------------------------------------------------------------- /contracts/modexp/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | fluentbase_build::build_default_genesis_contract() 3 | } 4 | -------------------------------------------------------------------------------- /contracts/modexp/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(target_arch = "wasm32"))] 2 | include!(concat!(env!("OUT_DIR"), "/build_output.rs")); 3 | -------------------------------------------------------------------------------- /contracts/multicall/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fluentbase-contracts-multicall" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | fluentbase-sdk = { workspace = true } 8 | 9 | [dev-dependencies] 10 | fluentbase-sdk-testing = { workspace = true } 11 | 12 | [build-dependencies] 13 | fluentbase-build = { workspace = true } 14 | fluentbase-sdk = { workspace = true } 15 | 16 | [features] 17 | default = ["std"] 18 | std = ["fluentbase-sdk/std"] 19 | -------------------------------------------------------------------------------- /contracts/multicall/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | fluentbase_build::build_default_genesis_contract() 3 | } 4 | -------------------------------------------------------------------------------- /contracts/multicall/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(target_arch = "wasm32"))] 2 | include!(concat!(env!("OUT_DIR"), "/build_output.rs")); 3 | -------------------------------------------------------------------------------- /contracts/multicall/src/main.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(target_arch = "wasm32", no_std, no_main)] 2 | extern crate alloc; 3 | extern crate fluentbase_sdk; 4 | 5 | use alloc::vec::Vec; 6 | use fluentbase_sdk::{ 7 | alloc_slice, 8 | bytes::Buf, 9 | codec::{bytes::BytesMut, encoder::SolidityABI}, 10 | entrypoint, 11 | Bytes, 12 | ContractContextReader, 13 | SharedAPI, 14 | SyscallResult, 15 | }; 16 | 17 | /// A selector for "multicall(bytes[])" - 0xac9650d8 18 | const MULTICALL_SELECTOR: [u8; 4] = [0xac, 0x96, 0x50, 0xd8]; 19 | 20 | pub fn main_entry(mut sdk: impl SharedAPI) { 21 | // Read full input data 22 | let input_length = sdk.input_size(); 23 | assert!(input_length >= 4, "multicall: insufficient input length"); 24 | let mut call_data = alloc_slice(input_length as usize); 25 | sdk.read(&mut call_data, 0); 26 | 27 | // Split into selector and parameters 28 | let (selector, params) = call_data.split_at(4); 29 | assert_eq!( 30 | selector, MULTICALL_SELECTOR, 31 | "multicall: invalid method selector" 32 | ); 33 | 34 | // Decode parameters into Vec 35 | let data = SolidityABI::>::decode(&Bytes::from(params), 0) 36 | .unwrap_or_else(|_| panic!("multicall: can't decode input parameters")); 37 | 38 | // Get contract address for delegate calls 39 | let target_addr = sdk.context().contract_address(); 40 | let mut results = Vec::with_capacity(data.len()); 41 | 42 | // Execute each call 43 | for call_data in data { 44 | let chunk = call_data.chunk(); 45 | let result = sdk.delegate_call(target_addr, chunk, None); 46 | if !SyscallResult::is_ok(result.status) { 47 | panic!("multicall: delegate call failed"); 48 | } 49 | results.push(result.data); 50 | } 51 | 52 | // Encode results for return 53 | let mut buf = BytesMut::new(); 54 | SolidityABI::encode(&(results,), &mut buf, 0) 55 | .unwrap_or_else(|_| panic!("multicall: can't decode input parameters")); 56 | let encoded_output = buf.freeze(); 57 | 58 | // Remove offset from encoded output since caller expects only data 59 | let clean_output = encoded_output[32..].to_vec(); 60 | sdk.write(&clean_output); 61 | } 62 | 63 | entrypoint!(main_entry); 64 | -------------------------------------------------------------------------------- /contracts/nitro/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fluentbase-contracts-nitro" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | fluentbase-sdk = { workspace = true } 8 | coset = { version = "0.3.8", default-features = false } 9 | ciborium = { version = "^0.2.1", default-features = false } 10 | x509-cert = { version = "0.2.5", default-features = false, features = ["pem"] } 11 | der = { version = "0.7.9", default-features = false, features = ["alloc"] } 12 | ecdsa = { version = "0.16.9", default-features = false, features = [ 13 | "digest", 14 | "alloc", 15 | "der", 16 | ] } 17 | p384 = { version = "0.13.0", default-features = false, features = [ 18 | "ecdsa-core", 19 | "ecdsa", 20 | ] } 21 | hex = "0.4.3" 22 | 23 | [dev-dependencies] 24 | fluentbase-sdk-testing = { workspace = true } 25 | 26 | [build-dependencies] 27 | fluentbase-build = { workspace = true } 28 | fluentbase-sdk = { workspace = true } 29 | 30 | [features] 31 | default = ["std", "fluentbase-sdk/debug-print"] 32 | std = ["fluentbase-sdk/std"] 33 | -------------------------------------------------------------------------------- /contracts/nitro/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | fluentbase_build::build_default_genesis_contract() 3 | } 4 | -------------------------------------------------------------------------------- /contracts/nitro/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(target_arch = "wasm32"))] 2 | include!(concat!(env!("OUT_DIR"), "/build_output.rs")); 3 | -------------------------------------------------------------------------------- /contracts/nitro/src/main.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(target_arch = "wasm32", no_std, no_main)] 2 | #![allow(dead_code)] 3 | 4 | extern crate alloc; 5 | extern crate fluentbase_sdk; 6 | 7 | mod attestation; 8 | 9 | use fluentbase_sdk::{alloc_slice, entrypoint, SharedAPI}; 10 | 11 | pub fn main_entry(sdk: impl SharedAPI) { 12 | let input_size = sdk.input_size(); 13 | let input = alloc_slice(input_size as usize); 14 | sdk.read(input, 0); 15 | attestation::parse_and_verify(&input); 16 | } 17 | 18 | entrypoint!(main_entry); 19 | 20 | #[cfg(test)] 21 | mod tests { 22 | use super::*; 23 | use fluentbase_sdk_testing::HostTestingContext; 24 | 25 | #[test] 26 | fn test_nitro_attestation_verification() { 27 | // Example of valid attestation document 28 | // https://github.com/evervault/attestation-doc-validation/blob/main/test-data/valid-attestation-doc-base64 29 | let data: Vec = hex::decode(include_bytes!("../attestation-example.hex")) 30 | .unwrap() 31 | .into(); 32 | let doc = attestation::parse_and_verify(&data); 33 | assert_eq!(doc.digest, "SHA384"); 34 | let sdk = HostTestingContext::default().with_input(data); 35 | main_entry(sdk); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /contracts/nitro/src/nitro.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICETCCAZagAwIBAgIRAPkxdWgbkK/hHUbMtOTn+FYwCgYIKoZIzj0EAwMwSTEL 3 | MAkGA1UEBhMCVVMxDzANBgNVBAoMBkFtYXpvbjEMMAoGA1UECwwDQVdTMRswGQYD 4 | VQQDDBJhd3Mubml0cm8tZW5jbGF2ZXMwHhcNMTkxMDI4MTMyODA1WhcNNDkxMDI4 5 | MTQyODA1WjBJMQswCQYDVQQGEwJVUzEPMA0GA1UECgwGQW1hem9uMQwwCgYDVQQL 6 | DANBV1MxGzAZBgNVBAMMEmF3cy5uaXRyby1lbmNsYXZlczB2MBAGByqGSM49AgEG 7 | BSuBBAAiA2IABPwCVOumCMHzaHDimtqQvkY4MpJzbolL//Zy2YlES1BR5TSksfbb 8 | 48C8WBoyt7F2Bw7eEtaaP+ohG2bnUs990d0JX28TcPQXCEPZ3BABIeTPYwEoCWZE 9 | h8l5YoQwTcU/9KNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUkCW1DdkF 10 | R+eWw5b6cp3PmanfS5YwDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2kAMGYC 11 | MQCjfy+Rocm9Xue4YnwWmNJVA44fA0P5W2OpYow9OYCVRaEevL8uO1XYru5xtMPW 12 | rfMCMQCi85sWBbJwKKXdS6BptQFuZbT73o/gBh1qUxl/nNr12UO8Yfwr6wPLb+6N 13 | IwLz3/Y= 14 | -----END CERTIFICATE----- -------------------------------------------------------------------------------- /contracts/oauth2/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fluentbase-contracts-oauth2" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | fluentbase-sdk = { workspace = true } 8 | 9 | [dev-dependencies] 10 | fluentbase-sdk-testing = { workspace = true } 11 | 12 | [build-dependencies] 13 | fluentbase-build = { workspace = true } 14 | fluentbase-sdk = { workspace = true } 15 | 16 | [features] 17 | default = ["std"] 18 | std = ["fluentbase-sdk/std"] 19 | -------------------------------------------------------------------------------- /contracts/oauth2/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | fluentbase_build::build_default_genesis_contract() 3 | } 4 | -------------------------------------------------------------------------------- /contracts/oauth2/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(target_arch = "wasm32"))] 2 | include!(concat!(env!("OUT_DIR"), "/build_output.rs")); 3 | -------------------------------------------------------------------------------- /contracts/oauth2/src/main.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(target_arch = "wasm32", no_std, no_main)] 2 | use fluentbase_sdk::{entrypoint, SharedAPI}; 3 | 4 | pub fn main_entry(_sdk: impl SharedAPI) { 5 | todo!("not implemented") 6 | } 7 | 8 | entrypoint!(main_entry); 9 | -------------------------------------------------------------------------------- /contracts/ripemd160/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fluentbase-contracts-ripemd160" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | fluentbase-sdk = { workspace = true } 8 | revm-precompile = { workspace = true } 9 | 10 | [dev-dependencies] 11 | fluentbase-sdk-testing = { workspace = true } 12 | 13 | [build-dependencies] 14 | fluentbase-build = { workspace = true } 15 | fluentbase-sdk = { workspace = true } 16 | revm-precompile = { workspace = true } 17 | 18 | [features] 19 | default = ["std"] 20 | std = ["fluentbase-sdk/std", "revm-precompile/std"] 21 | -------------------------------------------------------------------------------- /contracts/ripemd160/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | fluentbase_build::build_default_genesis_contract() 3 | } 4 | -------------------------------------------------------------------------------- /contracts/ripemd160/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(target_arch = "wasm32"))] 2 | include!(concat!(env!("OUT_DIR"), "/build_output.rs")); 3 | -------------------------------------------------------------------------------- /contracts/ripemd160/src/main.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(target_arch = "wasm32", no_std, no_main)] 2 | extern crate alloc; 3 | extern crate fluentbase_sdk; 4 | 5 | use fluentbase_sdk::{ 6 | alloc_slice, 7 | entrypoint, 8 | Bytes, 9 | ContractContextReader, 10 | ExitCode, 11 | SharedAPI, 12 | }; 13 | 14 | pub fn main_entry(mut sdk: impl SharedAPI) { 15 | // read full input data 16 | let gas_limit = sdk.context().contract_gas_limit(); 17 | let input_length = sdk.input_size(); 18 | let mut input = alloc_slice(input_length as usize); 19 | sdk.read(&mut input, 0); 20 | let input = Bytes::copy_from_slice(input); 21 | // call ripemd160 function 22 | let result = revm_precompile::hash::ripemd160_run(&input, gas_limit) 23 | .unwrap_or_else(|err| sdk.exit(ExitCode::from(err))); 24 | sdk.sync_evm_gas(result.gas_used, 0); 25 | // write output 26 | sdk.write(result.bytes.as_ref()); 27 | } 28 | 29 | entrypoint!(main_entry); 30 | 31 | #[cfg(test)] 32 | mod tests { 33 | use super::*; 34 | use fluentbase_sdk::{hex, ContractContextV1, FUEL_DENOM_RATE}; 35 | use fluentbase_sdk_testing::HostTestingContext; 36 | 37 | fn exec_evm_precompile(inputs: &[u8], expected: &[u8], expected_gas: u64) { 38 | let gas_limit = 100_000; 39 | let sdk = HostTestingContext::default() 40 | .with_input(Bytes::copy_from_slice(inputs)) 41 | .with_contract_context(ContractContextV1 { 42 | gas_limit, 43 | ..Default::default() 44 | }) 45 | .with_gas_limit(gas_limit); 46 | main_entry(sdk.clone()); 47 | let output = sdk.take_output(); 48 | assert_eq!(output, expected); 49 | let gas_remaining = sdk.fuel() / FUEL_DENOM_RATE; 50 | assert_eq!(gas_limit - gas_remaining, expected_gas); 51 | } 52 | 53 | #[test] 54 | fn test_hello_world_works() { 55 | exec_evm_precompile( 56 | "Hello, World".as_bytes(), 57 | &hex!("0000000000000000000000006782893f9a818abc3da35d745a803d72a660c9f5"), 58 | 720, 59 | ); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /contracts/secp256r1/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fluentbase-contracts-secp256r1" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | fluentbase-sdk = { workspace = true } 8 | revm-precompile = { workspace = true, features = ["secp256r1"] } 9 | 10 | [dev-dependencies] 11 | fluentbase-sdk-testing = { workspace = true } 12 | hex = "0.4.3" 13 | p256 = { version = "0.13.2", default-features = false, features = [ 14 | "ecdsa", 15 | "arithmetic", 16 | ] } 17 | sha2 = { version = "0.10", default-features = false } 18 | 19 | [build-dependencies] 20 | fluentbase-build = { workspace = true } 21 | fluentbase-sdk = { workspace = true } 22 | revm-precompile = { workspace = true, features = ["secp256r1"] } 23 | 24 | [features] 25 | default = ["std"] 26 | std = ["fluentbase-sdk/std", "revm-precompile/std"] 27 | -------------------------------------------------------------------------------- /contracts/secp256r1/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | fluentbase_build::build_default_genesis_contract() 3 | } 4 | -------------------------------------------------------------------------------- /contracts/secp256r1/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(target_arch = "wasm32"))] 2 | include!(concat!(env!("OUT_DIR"), "/build_output.rs")); 3 | -------------------------------------------------------------------------------- /contracts/sha256/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fluentbase-contracts-sha256" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | fluentbase-sdk = { workspace = true } 8 | revm-precompile = { workspace = true } 9 | 10 | [dev-dependencies] 11 | fluentbase-sdk-testing = { workspace = true } 12 | 13 | [build-dependencies] 14 | fluentbase-build = { workspace = true } 15 | fluentbase-sdk = { workspace = true } 16 | revm-precompile = { workspace = true } 17 | 18 | [features] 19 | default = ["std"] 20 | std = ["fluentbase-sdk/std", "revm-precompile/std"] 21 | -------------------------------------------------------------------------------- /contracts/sha256/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | fluentbase_build::build_default_genesis_contract() 3 | } 4 | -------------------------------------------------------------------------------- /contracts/sha256/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(target_arch = "wasm32"))] 2 | include!(concat!(env!("OUT_DIR"), "/build_output.rs")); 3 | -------------------------------------------------------------------------------- /contracts/sha256/src/main.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(target_arch = "wasm32", no_std, no_main)] 2 | extern crate alloc; 3 | extern crate fluentbase_sdk; 4 | 5 | use fluentbase_sdk::{ 6 | alloc_slice, 7 | entrypoint, 8 | Bytes, 9 | ContractContextReader, 10 | ExitCode, 11 | SharedAPI, 12 | }; 13 | 14 | pub fn main_entry(mut sdk: impl SharedAPI) { 15 | // read full input data 16 | let gas_limit = sdk.context().contract_gas_limit(); 17 | let input_length = sdk.input_size(); 18 | let mut input = alloc_slice(input_length as usize); 19 | sdk.read(&mut input, 0); 20 | let input = Bytes::copy_from_slice(input); 21 | // call sha256 function 22 | let result = revm_precompile::hash::sha256_run(&input, gas_limit) 23 | .unwrap_or_else(|err| sdk.exit(ExitCode::from(err))); 24 | sdk.sync_evm_gas(result.gas_used, 0); 25 | // write output 26 | sdk.write(result.bytes.as_ref()); 27 | } 28 | 29 | entrypoint!(main_entry); 30 | 31 | #[cfg(test)] 32 | mod tests { 33 | use super::*; 34 | use fluentbase_sdk::{hex, ContractContextV1, FUEL_DENOM_RATE}; 35 | use fluentbase_sdk_testing::HostTestingContext; 36 | 37 | fn exec_evm_precompile(inputs: &[u8], expected: &[u8], expected_gas: u64) { 38 | let gas_limit = 100_000; 39 | let sdk = HostTestingContext::default() 40 | .with_input(Bytes::copy_from_slice(inputs)) 41 | .with_contract_context(ContractContextV1 { 42 | gas_limit, 43 | ..Default::default() 44 | }) 45 | .with_gas_limit(gas_limit); 46 | main_entry(sdk.clone()); 47 | let output = sdk.take_output(); 48 | assert_eq!(output, expected); 49 | let gas_remaining = sdk.fuel() / FUEL_DENOM_RATE; 50 | assert_eq!(gas_limit - gas_remaining, expected_gas); 51 | } 52 | 53 | #[test] 54 | fn test_hello_world_works() { 55 | exec_evm_precompile( 56 | "Hello, World".as_bytes(), 57 | &hex!("03675ac53ff9cd1535ccc7dfcdfa2c458c5218371f418dc136f2d19ac1fbe8a5"), 58 | 72, 59 | ); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /contracts/webauthn/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fluentbase-contracts-webauthn" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | base64 = { version = "0.22.0", default-features = false, features = ["alloc"] } 8 | fluentbase-sdk = { workspace = true } 9 | hex = { version = "0.4", default-features = false, features = ["alloc"] } 10 | # p256 = {version = "0.13.2", default-features = false, features = ["ecdsa", "arithmetic"]} 11 | revm-precompile = { workspace = true, features = ["secp256r1"] } 12 | 13 | sha2 = { version = "0.10", default-features = false } 14 | 15 | [dev-dependencies] 16 | fluentbase-sdk-testing = { workspace = true } 17 | p256 = { version = "0.13.2", default-features = false, features = [ 18 | "ecdsa", 19 | "arithmetic", 20 | ] } 21 | 22 | [build-dependencies] 23 | fluentbase-build = { workspace = true } 24 | fluentbase-sdk = { workspace = true } 25 | 26 | [features] 27 | default = ["std"] 28 | std = [ 29 | "fluentbase-sdk/std", # "p256/std", 30 | "sha2/std", 31 | "base64/std", 32 | "hex/std", 33 | "revm-precompile/std", 34 | ] 35 | -------------------------------------------------------------------------------- /contracts/webauthn/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | fluentbase_build::build_default_genesis_contract() 3 | } 4 | -------------------------------------------------------------------------------- /contracts/webauthn/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(target_arch = "wasm32"))] 2 | include!(concat!(env!("OUT_DIR"), "/build_output.rs")); 3 | -------------------------------------------------------------------------------- /crates/build/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fluentbase-build" 3 | version = "0.1.0" 4 | authors.workspace = true 5 | repository.workspace = true 6 | edition.workspace = true 7 | readme.workspace = true 8 | license.workspace = true 9 | keywords.workspace = true 10 | categories.workspace = true 11 | 12 | [dependencies] 13 | cargo_metadata = "0.19.1" 14 | fluentbase-types = { workspace = true } 15 | rwasm = { workspace = true } 16 | wasmtime = { workspace = true } 17 | 18 | [features] 19 | default = [] -------------------------------------------------------------------------------- /crates/build/src/config.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone)] 2 | pub struct RustToWasmConfig { 3 | pub stack_size: u32, 4 | pub features: Vec, 5 | pub no_default_features: bool, 6 | } 7 | 8 | impl Default for RustToWasmConfig { 9 | fn default() -> Self { 10 | Self { 11 | stack_size: 128 * 1024, 12 | features: vec![], 13 | no_default_features: true, 14 | } 15 | } 16 | } 17 | 18 | impl RustToWasmConfig { 19 | pub fn with_stack_size(mut self, stack_size: u32) -> Self { 20 | self.stack_size = stack_size; 21 | self 22 | } 23 | 24 | pub fn with_features(mut self, features: Vec) -> Self { 25 | self.features = features; 26 | self 27 | } 28 | 29 | pub fn with_no_default_features(mut self, no_default_features: bool) -> Self { 30 | self.no_default_features = no_default_features; 31 | self 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /crates/codec-derive/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fluentbase-codec-derive" 3 | version = "0.1.0" 4 | authors.workspace = true 5 | repository.workspace = true 6 | edition.workspace = true 7 | readme.workspace = true 8 | license.workspace = true 9 | keywords.workspace = true 10 | categories.workspace = true 11 | 12 | [dependencies] 13 | convert_case = "0.6.0" 14 | quote = "1.0" 15 | serde = { version = "1.0", default-features = false, features = ["derive"] } 16 | syn = { workspace = true } 17 | crypto-hashes = { version = "0.10.0", default-features = false, features = ["include_weak"] } 18 | proc-macro2 = { version = "1.0", default-features = false } 19 | 20 | 21 | 22 | [dev-dependencies] 23 | bytes = "1.0" 24 | insta = { version = "1.43.1", features = ["yaml"] } 25 | prettyplease = "0.2.32" 26 | 27 | [lib] 28 | proc-macro = true 29 | 30 | -------------------------------------------------------------------------------- /crates/codec/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors.workspace = true 3 | categories.workspace = true 4 | edition.workspace = true 5 | keywords.workspace = true 6 | license.workspace = true 7 | name = "fluentbase-codec" 8 | readme.workspace = true 9 | repository.workspace = true 10 | version = "0.1.0" 11 | 12 | [dependencies] 13 | alloy-primitives = { workspace = true } 14 | byteorder = { workspace = true } 15 | bytes = { workspace = true, default-features = false } 16 | fluentbase-codec-derive = { workspace = true } 17 | hashbrown = { workspace = true } 18 | serde = { workspace = true, default-features = false } 19 | 20 | [dev-dependencies] 21 | alloy-sol-types = { workspace = true } 22 | hex = { workspace = true } 23 | hex-literal = { workspace = true } 24 | 25 | [features] 26 | default = ["std", "derive"] 27 | derive = [] 28 | std = [ 29 | "byteorder/std", 30 | "alloy-primitives/std", 31 | "serde/std", 32 | "bytes/std", 33 | ] 34 | -------------------------------------------------------------------------------- /crates/codec/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(feature = "std"), no_std)] 2 | #![allow(unused_imports)] 3 | extern crate alloc; 4 | extern crate core; 5 | 6 | pub mod bytes_codec; 7 | mod empty; 8 | pub mod encoder; 9 | mod error; 10 | mod evm; 11 | mod hash; 12 | mod primitive; 13 | mod tuple; 14 | mod vec; 15 | 16 | #[cfg(test)] 17 | mod test_utils; 18 | #[cfg(test)] 19 | mod tests; 20 | 21 | pub use ::byteorder; 22 | pub use ::bytes; 23 | pub use encoder::*; 24 | pub use error::*; 25 | #[cfg(feature = "derive")] 26 | pub use fluentbase_codec_derive::Codec; 27 | -------------------------------------------------------------------------------- /crates/codec/src/test_utils.rs: -------------------------------------------------------------------------------- 1 | use crate::encoder::{is_big_endian, read_u32_aligned}; 2 | use byteorder::ByteOrder; 3 | 4 | pub(crate) fn print_bytes(buf: &[u8]) { 5 | for (i, chunk) in buf.chunks(ALIGN).enumerate() { 6 | let offset = i * ALIGN; 7 | print!("{:04x}: ", offset); 8 | 9 | if is_big_endian::() { 10 | for &byte in &chunk[&chunk.len() - 4..] { 11 | print!("{:02x} ", byte); 12 | } 13 | } else { 14 | for &byte in &chunk[..4] { 15 | print!("{:02x} ", byte); 16 | } 17 | } 18 | 19 | for _ in chunk.len()..ALIGN { 20 | print!(" "); 21 | } 22 | print!(" || {:03}", offset); 23 | let decimal_value = read_u32_aligned::(&chunk, 0).unwrap(); 24 | println!(": {:03} |", decimal_value); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /crates/codec/tests/common/mod.rs: -------------------------------------------------------------------------------- 1 | #[allow(dead_code)] 2 | pub(crate) fn print_hex_dump(data: &[u8]) { 3 | for (i, chunk) in data.chunks(32).enumerate() { 4 | println!("{:03x}: {}", i * 32, hex::encode(chunk)); 5 | } 6 | } 7 | 8 | #[allow(dead_code)] 9 | pub(crate) fn print_hex_dump_and_expected(actual: &[u8], expected: &[u8]) { 10 | println!("Actual:"); 11 | print_hex_dump(actual); 12 | println!("\nExpected:"); 13 | print_hex_dump(expected); 14 | } 15 | -------------------------------------------------------------------------------- /crates/codec/tests/lib.rs: -------------------------------------------------------------------------------- 1 | mod common; 2 | mod roundtrip; 3 | -------------------------------------------------------------------------------- /crates/codec/tests/roundtrip/mod.rs: -------------------------------------------------------------------------------- 1 | use alloy_primitives::{Address, Bytes, FixedBytes, U256}; 2 | use alloy_sol_types::{sol, SolValue}; 3 | use byteorder::BE; 4 | use bytes::BytesMut; 5 | use fluentbase_codec::{ 6 | byteorder, 7 | encoder::{CompactABI, Encoder, SolidityABI, SolidityPackedABI}, 8 | Codec, 9 | }; 10 | 11 | mod structs; 12 | mod tuples; 13 | -------------------------------------------------------------------------------- /crates/evm/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fluentbase-evm" 3 | version = "0.1.0" 4 | authors.workspace = true 5 | repository.workspace = true 6 | edition.workspace = true 7 | readme.workspace = true 8 | license.workspace = true 9 | keywords.workspace = true 10 | categories.workspace = true 11 | 12 | [dependencies] 13 | fluentbase-sdk = { workspace = true } 14 | bitvec = { workspace = true } 15 | bincode = { workspace = true } 16 | 17 | [dev-dependencies] 18 | fluentbase-sdk-testing = { workspace = true } 19 | 20 | [features] 21 | default = ["std"] 22 | std = [ 23 | "fluentbase-sdk/std", 24 | ] 25 | -------------------------------------------------------------------------------- /crates/evm/src/evm/context.rs: -------------------------------------------------------------------------------- 1 | use crate::{as_usize_saturated, gas, pop_top, push, push_b256, try_push, EVM}; 2 | use fluentbase_sdk::{BlockContextReader, SharedAPI, TxContextReader, U256}; 3 | 4 | /// EIP-1344: ChainID opcode 5 | pub fn chainid(evm: &mut EVM) { 6 | gas!(evm, gas::BASE); 7 | push!(evm, U256::from(evm.sdk.context().block_chain_id())); 8 | } 9 | 10 | pub fn coinbase(evm: &mut EVM) { 11 | gas!(evm, gas::BASE); 12 | push_b256!(evm, evm.sdk.context().block_coinbase().into_word()); 13 | } 14 | 15 | pub fn timestamp(evm: &mut EVM) { 16 | gas!(evm, gas::BASE); 17 | try_push!(evm, evm.sdk.context().block_timestamp()); 18 | } 19 | 20 | pub fn block_number(evm: &mut EVM) { 21 | gas!(evm, gas::BASE); 22 | try_push!(evm, evm.sdk.context().block_number()); 23 | } 24 | 25 | pub fn difficulty(evm: &mut EVM) { 26 | gas!(evm, gas::BASE); 27 | push_b256!(evm, evm.sdk.context().block_prev_randao()); 28 | } 29 | 30 | pub fn gaslimit(evm: &mut EVM) { 31 | gas!(evm, gas::BASE); 32 | try_push!(evm, evm.sdk.context().block_gas_limit()); 33 | } 34 | 35 | pub fn gasprice(evm: &mut EVM) { 36 | gas!(evm, gas::BASE); 37 | try_push!(evm, evm.sdk.context().tx_gas_price()); 38 | } 39 | 40 | /// EIP-3198: BASEFEE opcode 41 | pub fn basefee(evm: &mut EVM) { 42 | gas!(evm, gas::BASE); 43 | try_push!(evm, evm.sdk.context().block_base_fee()); 44 | } 45 | 46 | pub fn origin(evm: &mut EVM) { 47 | gas!(evm, gas::BASE); 48 | push_b256!(evm, evm.sdk.context().tx_origin().into_word()); 49 | } 50 | 51 | // EIP-4844: Shard Blob Transactions 52 | pub fn blob_hash(evm: &mut EVM) { 53 | gas!(evm, gas::VERY_LOW); 54 | pop_top!(evm, index); 55 | let _i = as_usize_saturated!(index); 56 | // TODO(dmitry123): "we don't support blob hashes" 57 | *index = U256::ZERO; 58 | } 59 | 60 | /// EIP-7516: BLOBBASEFEE opcode 61 | pub fn blob_basefee(evm: &mut EVM) { 62 | gas!(evm, gas::BASE); 63 | push!(evm, evm.sdk.context().block_base_fee()); 64 | } 65 | -------------------------------------------------------------------------------- /crates/evm/src/evm/memory.rs: -------------------------------------------------------------------------------- 1 | use crate::{as_usize_or_fail, gas, gas_or_fail, pop, pop_top, push, resize_memory, EVM}; 2 | use core::cmp::max; 3 | use fluentbase_sdk::{SharedAPI, U256}; 4 | 5 | pub fn mload(evm: &mut EVM) { 6 | gas!(evm, gas::VERY_LOW); 7 | pop_top!(evm, top); 8 | let offset = as_usize_or_fail!(evm, top); 9 | resize_memory!(evm, offset, 32); 10 | *top = evm.memory.get_u256(offset); 11 | } 12 | 13 | pub fn mstore(evm: &mut EVM) { 14 | gas!(evm, gas::VERY_LOW); 15 | pop!(evm, offset, value); 16 | let offset = as_usize_or_fail!(evm, offset); 17 | resize_memory!(evm, offset, 32); 18 | evm.memory.set_u256(offset, value); 19 | } 20 | 21 | pub fn mstore8(evm: &mut EVM) { 22 | gas!(evm, gas::VERY_LOW); 23 | pop!(evm, offset, value); 24 | let offset = as_usize_or_fail!(evm, offset); 25 | resize_memory!(evm, offset, 1); 26 | evm.memory.set_byte(offset, value.byte(0)) 27 | } 28 | 29 | pub fn msize(evm: &mut EVM) { 30 | gas!(evm, gas::BASE); 31 | push!(evm, U256::from(evm.memory.len())); 32 | } 33 | 34 | // EIP-5656: MCOPY - Memory copying instruction 35 | pub fn mcopy(evm: &mut EVM) { 36 | pop!(evm, dst, src, len); 37 | // into usize or fail 38 | let len = as_usize_or_fail!(evm, len); 39 | // deduce gas 40 | gas_or_fail!(evm, gas::verylowcopy_cost(len as u64)); 41 | if len == 0 { 42 | return; 43 | } 44 | let dst = as_usize_or_fail!(evm, dst); 45 | let src = as_usize_or_fail!(evm, src); 46 | // resize memory 47 | resize_memory!(evm, max(dst, src), len); 48 | // copy memory in place 49 | evm.memory.copy(dst, src, len); 50 | } 51 | -------------------------------------------------------------------------------- /crates/evm/src/evm/stack.rs: -------------------------------------------------------------------------------- 1 | use crate::{gas, EVM}; 2 | use fluentbase_sdk::{SharedAPI, U256}; 3 | 4 | pub fn pop(evm: &mut EVM) { 5 | gas!(evm, gas::BASE); 6 | if let Err(result) = evm.stack.pop() { 7 | evm.state = result; 8 | } 9 | } 10 | 11 | /// EIP-3855: PUSH0 instruction 12 | /// 13 | /// Introduce a new instruction which pushes the constant value 0 onto the stack. 14 | pub fn push0(evm: &mut EVM) { 15 | gas!(evm, gas::BASE); 16 | if let Err(result) = evm.stack.push(U256::ZERO) { 17 | evm.state = result; 18 | } 19 | } 20 | 21 | pub fn push(evm: &mut EVM) { 22 | gas!(evm, gas::VERY_LOW); 23 | // SAFETY: In analysis, we append trailing bytes to the bytecode so that this is safe to do 24 | // without bounds checking. 25 | let ip = evm.ip; 26 | if let Err(result) = evm 27 | .stack 28 | .push_slice(unsafe { core::slice::from_raw_parts(ip, N) }) 29 | { 30 | evm.state = result; 31 | return; 32 | } 33 | evm.ip = unsafe { ip.add(N) }; 34 | } 35 | 36 | pub fn dup(evm: &mut EVM) { 37 | gas!(evm, gas::VERY_LOW); 38 | if let Err(result) = evm.stack.dup(N) { 39 | evm.state = result; 40 | } 41 | } 42 | 43 | pub fn swap(evm: &mut EVM) { 44 | gas!(evm, gas::VERY_LOW); 45 | if let Err(result) = evm.stack.swap(N) { 46 | evm.state = result; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /crates/evm/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(feature = "std"), no_std)] 2 | #![allow(dead_code)] 3 | 4 | pub mod bytecode; 5 | pub mod evm; 6 | pub mod gas; 7 | pub mod macros; 8 | pub mod memory; 9 | pub mod result; 10 | pub mod stack; 11 | pub mod utils; 12 | 13 | pub use evm::EVM; 14 | 15 | extern crate alloc; 16 | extern crate core; 17 | 18 | /// Number of block hashes that EVM can access in the past (pre-Prague). 19 | pub const BLOCK_HASH_HISTORY: u64 = 256; 20 | -------------------------------------------------------------------------------- /crates/runtime/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fluentbase-runtime" 3 | version = "0.1.0" 4 | authors.workspace = true 5 | repository.workspace = true 6 | edition.workspace = true 7 | readme.workspace = true 8 | license.workspace = true 9 | keywords.workspace = true 10 | categories.workspace = true 11 | 12 | [dependencies] 13 | # fluentbase 14 | fluentbase-codec = { workspace = true } 15 | fluentbase-types = { workspace = true } 16 | fluentbase-genesis = { workspace = true, optional = true } 17 | 18 | rwasm = { workspace = true } 19 | 20 | # misc 21 | k256 = { version = "0.13.1", default-features = false, features = ["ecdsa"] } 22 | secp256k1 = { version = ">=0.28, <=0.29", default-features = false, features = [ 23 | "alloc", 24 | "recovery", 25 | "rand", 26 | "global-context", 27 | ] } 28 | hashbrown = { workspace = true } 29 | hex = { version = "0.4.3", optional = true } 30 | tiny-keccak = { version = "2.0.2", features = ["keccak"] } 31 | num = "0.4.3" 32 | sp1-curves = { version = "4.1.0" } 33 | sp1-primitives = { version = "4.1.0" } 34 | wasmtime = { workspace = true, optional = true } 35 | anyhow = { version = "1.0.97", optional = true } 36 | ctor = { version = "0.4.1", optional = true } 37 | 38 | [dev-dependencies] 39 | sha2 = { version = "0.10.8" } 40 | wat = { version = "1.0.69" } 41 | hex-literal = { workspace = true } 42 | 43 | [features] 44 | default = ["std"] 45 | std = [ 46 | "rwasm/std", 47 | ] 48 | rwasm = [] 49 | debug-print = [ 50 | "dep:hex" 51 | ] 52 | optimism = ["fluentbase-types/optimism"] 53 | wasmtime = ["dep:wasmtime", "dep:ctor", "dep:anyhow", "dep:fluentbase-genesis"] 54 | -------------------------------------------------------------------------------- /crates/runtime/src/instruction/charge_fuel.rs: -------------------------------------------------------------------------------- 1 | use crate::RuntimeContext; 2 | use rwasm::{Caller, RwasmError}; 3 | 4 | pub struct SyscallChargeFuel; 5 | 6 | impl SyscallChargeFuel { 7 | pub fn fn_handler(mut caller: Caller<'_, RuntimeContext>) -> Result<(), RwasmError> { 8 | let fuel_consumed: u64 = caller.stack_pop_as(); 9 | println!("ChargeFuel: fuel_consumed={}", fuel_consumed); 10 | caller.vm_mut().try_consume_fuel(fuel_consumed)?; 11 | Ok(()) 12 | } 13 | 14 | pub fn fn_impl(ctx: &mut RuntimeContext, fuel_consumed: u64) { 15 | ctx.try_consume_fuel(fuel_consumed).unwrap(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /crates/runtime/src/instruction/charge_fuel_manually.rs: -------------------------------------------------------------------------------- 1 | use crate::RuntimeContext; 2 | use rwasm::{Caller, RwasmError}; 3 | 4 | pub struct SyscallChargeFuelManually; 5 | 6 | impl SyscallChargeFuelManually { 7 | pub fn fn_handler(mut caller: Caller<'_, RuntimeContext>) -> Result<(), RwasmError> { 8 | // this method is allowed only in manual fuel mode that is possible with disabled fuel 9 | if !caller.context().disable_fuel { 10 | return Err(RwasmError::NotAllowedInFuelMode); 11 | } 12 | let fuel_refunded: i64 = caller.stack_pop_as(); 13 | let fuel_consumed: u64 = caller.stack_pop_as(); 14 | println!( 15 | "ChargeFuelManually: fuel_consumed={}, fuel_refunded={}", 16 | fuel_consumed, fuel_refunded 17 | ); 18 | caller.vm_mut().try_consume_fuel(fuel_consumed)?; 19 | caller.vm_mut().refund_fuel(fuel_refunded); 20 | let remaining_fuel = caller.vm().remaining_fuel().unwrap_or(u64::MAX); 21 | caller.stack_push(remaining_fuel); 22 | Ok(()) 23 | } 24 | 25 | pub fn fn_impl(ctx: &mut RuntimeContext, fuel_consumed: u64, fuel_refunded: i64) -> u64 { 26 | ctx.try_consume_fuel(fuel_consumed).unwrap(); 27 | ctx.refund_fuel(fuel_refunded); 28 | ctx.remaining_fuel() 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /crates/runtime/src/instruction/debug_log.rs: -------------------------------------------------------------------------------- 1 | use crate::RuntimeContext; 2 | use core::cell::Cell; 3 | use rwasm::{Caller, RwasmError}; 4 | 5 | pub struct SyscallDebugLog; 6 | 7 | thread_local! { 8 | pub static LAST_LOG_TIME: Cell = const { Cell::new(0) }; 9 | } 10 | 11 | impl SyscallDebugLog { 12 | pub fn fn_handler(mut caller: Caller<'_, RuntimeContext>) -> Result<(), RwasmError> { 13 | let [message_ptr, message_len] = caller.stack_pop_n(); 14 | let mut buffer = vec![0u8; message_len.as_usize()]; 15 | caller.memory_read(message_ptr.as_usize(), &mut buffer)?; 16 | Self::fn_impl(&buffer); 17 | Ok(()) 18 | } 19 | 20 | #[cfg(feature = "debug-print")] 21 | pub fn fn_impl(msg: &[u8]) { 22 | use std::time::SystemTime; 23 | let curr_time = SystemTime::now() 24 | .duration_since(SystemTime::UNIX_EPOCH) 25 | .unwrap() 26 | .as_millis() as i64; 27 | let last_time = LAST_LOG_TIME.get(); 28 | let time_diff = if last_time > 0 { 29 | curr_time - last_time 30 | } else { 31 | 0 32 | }; 33 | LAST_LOG_TIME.set(curr_time); 34 | const MSG_LIMIT: usize = 100; 35 | let msg = if msg.len() > MSG_LIMIT { 36 | &msg[..MSG_LIMIT] 37 | } else { 38 | &msg[..] 39 | }; 40 | println!( 41 | "debug_log (diff {}ms): {}", 42 | time_diff, 43 | std::str::from_utf8(msg) 44 | .map(|s| s.to_string()) 45 | .unwrap_or_else(|_| { hex::encode(msg) }) 46 | ); 47 | } 48 | 49 | #[cfg(not(feature = "debug-print"))] 50 | pub fn fn_impl(_msg: &[u8]) {} 51 | } 52 | -------------------------------------------------------------------------------- /crates/runtime/src/instruction/ed_add.rs: -------------------------------------------------------------------------------- 1 | use crate::{instruction::cast_u8_to_u32, RuntimeContext}; 2 | use k256::elliptic_curve::generic_array::typenum::Unsigned; 3 | use rwasm::{Caller, RwasmError}; 4 | use sp1_curves::{edwards::EdwardsParameters, params::NumWords, AffinePoint, EllipticCurve}; 5 | use std::marker::PhantomData; 6 | 7 | pub(crate) struct SyscallEdwardsAddAssign { 8 | _phantom: PhantomData, 9 | } 10 | 11 | impl SyscallEdwardsAddAssign { 12 | /// Create a new instance of the [`SyscallEdwardsAddAssign`]. 13 | pub const fn new() -> Self { 14 | Self { 15 | _phantom: PhantomData, 16 | } 17 | } 18 | } 19 | 20 | impl SyscallEdwardsAddAssign { 21 | pub fn fn_handler(mut caller: Caller<'_, RuntimeContext>) -> Result<(), RwasmError> { 22 | let (p_ptr, q_ptr) = caller.stack_pop2_as::(); 23 | 24 | let num_words = ::WordsCurvePoint::USIZE; 25 | 26 | let p = caller.memory_read_vec(p_ptr as usize, num_words * 4)?; 27 | let q = caller.memory_read_vec(q_ptr as usize, num_words * 4)?; 28 | 29 | let result_vec = Self::fn_impl(&p, &q); 30 | 31 | caller.memory_write(p_ptr as usize, &result_vec)?; 32 | 33 | Ok(()) 34 | } 35 | 36 | pub fn fn_impl(p: &[u8], q: &[u8]) -> Vec { 37 | let p = cast_u8_to_u32(p).unwrap(); 38 | let q = cast_u8_to_u32(q).unwrap(); 39 | 40 | let p_affine = AffinePoint::::from_words_le(p); 41 | let q_affine = AffinePoint::::from_words_le(q); 42 | let result_affine = p_affine + q_affine; 43 | 44 | let result_words = result_affine.to_words_le(); 45 | result_words 46 | .into_iter() 47 | .map(|x| x.to_be_bytes()) 48 | .flatten() 49 | .collect::>() 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /crates/runtime/src/instruction/ed_decompress.rs: -------------------------------------------------------------------------------- 1 | use crate::RuntimeContext; 2 | use fluentbase_types::ExitCode; 3 | use rwasm::{Caller, RwasmError}; 4 | use sp1_curves::{ 5 | curve25519_dalek::CompressedEdwardsY, 6 | edwards::{ed25519::decompress, EdwardsParameters, WORDS_FIELD_ELEMENT}, 7 | COMPRESSED_POINT_BYTES, 8 | }; 9 | use std::marker::PhantomData; 10 | 11 | pub(crate) struct SyscallEdwardsDecompress { 12 | _phantom: PhantomData, 13 | } 14 | 15 | impl SyscallEdwardsDecompress { 16 | /// Create a new instance of the [`SyscallEdwardsDecompress`]. 17 | pub const fn new() -> Self { 18 | Self { 19 | _phantom: PhantomData, 20 | } 21 | } 22 | 23 | #[allow(clippy::many_single_char_names)] 24 | pub fn fn_handler(mut caller: Caller<'_, RuntimeContext>) -> Result<(), RwasmError> { 25 | let (slice_ptr, sign) = caller.stack_pop2(); 26 | // Read the Y bytes from memory 27 | let y_bytes = caller 28 | .memory_read_fixed::<{ WORDS_FIELD_ELEMENT * 4 }>( 29 | slice_ptr.as_usize() + COMPRESSED_POINT_BYTES, 30 | )? 31 | .try_into() 32 | .unwrap(); 33 | let result_vec = Self::fn_impl(y_bytes, sign.as_u32()) 34 | .map_err(|err| RwasmError::ExecutionHalted(err.into_i32()))?; 35 | // Write the decompressed X back to memory 36 | caller.memory_write(slice_ptr.as_usize(), &result_vec)?; 37 | Ok(()) 38 | } 39 | 40 | pub fn fn_impl(mut y_bytes: [u8; 32], sign: u32) -> Result, ExitCode> { 41 | if sign > 1 { 42 | return Err(ExitCode::MalformedBuiltinParams); 43 | } 44 | 45 | // Copy bytes into another array so we can modify the last byte and make CompressedEdwardsY 46 | y_bytes[COMPRESSED_POINT_BYTES - 1] &= 0b0111_1111; 47 | y_bytes[COMPRESSED_POINT_BYTES - 1] |= (sign as u8) << 7; 48 | 49 | // Compute actual decompressed X 50 | let compressed_y = CompressedEdwardsY(y_bytes); 51 | let decompressed = decompress(&compressed_y).ok_or(ExitCode::MalformedBuiltinParams)?; 52 | 53 | // Convert the decompressed X to bytes and then words 54 | let mut decompressed_x_bytes = decompressed.x.to_bytes_le(); 55 | decompressed_x_bytes.resize(32, 0u8); // Ensure it has the correct size 56 | 57 | Ok(decompressed_x_bytes) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /crates/runtime/src/instruction/exit.rs: -------------------------------------------------------------------------------- 1 | use crate::RuntimeContext; 2 | use fluentbase_types::ExitCode; 3 | use rwasm::{Caller, RwasmError}; 4 | 5 | pub struct SyscallExit; 6 | 7 | impl SyscallExit { 8 | pub fn fn_handler(mut caller: Caller<'_, RuntimeContext>) -> Result<(), RwasmError> { 9 | let exit_code: i32 = caller.stack_pop_as(); 10 | let exit_code = Self::fn_impl(caller.context_mut(), exit_code).unwrap_err(); 11 | Err(RwasmError::ExecutionHalted(exit_code.into_i32())) 12 | } 13 | 14 | pub fn fn_impl(ctx: &mut RuntimeContext, exit_code: i32) -> Result<(), ExitCode> { 15 | if exit_code > 0 { 16 | return Err(ExitCode::NonNegativeExitCode); 17 | } 18 | ctx.execution_result.exit_code = exit_code; 19 | Err(ExitCode::Ok) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /crates/runtime/src/instruction/forward_output.rs: -------------------------------------------------------------------------------- 1 | use crate::RuntimeContext; 2 | use fluentbase_types::ExitCode; 3 | use rwasm::{Caller, RwasmError}; 4 | 5 | pub struct SyscallForwardOutput; 6 | 7 | impl SyscallForwardOutput { 8 | pub fn fn_handler(mut caller: Caller<'_, RuntimeContext>) -> Result<(), RwasmError> { 9 | let (offset, length) = caller.stack_pop2(); 10 | Self::fn_impl(&mut caller.context_mut(), offset.as_u32(), length.as_u32()) 11 | .map_err(|err| RwasmError::ExecutionHalted(err.into_i32()))?; 12 | Ok(()) 13 | } 14 | 15 | pub fn fn_impl(ctx: &mut RuntimeContext, offset: u32, len: u32) -> Result<(), ExitCode> { 16 | if offset + len <= ctx.execution_result.return_data.len() as u32 { 17 | let ret_data = &ctx.execution_result.return_data 18 | [(offset as usize)..(offset as usize + len as usize)]; 19 | ctx.execution_result.output.extend_from_slice(ret_data); 20 | Ok(()) 21 | } else { 22 | Err(ExitCode::MemoryOutOfBounds) 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /crates/runtime/src/instruction/fp2_addsub.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | instruction::{cast_u8_to_u32, FieldOp2}, 3 | RuntimeContext, 4 | }; 5 | use k256::elliptic_curve::generic_array::typenum::Unsigned; 6 | use num::BigUint; 7 | use rwasm::{Caller, RwasmError}; 8 | use sp1_curves::{params::NumWords, weierstrass::FpOpField}; 9 | use sp1_primitives::consts::words_to_bytes_le_vec; 10 | use std::marker::PhantomData; 11 | 12 | pub struct SyscallFp2AddSub { 13 | _op: PhantomData, 14 | _marker: PhantomData

, 15 | } 16 | 17 | impl SyscallFp2AddSub { 18 | pub fn fn_handler(mut caller: Caller<'_, RuntimeContext>) -> Result<(), RwasmError> { 19 | let (x_ptr, y_ptr) = caller.stack_pop2_as::(); 20 | 21 | let num_words =

::WordsFieldElement::USIZE; 22 | 23 | let x = caller.memory_read_vec(x_ptr as usize, num_words * 4)?; 24 | let y = caller.memory_read_vec(y_ptr as usize, num_words * 4)?; 25 | 26 | let result_vec = Self::fn_impl(&x, &y); 27 | 28 | caller.memory_write(x_ptr as usize, &result_vec)?; 29 | 30 | Ok(()) 31 | } 32 | 33 | pub fn fn_impl(x: &[u8], y: &[u8]) -> Vec { 34 | let num_words =

::WordsFieldElement::USIZE; 35 | 36 | let x = cast_u8_to_u32(x).unwrap(); 37 | let y = cast_u8_to_u32(y).unwrap(); 38 | 39 | let (ac0, ac1) = x.split_at(x.len() / 2); 40 | let (bc0, bc1) = y.split_at(y.len() / 2); 41 | 42 | let ac0 = &BigUint::from_slice(ac0); 43 | let ac1 = &BigUint::from_slice(ac1); 44 | let bc0 = &BigUint::from_slice(bc0); 45 | let bc1 = &BigUint::from_slice(bc1); 46 | let modulus = &BigUint::from_bytes_le(P::MODULUS); 47 | 48 | let (c0, c1) = OP::execute(ac0, ac1, bc0, bc1, modulus); 49 | 50 | let mut result = c0 51 | .to_u32_digits() 52 | .into_iter() 53 | .chain(c1.to_u32_digits()) 54 | .collect::>(); 55 | result.resize(num_words, 0); 56 | 57 | words_to_bytes_le_vec(result.as_slice()) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /crates/runtime/src/instruction/fp2_mul.rs: -------------------------------------------------------------------------------- 1 | use crate::{instruction::cast_u8_to_u32, RuntimeContext}; 2 | use k256::elliptic_curve::generic_array::typenum::Unsigned; 3 | use num::BigUint; 4 | use rwasm::{Caller, RwasmError}; 5 | use sp1_curves::{params::NumWords, weierstrass::FpOpField}; 6 | use sp1_primitives::consts::words_to_bytes_le_vec; 7 | use std::marker::PhantomData; 8 | 9 | pub struct SyscallFp2Mul

{ 10 | _marker: PhantomData

, 11 | } 12 | 13 | impl SyscallFp2Mul

{ 14 | pub fn fn_handler(mut caller: Caller<'_, RuntimeContext>) -> Result<(), RwasmError> { 15 | let (x_ptr, y_ptr) = caller.stack_pop2_as::(); 16 | 17 | let num_words =

::WordsFieldElement::USIZE; 18 | 19 | let x = caller.memory_read_vec(x_ptr as usize, num_words * 4)?; 20 | let y = caller.memory_read_vec(y_ptr as usize, num_words * 4)?; 21 | 22 | let result_vec = Self::fn_impl(&x, &y); 23 | caller.memory_write(x_ptr as usize, &result_vec)?; 24 | 25 | Ok(()) 26 | } 27 | 28 | pub fn fn_impl(x: &[u8], y: &[u8]) -> Vec { 29 | let num_words =

::WordsFieldElement::USIZE; 30 | 31 | let x = cast_u8_to_u32(x).unwrap(); 32 | let y = cast_u8_to_u32(y).unwrap(); 33 | 34 | let (ac0, ac1) = x.split_at(x.len() / 2); 35 | let (bc0, bc1) = y.split_at(y.len() / 2); 36 | 37 | let ac0 = &BigUint::from_slice(ac0); 38 | let ac1 = &BigUint::from_slice(ac1); 39 | let bc0 = &BigUint::from_slice(bc0); 40 | let bc1 = &BigUint::from_slice(bc1); 41 | let modulus = &BigUint::from_bytes_le(P::MODULUS); 42 | 43 | #[allow(clippy::match_bool)] 44 | let c0 = match (ac0 * bc0) % modulus < (ac1 * bc1) % modulus { 45 | true => ((modulus + (ac0 * bc0) % modulus) - (ac1 * bc1) % modulus) % modulus, 46 | false => ((ac0 * bc0) % modulus - (ac1 * bc1) % modulus) % modulus, 47 | }; 48 | let c1 = ((ac0 * bc1) % modulus + (ac1 * bc0) % modulus) % modulus; 49 | 50 | let mut result = c0 51 | .to_u32_digits() 52 | .into_iter() 53 | .chain(c1.to_u32_digits()) 54 | .collect::>(); 55 | result.resize(num_words, 0); 56 | 57 | words_to_bytes_le_vec(result.as_slice()) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /crates/runtime/src/instruction/fp_op.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | instruction::{cast_u8_to_u32, FieldOp}, 3 | RuntimeContext, 4 | }; 5 | use k256::elliptic_curve::generic_array::typenum::Unsigned; 6 | use num::BigUint; 7 | use rwasm::{Caller, RwasmError}; 8 | use sp1_curves::{params::NumWords, weierstrass::FpOpField}; 9 | use sp1_primitives::consts::words_to_bytes_le_vec; 10 | use std::marker::PhantomData; 11 | 12 | pub struct SyscallFpOp { 13 | _op: PhantomData, 14 | _marker: PhantomData

, 15 | } 16 | 17 | impl SyscallFpOp { 18 | pub fn fn_handler(mut caller: Caller<'_, RuntimeContext>) -> Result<(), RwasmError> { 19 | let (x_ptr, y_ptr) = caller.stack_pop2_as::(); 20 | 21 | let num_words =

::WordsFieldElement::USIZE; 22 | 23 | let x = caller.memory_read_vec(x_ptr as usize, num_words * 4)?; 24 | let y = caller.memory_read_vec(y_ptr as usize, num_words * 4)?; 25 | 26 | let result_vec = Self::fn_impl(&x, &y); 27 | caller.memory_write(x_ptr as usize, &result_vec)?; 28 | 29 | Ok(()) 30 | } 31 | 32 | pub fn fn_impl(x: &[u8], y: &[u8]) -> Vec { 33 | let num_words =

::WordsFieldElement::USIZE; 34 | 35 | let x = cast_u8_to_u32(x).unwrap(); 36 | let y = cast_u8_to_u32(y).unwrap(); 37 | 38 | let modulus = &BigUint::from_bytes_le(P::MODULUS); 39 | let a = BigUint::from_slice(&x) % modulus; 40 | let b = BigUint::from_slice(&y) % modulus; 41 | 42 | let result = OP::execute(a, b, modulus); 43 | 44 | let mut result = result.to_u32_digits(); 45 | result.resize(num_words, 0); 46 | 47 | words_to_bytes_le_vec(result.as_slice()) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /crates/runtime/src/instruction/fuel.rs: -------------------------------------------------------------------------------- 1 | use crate::RuntimeContext; 2 | use rwasm::{Caller, RwasmError}; 3 | 4 | pub struct SyscallFuel; 5 | 6 | impl SyscallFuel { 7 | pub fn fn_handler(mut caller: Caller<'_, RuntimeContext>) -> Result<(), RwasmError> { 8 | let fuel_remaining = caller.vm().remaining_fuel().unwrap_or(u64::MAX); 9 | caller.stack_push(fuel_remaining); 10 | Ok(()) 11 | } 12 | 13 | pub fn fn_impl(ctx: &RuntimeContext) -> u64 { 14 | ctx.remaining_fuel() 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /crates/runtime/src/instruction/input_size.rs: -------------------------------------------------------------------------------- 1 | use crate::RuntimeContext; 2 | use rwasm::{Caller, RwasmError}; 3 | 4 | pub struct SyscallInputSize; 5 | 6 | impl SyscallInputSize { 7 | pub fn fn_handler(mut caller: Caller<'_, RuntimeContext>) -> Result<(), RwasmError> { 8 | let input_size = Self::fn_impl(caller.context()); 9 | caller.stack_push(input_size); 10 | Ok(()) 11 | } 12 | 13 | pub fn fn_impl(ctx: &RuntimeContext) -> u32 { 14 | ctx.input_size() 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /crates/runtime/src/instruction/keccak256.rs: -------------------------------------------------------------------------------- 1 | use crate::RuntimeContext; 2 | use fluentbase_types::{keccak256, B256}; 3 | use rwasm::{Caller, RwasmError}; 4 | 5 | pub struct SyscallKeccak256; 6 | 7 | impl SyscallKeccak256 { 8 | pub fn fn_handler(mut caller: Caller<'_, RuntimeContext>) -> Result<(), RwasmError> { 9 | let [data_offset, data_len, output_offset] = caller.stack_pop_n(); 10 | let data = caller.memory_read_vec(data_offset.as_usize(), data_len.as_usize())?; 11 | caller.memory_write(output_offset.as_usize(), Self::fn_impl(&data).as_slice())?; 12 | Ok(()) 13 | } 14 | 15 | pub fn fn_impl(data: &[u8]) -> B256 { 16 | keccak256(data) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /crates/runtime/src/instruction/keccak256_permute.rs: -------------------------------------------------------------------------------- 1 | use crate::RuntimeContext; 2 | use rwasm::{Caller, RwasmError}; 3 | use tiny_keccak::keccakf; 4 | 5 | pub(crate) const STATE_SIZE: u32 = 25; 6 | 7 | // The permutation state is 25 u64's. Our word size is 32 bits, so it is 50 words. 8 | pub const STATE_NUM_WORDS: u32 = STATE_SIZE * 2; 9 | 10 | pub struct SyscallKeccak256Permute; 11 | 12 | impl SyscallKeccak256Permute { 13 | pub fn fn_handler(mut caller: Caller<'_, RuntimeContext>) -> Result<(), RwasmError> { 14 | let state_ptr: u32 = caller.stack_pop_as(); 15 | let state = caller.memory_read_fixed::<{ STATE_NUM_WORDS as usize }>(state_ptr as usize)?; 16 | 17 | let result = Self::fn_impl(&state); 18 | caller.memory_write(state_ptr as usize, &result)?; 19 | 20 | Ok(()) 21 | } 22 | 23 | pub fn fn_impl(state: &[u8]) -> Vec { 24 | let mut state_result = Vec::new(); 25 | for values in state.chunks_exact(2) { 26 | let least_sig = values[0]; 27 | let most_sig = values[1]; 28 | state_result.push(least_sig as u64 + ((most_sig as u64) << 32)); 29 | } 30 | let mut state = state_result.try_into().unwrap(); 31 | keccakf(&mut state); 32 | let mut values_to_write = Vec::new(); 33 | for i in 0..STATE_SIZE { 34 | let most_sig = ((state[i as usize] >> 32) & 0xFFFFFFFF) as u32; 35 | let least_sig = (state[i as usize] & 0xFFFFFFFF) as u32; 36 | values_to_write.push(least_sig); 37 | values_to_write.push(most_sig); 38 | } 39 | values_to_write 40 | .into_iter() 41 | .map(|x| x.to_be_bytes()) 42 | .flatten() 43 | .collect::>() 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /crates/runtime/src/instruction/output_size.rs: -------------------------------------------------------------------------------- 1 | use crate::RuntimeContext; 2 | use rwasm::{Caller, RwasmError}; 3 | 4 | pub struct SyscallOutputSize; 5 | 6 | impl SyscallOutputSize { 7 | pub fn fn_handler(mut caller: Caller<'_, RuntimeContext>) -> Result<(), RwasmError> { 8 | let output_size = Self::fn_impl(caller.context()); 9 | caller.stack_push(output_size); 10 | Ok(()) 11 | } 12 | 13 | pub fn fn_impl(ctx: &RuntimeContext) -> u32 { 14 | ctx.execution_result.return_data.len() as u32 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /crates/runtime/src/instruction/preimage_copy.rs: -------------------------------------------------------------------------------- 1 | use crate::RuntimeContext; 2 | use fluentbase_types::Bytes; 3 | use rwasm::{Caller, RwasmError}; 4 | 5 | pub struct SyscallPreimageCopy; 6 | 7 | impl SyscallPreimageCopy { 8 | pub fn fn_handler(mut caller: Caller<'_, RuntimeContext>) -> Result<(), RwasmError> { 9 | let (hash32_ptr, preimage_ptr) = caller.stack_pop2_as::(); 10 | let hash = caller.memory_read_fixed::<32>(hash32_ptr as usize)?; 11 | let preimage = Self::fn_impl(caller.context_mut(), &hash)?; 12 | caller.memory_write(preimage_ptr as usize, preimage.as_ref())?; 13 | Ok(()) 14 | } 15 | 16 | pub fn fn_impl(_ctx: &RuntimeContext, _hash: &[u8]) -> Result { 17 | Err(RwasmError::UnreachableCodeReached) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /crates/runtime/src/instruction/preimage_size.rs: -------------------------------------------------------------------------------- 1 | use crate::RuntimeContext; 2 | use rwasm::{Caller, RwasmError}; 3 | 4 | pub struct SyscallPreimageSize; 5 | 6 | impl SyscallPreimageSize { 7 | pub fn fn_handler(mut caller: Caller<'_, RuntimeContext>) -> Result<(), RwasmError> { 8 | let hash32_offset: u32 = caller.stack_pop_as(); 9 | let hash = caller 10 | .memory_read_fixed::<32>(hash32_offset as usize)? 11 | .to_vec(); 12 | let preimage_size = Self::fn_impl(caller.context_mut(), &hash)?; 13 | caller.stack_push(preimage_size); 14 | Ok(()) 15 | } 16 | 17 | pub fn fn_impl(_ctx: &RuntimeContext, _hash: &[u8]) -> Result { 18 | Err(RwasmError::UnreachableCodeReached) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /crates/runtime/src/instruction/read.rs: -------------------------------------------------------------------------------- 1 | use crate::RuntimeContext; 2 | use fluentbase_types::ExitCode; 3 | use rwasm::{Caller, RwasmError}; 4 | 5 | pub struct SyscallRead; 6 | 7 | impl SyscallRead { 8 | pub fn fn_handler(mut caller: Caller<'_, RuntimeContext>) -> Result<(), RwasmError> { 9 | let [target_ptr, offset, length] = caller.stack_pop_n(); 10 | let input = Self::fn_impl(caller.context(), offset.as_u32(), length.as_u32())?; 11 | let _ = caller.memory_write(target_ptr.as_usize(), &input)?; 12 | Ok(()) 13 | } 14 | 15 | pub fn fn_impl(ctx: &RuntimeContext, offset: u32, length: u32) -> Result, RwasmError> { 16 | if offset + length <= ctx.input.len() as u32 { 17 | Ok(ctx.input[(offset as usize)..(offset as usize + length as usize)].to_vec()) 18 | } else { 19 | Err(RwasmError::ExecutionHalted( 20 | ExitCode::InputOutputOutOfBounds.into_i32(), 21 | )) 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /crates/runtime/src/instruction/read_output.rs: -------------------------------------------------------------------------------- 1 | use crate::RuntimeContext; 2 | use fluentbase_types::ExitCode; 3 | use rwasm::{Caller, RwasmError}; 4 | 5 | pub struct SyscallReadOutput; 6 | 7 | impl SyscallReadOutput { 8 | pub fn fn_handler(mut caller: Caller<'_, RuntimeContext>) -> Result<(), RwasmError> { 9 | let [target_ptr, offset, length] = caller.stack_pop_n(); 10 | let input = Self::fn_impl(caller.context(), offset.as_u32(), length.as_u32())?; 11 | let _ = caller.memory_write(target_ptr.as_usize(), &input)?; 12 | Ok(()) 13 | } 14 | 15 | pub fn fn_impl(ctx: &RuntimeContext, offset: u32, length: u32) -> Result, RwasmError> { 16 | if offset + length <= ctx.execution_result.return_data.len() as u32 { 17 | Ok(ctx.execution_result.return_data 18 | [(offset as usize)..(offset as usize + length as usize)] 19 | .to_vec()) 20 | } else { 21 | Err(RwasmError::ExecutionHalted( 22 | ExitCode::InputOutputOutOfBounds.into_i32(), 23 | )) 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /crates/runtime/src/instruction/sha256_extend.rs: -------------------------------------------------------------------------------- 1 | use crate::RuntimeContext; 2 | use rwasm::{Caller, RwasmError}; 3 | 4 | pub(crate) struct SyscallSha256Extend; 5 | 6 | impl SyscallSha256Extend { 7 | pub fn fn_handler(mut caller: Caller<'_, RuntimeContext>) -> Result<(), RwasmError> { 8 | let w_ptr: u32 = caller.stack_pop_as(); 9 | 10 | for i in 16..64 { 11 | // Read w[i-15]. 12 | let w_i_minus_15 = u32::from_be_bytes( 13 | caller 14 | .memory_read_fixed::<4>((w_ptr + (i - 15) * 4) as usize)? 15 | .try_into() 16 | .unwrap(), 17 | ); 18 | 19 | // Compute `s0`. 20 | let s0 = 21 | w_i_minus_15.rotate_right(7) ^ w_i_minus_15.rotate_right(18) ^ (w_i_minus_15 >> 3); 22 | 23 | // Read w[i-2]. 24 | let w_i_minus_2 = u32::from_be_bytes( 25 | caller 26 | .memory_read_fixed::<4>((w_ptr + (i - 2) * 4) as usize)? 27 | .try_into() 28 | .unwrap(), 29 | ); 30 | 31 | // Compute `s1`. 32 | let s1 = 33 | w_i_minus_2.rotate_right(17) ^ w_i_minus_2.rotate_right(19) ^ (w_i_minus_2 >> 10); 34 | 35 | // Read w[i-16]. 36 | let w_i_minus_16 = u32::from_be_bytes( 37 | caller 38 | .memory_read_fixed::<4>((w_ptr + (i - 16) * 4) as usize)? 39 | .try_into() 40 | .unwrap(), 41 | ); 42 | 43 | // Read w[i-7]. 44 | let w_i_minus_7 = u32::from_be_bytes( 45 | caller 46 | .memory_read_fixed::<4>((w_ptr + (i - 7) * 4) as usize)? 47 | .try_into() 48 | .unwrap(), 49 | ); 50 | 51 | // Compute `w_i`. 52 | let w_i = s1 53 | .wrapping_add(w_i_minus_16) 54 | .wrapping_add(s0) 55 | .wrapping_add(w_i_minus_7); 56 | 57 | caller.memory_write((w_ptr + i * 4) as usize, &w_i.to_be_bytes())?; 58 | } 59 | 60 | Ok(()) 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /crates/runtime/src/instruction/state.rs: -------------------------------------------------------------------------------- 1 | use crate::RuntimeContext; 2 | use rwasm::{Caller, RwasmError}; 3 | 4 | pub struct SyscallState; 5 | 6 | impl SyscallState { 7 | pub fn fn_handler(mut caller: Caller<'_, RuntimeContext>) -> Result<(), RwasmError> { 8 | let state = Self::fn_impl(caller.context()); 9 | caller.stack_push(state); 10 | Ok(()) 11 | } 12 | 13 | pub fn fn_impl(ctx: &RuntimeContext) -> u32 { 14 | ctx.state 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /crates/runtime/src/instruction/uint256_mul.rs: -------------------------------------------------------------------------------- 1 | use crate::RuntimeContext; 2 | use num::{BigUint, One, Zero}; 3 | use rwasm::{Caller, RwasmError}; 4 | use sp1_curves::edwards::WORDS_FIELD_ELEMENT; 5 | 6 | pub struct SyscallUint256Mul; 7 | 8 | impl SyscallUint256Mul { 9 | pub fn fn_handler(mut caller: Caller<'_, RuntimeContext>) -> Result<(), RwasmError> { 10 | let [x_ptr, y_ptr, m_ptr] = caller.stack_pop_n(); 11 | 12 | let x = caller.memory_read_fixed::(x_ptr.as_usize())?; 13 | let y = caller.memory_read_fixed::(y_ptr.as_usize())?; 14 | let m = caller.memory_read_fixed::(m_ptr.as_usize())?; 15 | 16 | let result_vec = Self::fn_impl(&x, &y, &m); 17 | caller.memory_write(x_ptr.as_usize(), &result_vec) 18 | } 19 | 20 | pub fn fn_impl(x: &[u8], y: &[u8], m: &[u8]) -> Vec { 21 | // Get the BigUint values for x, y, and the modulus. 22 | let uint256_x = BigUint::from_bytes_le(x); 23 | let uint256_y = BigUint::from_bytes_le(y); 24 | let uint256_m = BigUint::from_bytes_le(&m); 25 | 26 | // Perform the multiplication and take the result modulo the modulus. 27 | let result: BigUint = if uint256_m.is_zero() { 28 | let modulus = BigUint::one() << 256; 29 | (uint256_x * uint256_y) % modulus 30 | } else { 31 | (uint256_x * uint256_y) % uint256_m 32 | }; 33 | 34 | let mut result_bytes = result.to_bytes_le(); 35 | result_bytes.resize(32, 0u8); // Pad the result to 32 bytes. 36 | result_bytes 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /crates/runtime/src/instruction/weierstrass_add.rs: -------------------------------------------------------------------------------- 1 | use crate::{instruction::cast_u8_to_u32, RuntimeContext}; 2 | use k256::elliptic_curve::generic_array::typenum::Unsigned; 3 | use rwasm::{Caller, RwasmError}; 4 | use sp1_curves::{params::NumWords, AffinePoint, EllipticCurve}; 5 | use sp1_primitives::consts::words_to_bytes_le_vec; 6 | use std::marker::PhantomData; 7 | 8 | pub struct SyscallWeierstrassAddAssign { 9 | _phantom: PhantomData, 10 | } 11 | 12 | impl SyscallWeierstrassAddAssign { 13 | /// Create a new instance of the [`SyscallWeierstrassAddAssign`]. 14 | pub const fn new() -> Self { 15 | Self { 16 | _phantom: PhantomData, 17 | } 18 | } 19 | 20 | /// Handles the syscall for point addition on a Weierstrass curve. 21 | pub fn fn_handler(mut caller: Caller<'_, RuntimeContext>) -> Result<(), RwasmError> { 22 | let (p_ptr, q_ptr) = caller.stack_pop2_as::(); 23 | let num_words = ::WordsCurvePoint::USIZE; 24 | 25 | // Read p and q values from memory 26 | let p = caller.memory_read_vec(p_ptr as usize, num_words * 4)?; 27 | let q = caller.memory_read_vec(q_ptr as usize, num_words * 4)?; 28 | 29 | // Write the result back to memory at the p_ptr location 30 | let result_vec = Self::fn_impl(&p, &q); 31 | caller.memory_write(p_ptr as usize, &result_vec)?; 32 | 33 | Ok(()) 34 | } 35 | 36 | pub fn fn_impl(p: &[u8], q: &[u8]) -> Vec { 37 | let p = cast_u8_to_u32(p).unwrap(); 38 | let q = cast_u8_to_u32(q).unwrap(); 39 | 40 | // Convert memory to affine points 41 | let p_affine = AffinePoint::::from_words_le(&p); 42 | let q_affine = AffinePoint::::from_words_le(&q); 43 | 44 | // Perform point addition on the affine points 45 | let result_affine = p_affine + q_affine; 46 | 47 | // Convert the result back to memory format (LE words) 48 | let result_words = result_affine.to_words_le(); 49 | 50 | words_to_bytes_le_vec(result_words.as_slice()) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /crates/runtime/src/instruction/weierstrass_decompress.rs: -------------------------------------------------------------------------------- 1 | use crate::RuntimeContext; 2 | use fluentbase_types::ExitCode; 3 | use k256::elliptic_curve::generic_array::typenum::Unsigned; 4 | use rwasm::{Caller, RwasmError}; 5 | use sp1_curves::{ 6 | params::NumLimbs, 7 | weierstrass::{bls12_381::bls12381_decompress, secp256k1::secp256k1_decompress}, 8 | AffinePoint, 9 | CurveType, 10 | EllipticCurve, 11 | }; 12 | use sp1_primitives::consts::{bytes_to_words_le_vec, words_to_bytes_le_vec}; 13 | use std::marker::PhantomData; 14 | 15 | pub struct SyscallWeierstrassDecompressAssign { 16 | _phantom: PhantomData, 17 | } 18 | 19 | impl SyscallWeierstrassDecompressAssign { 20 | /// Create a new instance of the [`SyscallWeierstrassDecompressAssign`]. 21 | pub const fn new() -> Self { 22 | Self { 23 | _phantom: PhantomData, 24 | } 25 | } 26 | 27 | /// Handles the syscall for point addition on a Weierstrass curve. 28 | pub fn fn_handler(mut caller: Caller<'_, RuntimeContext>) -> Result<(), RwasmError> { 29 | let (x_ptr, sign_bit) = caller.stack_pop2_as::(); 30 | 31 | let num_limbs = ::Limbs::USIZE; 32 | let num_words_field_element = num_limbs / 4; 33 | 34 | let x_bytes = caller.memory_read_vec( 35 | (x_ptr + (num_limbs as u32)) as usize, 36 | num_words_field_element * 4, 37 | )?; 38 | 39 | let result_vec = Self::fn_impl(&x_bytes, sign_bit) 40 | .map_err(|err| RwasmError::ExecutionHalted(err.into_i32()))?; 41 | caller.memory_write(x_ptr as usize, &result_vec)?; 42 | 43 | Ok(()) 44 | } 45 | 46 | pub fn fn_impl(x_bytes: &[u8], sign_bit: u32) -> Result, ExitCode> { 47 | if sign_bit > 1 { 48 | return Err(ExitCode::MalformedBuiltinParams); 49 | } 50 | 51 | let num_limbs = ::Limbs::USIZE; 52 | 53 | let mut x_bytes_be = x_bytes.to_vec(); 54 | x_bytes_be.reverse(); 55 | 56 | let decompress_fn = match E::CURVE_TYPE { 57 | CurveType::Secp256k1 => secp256k1_decompress::, 58 | CurveType::Bls12381 => bls12381_decompress::, 59 | _ => panic!("unsupported curve"), 60 | }; 61 | 62 | let computed_point: AffinePoint = decompress_fn(&x_bytes_be, sign_bit); 63 | 64 | let mut decompressed_y_bytes = computed_point.y.to_bytes_le(); 65 | decompressed_y_bytes.resize(num_limbs, 0u8); 66 | let y_words = bytes_to_words_le_vec(&decompressed_y_bytes); 67 | 68 | let result_vec = words_to_bytes_le_vec(&y_words); 69 | Ok(result_vec) 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /crates/runtime/src/instruction/weierstrass_double.rs: -------------------------------------------------------------------------------- 1 | use crate::{instruction::cast_u8_to_u32, RuntimeContext}; 2 | use k256::elliptic_curve::generic_array::typenum::Unsigned; 3 | use rwasm::{Caller, RwasmError}; 4 | use sp1_curves::{params::NumWords, AffinePoint, EllipticCurve}; 5 | use sp1_primitives::consts::words_to_bytes_le_vec; 6 | use std::marker::PhantomData; 7 | 8 | pub struct SyscallWeierstrassDoubleAssign { 9 | _phantom: PhantomData, 10 | } 11 | 12 | impl SyscallWeierstrassDoubleAssign { 13 | /// Create a new instance of the [`SyscallWeierstrassDoubleAssign`]. 14 | pub const fn new() -> Self { 15 | Self { 16 | _phantom: PhantomData, 17 | } 18 | } 19 | 20 | /// Handles the syscall for point addition on a Weierstrass curve. 21 | pub fn fn_handler(mut caller: Caller<'_, RuntimeContext>) -> Result<(), RwasmError> { 22 | let p_ptr: u32 = caller.stack_pop_as(); 23 | 24 | let num_words = ::WordsCurvePoint::USIZE; 25 | let p = caller.memory_read_vec(p_ptr as usize, num_words * 4)?; 26 | 27 | let result_vec = Self::fn_impl(&p); 28 | caller.memory_write(p_ptr as usize, &result_vec)?; 29 | 30 | Ok(()) 31 | } 32 | 33 | pub fn fn_impl(p: &[u8]) -> Vec { 34 | let p = cast_u8_to_u32(p).unwrap(); 35 | let p_affine = AffinePoint::::from_words_le(&p); 36 | 37 | let result_affine = E::ec_double(&p_affine); 38 | let result_words = result_affine.to_words_le(); 39 | words_to_bytes_le_vec(result_words.as_slice()) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /crates/runtime/src/instruction/write.rs: -------------------------------------------------------------------------------- 1 | use crate::RuntimeContext; 2 | use rwasm::{Caller, RwasmError}; 3 | 4 | pub struct SyscallWrite; 5 | 6 | impl SyscallWrite { 7 | pub fn fn_handler(mut caller: Caller<'_, RuntimeContext>) -> Result<(), RwasmError> { 8 | let (offset, length) = caller.stack_pop2_as::(); 9 | let data = caller.memory_read_vec(offset as usize, length as usize)?; 10 | Self::fn_impl(caller.context_mut(), &data); 11 | Ok(()) 12 | } 13 | 14 | pub fn fn_impl(ctx: &mut RuntimeContext, data: &[u8]) { 15 | ctx.execution_result.output.extend_from_slice(data); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /crates/runtime/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code, unreachable_patterns, unused_macros)] 2 | #![warn(unused_crate_dependencies)] 3 | extern crate core; 4 | 5 | pub mod instruction; 6 | 7 | mod context; 8 | #[cfg(feature = "std")] 9 | mod context_wrapper; 10 | mod runtime; 11 | mod storage; 12 | #[cfg(test)] 13 | mod tests; 14 | mod utils; 15 | #[cfg(feature = "wasmtime")] 16 | mod wasmtime; 17 | 18 | pub use context::*; 19 | #[cfg(feature = "std")] 20 | pub use context_wrapper::*; 21 | pub use runtime::*; 22 | pub use storage::*; 23 | -------------------------------------------------------------------------------- /crates/runtime/src/storage.rs: -------------------------------------------------------------------------------- 1 | use fluentbase_types::{Bytes, ExitCode}; 2 | 3 | pub trait TrieStorage { 4 | fn open(&mut self, root32: &[u8]) -> bool; 5 | 6 | fn compute_root(&self) -> [u8; 32]; 7 | 8 | fn get(&self, key: &[u8]) -> Option<(Vec<[u8; 32]>, u32)>; 9 | 10 | fn update( 11 | &mut self, 12 | key: &[u8], 13 | value_flags: u32, 14 | value: &Vec<[u8; 32]>, 15 | ) -> Result<(), ExitCode>; 16 | 17 | fn remove(&mut self, key: &[u8]) -> Result<(), ExitCode>; 18 | 19 | fn proof(&self, key: &[u8; 32]) -> Option>>; 20 | 21 | fn get_preimage(&mut self, key: &[u8]) -> Option; 22 | 23 | fn preimage_size(&mut self, key: &[u8]) -> u32 { 24 | self.get_preimage(key) 25 | .map(|v| v.len() as u32) 26 | .unwrap_or_default() 27 | } 28 | 29 | fn update_preimage(&mut self, key: &[u8], value: Bytes); 30 | } 31 | -------------------------------------------------------------------------------- /crates/runtime/src/utils.rs: -------------------------------------------------------------------------------- 1 | use crate::{ExecutionResult, Runtime}; 2 | use fluentbase_types::ExitCode; 3 | 4 | pub(crate) fn trace_execution_logs(runtime: &Runtime, execution_result: &ExecutionResult) { 5 | let trace = runtime.executor.tracer().unwrap().logs.len(); 6 | println!("execution trace ({} steps):", trace); 7 | 8 | println!("EXEC, interrupted: {}", execution_result.interrupted); 9 | println!( 10 | "exit_code: {} ({})", 11 | execution_result.exit_code, 12 | ExitCode::from(execution_result.exit_code) 13 | ); 14 | println!( 15 | "output: 0x{} ({})", 16 | fluentbase_types::hex::encode(&execution_result.output), 17 | std::str::from_utf8(&execution_result.output).unwrap_or("can't decode utf-8") 18 | ); 19 | println!("fuel consumed: {}", execution_result.fuel_consumed); 20 | let logs = &runtime.executor.tracer().unwrap().logs; 21 | println!("execution trace ({} steps):", logs.len()); 22 | for log in logs.iter().rev().take(100).rev() { 23 | println!( 24 | " - pc={} opcode={:?} gas={} stack={:?}", 25 | log.program_counter, 26 | log.opcode, 27 | log.consumed_fuel, 28 | log.stack 29 | .iter() 30 | .map(|v| v.to_string()) 31 | .rev() 32 | .take(3) 33 | .rev() 34 | .collect::>(), 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /crates/sdk-derive/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors.workspace = true 3 | categories.workspace = true 4 | edition.workspace = true 5 | keywords.workspace = true 6 | license.workspace = true 7 | name = "fluentbase-sdk-derive" 8 | readme.workspace = true 9 | repository.workspace = true 10 | version = "0.1.0" 11 | 12 | [dependencies] 13 | crypto-hashes = { version = "0.10.0", default-features = false, features = ["include_weak"] } 14 | proc-macro2 = "1.0" 15 | proc-macro-error = { version = "1", default-features = false } 16 | quote = "1.0" 17 | fluentbase-sdk-derive-core = { path = "./derive-core", default-features = false } 18 | syn = { workspace = true, features = ["full", "visit"] } 19 | alloy-sol-macro-input = "1.1.0" 20 | 21 | [dev-dependencies] 22 | trybuild = "1.0.104" 23 | fluentbase-sdk = { workspace = true } 24 | 25 | [lib] 26 | proc-macro = true 27 | -------------------------------------------------------------------------------- /crates/sdk-derive/derive-core/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fluentbase-sdk-derive-core" 3 | 4 | authors.workspace = true 5 | categories.workspace = true 6 | edition.workspace = true 7 | keywords.workspace = true 8 | license.workspace = true 9 | 10 | readme.workspace = true 11 | repository.workspace = true 12 | 13 | [dependencies] 14 | alloy-sol-macro-input = "1.1.0" 15 | anyhow.workspace = true 16 | convert_case = "0.8.0" 17 | crypto-hashes = { version = "0.10.0", default-features = false, features = ["include_weak"] } 18 | darling = "0.20.10" 19 | fluentbase-codec = { workspace = true } 20 | hex = "0.4.3" 21 | proc-macro-error = { version = "1", default-features = false } 22 | proc-macro2 = "1.0" 23 | quote = "1.0" 24 | serde = { version = "1.0", default-features = false, features = ["derive"] } 25 | serde_json = "1.0" 26 | syn = { workspace = true, features = ["full", "visit"] } 27 | syn-solidity = { version = "1.1.0", default-features = false, features = ["visit"] } 28 | thiserror = "2.0.12" 29 | tracing = { version = "0.1.40", default-features = false } 30 | 31 | [dev-dependencies] 32 | bytes = "1.0" 33 | insta = { version = "1.43.1", features = ["yaml"] } 34 | prettyplease = "0.2.32" 35 | -------------------------------------------------------------------------------- /crates/sdk-derive/derive-core/src/abi/contract.rs: -------------------------------------------------------------------------------- 1 | use crate::abi::function::FunctionABI; 2 | use serde::{Deserialize, Serialize}; 3 | use std::collections::HashMap; 4 | 5 | /// Represents a stored ABI definition with metadata 6 | #[derive(Debug, Clone, Serialize, Deserialize)] 7 | pub struct ContractABI { 8 | pub id: String, 9 | pub functions: Vec, 10 | 11 | #[serde(default, skip_serializing_if = "HashMap::is_empty")] 12 | pub metadata: HashMap, 13 | } 14 | 15 | #[allow(dead_code)] 16 | impl ContractABI { 17 | pub fn new(id: impl Into) -> Self { 18 | Self { 19 | id: id.into(), 20 | functions: Vec::new(), 21 | metadata: HashMap::new(), 22 | } 23 | } 24 | 25 | #[must_use] 26 | pub fn with_function(mut self, function: FunctionABI) -> Self { 27 | self.functions.push(function); 28 | self 29 | } 30 | 31 | #[must_use] 32 | pub fn with_functions(mut self, functions: Vec) -> Self { 33 | self.functions.extend(functions); 34 | self 35 | } 36 | 37 | pub fn with_metadata(mut self, key: impl Into, value: impl Into) -> Self { 38 | self.metadata.insert(key.into(), value.into()); 39 | self 40 | } 41 | #[must_use] 42 | pub fn path(&self) -> String { 43 | self.id.replace("::", "/") 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /crates/sdk-derive/derive-core/src/abi/error.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, thiserror::Error)] 2 | pub enum ABIError { 3 | #[error("Invalid type: {0}")] 4 | InvalidType(String), 5 | 6 | #[error("Invalid type conversion: {0}")] 7 | TypeConversion(String), 8 | 9 | #[error("Serialization error: {0}")] 10 | Serialization(String), 11 | 12 | #[error("Deserialization error: {0}")] 13 | Deserialization(String), 14 | 15 | #[error("Unsupported type: {0}")] 16 | UnsupportedType(String), 17 | 18 | #[error("Unsupported pattern: {0}")] 19 | UnsupportedPattern(String), 20 | 21 | #[error("Syntax error: {0}")] 22 | Syntax(String), 23 | 24 | #[error("Internal error: {0}")] 25 | Internal(String), 26 | 27 | #[error("Artifacts error: {0}")] 28 | Artifacts(String), 29 | 30 | #[error("Config error: {0}")] 31 | Config(String), 32 | } 33 | 34 | impl From for syn::Error { 35 | fn from(error: ABIError) -> Self { 36 | syn::Error::new(proc_macro2::Span::call_site(), error.to_string()) 37 | } 38 | } 39 | 40 | impl From for proc_macro_error::Diagnostic { 41 | fn from(error: ABIError) -> Self { 42 | proc_macro_error::Diagnostic::new(proc_macro_error::Level::Error, error.to_string()) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /crates/sdk-derive/derive-core/src/abi/mod.rs: -------------------------------------------------------------------------------- 1 | //! ABI module provides functionality for working with Solidity ABI, focusing on function signatures 2 | //! parsing and type conversions. 3 | //! 4 | //! # Core components 5 | //! 6 | //! * `SolType` - represents Solidity types, parses Rust types into their Solidity equivalents 7 | //! * `FunctionABI` - represents Solidity function definitions 8 | //! * `RustToSol` - converts Rust types to their Solidity equivalents using registry 9 | //! 10 | //! # Function ID Generation 11 | //! 12 | //! Module can generate function signatures and IDs from Rust code in two modes: 13 | //! 14 | //! 1. Registry mode (enabled via feature flag): 15 | //! - All structure definitions are loaded into registry at startup 16 | //! - When constructing `FunctionABI`, registry is used to resolve types 17 | //! - Provides complete type information for complex structures 18 | //! 19 | //! 2. Direct mode (default): 20 | //! - No registry preloading 21 | //! - Types are converted directly during `FunctionABI` construction 22 | //! - Suitable for simple cases without complex nested structures 23 | //! 24 | //! ```rust, ignore 25 | //! use crate::abi::{FunctionABI, RustToSol}; 26 | //! 27 | //! // Parse Rust function signature 28 | //! let sig: syn::Signature = parse_quote! { 29 | //! fn transfer(amount: u64, recipient: String) -> String 30 | //! }; 31 | //! 32 | //! // Create registry (optional) 33 | //! // check artifacts for structure definitions 34 | //! 35 | //! let config = ArtifactsRegistryConfig::new("OUT_DIR").with_mirror(".artifacts"); 36 | //! let registry = ArtifactsRegistry::new(config)?; 37 | //! 38 | //! 39 | //! // Convert to FunctionABI 40 | //! let abi = FunctionABI::from_syn(&sig, registry)?; 41 | //! 42 | //! // Get function ID (first 4 bytes of keccak256 hash) 43 | //! let function_id = abi.function_id(); 44 | //! 45 | //! // Get canonical function signature (e.g. "transfer(uint256,string)") 46 | //! let signature = abi.signature(); 47 | //! ``` 48 | //! 49 | //! # Constraints 50 | //! 51 | //! - Types must implement `SolidityABI` derive macro 52 | //! - Generic types are not supported 53 | //! - Module path used for type identification in registry 54 | //! - Only non-generic Rust types can be converted to Solidity types 55 | //! - Complex types must be registered in the registry when using Registry mode 56 | pub mod contract; 57 | pub mod error; 58 | pub mod function; 59 | pub mod parameter; 60 | pub mod types; 61 | -------------------------------------------------------------------------------- /crates/sdk-derive/derive-core/src/abi/types/conversion/mod.rs: -------------------------------------------------------------------------------- 1 | #[doc = include_str!("../../../../../docs/type_conversion.md")] 2 | mod rust_to_sol; 3 | mod sol_to_rust; 4 | mod syn_sol_to_internal; 5 | 6 | pub use rust_to_sol::{rust_to_sol, ConversionError}; 7 | pub use sol_to_rust::sol_to_rust; 8 | pub use syn_sol_to_internal::convert_solidity_type; 9 | -------------------------------------------------------------------------------- /crates/sdk-derive/derive-core/src/abi/types/conversion/syn_sol_to_internal.rs: -------------------------------------------------------------------------------- 1 | use crate::abi::{error::ABIError, types::SolType}; 2 | use syn_solidity::{Expr, Lit, Type as SolidityAstType}; 3 | 4 | /// Converts `syn_solidity::Type` to internal `SolType`. 5 | pub fn convert_solidity_type(sol_ty: &SolidityAstType) -> Result { 6 | use SolidityAstType::*; 7 | 8 | match sol_ty { 9 | Address(_, _) => Ok(SolType::Address), 10 | Bool(_) => Ok(SolType::Bool), 11 | String(_) => Ok(SolType::String), 12 | Bytes(_) => Ok(SolType::Bytes), 13 | 14 | FixedBytes(_, size) => Ok(SolType::FixedBytes(size.get() as usize)), 15 | 16 | Uint(_, size) => Ok(SolType::Uint(size.map_or(256, |s| s.get() as usize))), 17 | Int(_, size) => Ok(SolType::Int(size.map_or(256, |s| s.get() as usize))), 18 | 19 | Array(arr) => { 20 | let inner = convert_solidity_type(&arr.ty)?; 21 | match &arr.size { 22 | Some(expr) => match expr.as_ref() { 23 | Expr::Lit(Lit::Number(lit_num)) => { 24 | let size = lit_num.base10_parse::().map_err(|_| { 25 | ABIError::UnsupportedType(format!( 26 | "Invalid array size: {:?}", 27 | lit_num.base10_digits() 28 | )) 29 | })?; 30 | Ok(SolType::FixedArray(Box::new(inner), size)) 31 | } 32 | _ => Err(ABIError::UnsupportedType( 33 | "Expected numeric literal for array size".into(), 34 | )), 35 | }, 36 | None => Ok(SolType::Array(Box::new(inner))), 37 | } 38 | } 39 | 40 | Tuple(tuple) => { 41 | let types = tuple 42 | .types 43 | .iter() 44 | .map(convert_solidity_type) 45 | .collect::, _>>()?; 46 | Ok(SolType::Tuple(types)) 47 | } 48 | 49 | Custom(path) => Ok(SolType::Struct { 50 | name: path.to_string(), 51 | fields: vec![], 52 | }), 53 | 54 | Mapping(_) | Function(_) => Err(ABIError::UnsupportedType( 55 | "mapping/function not supported".into(), 56 | )), 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /crates/sdk-derive/derive-core/src/abi/types/mod.rs: -------------------------------------------------------------------------------- 1 | mod conversion; 2 | mod sol; 3 | 4 | pub use conversion::*; 5 | pub use sol::SolType; 6 | -------------------------------------------------------------------------------- /crates/sdk-derive/derive-core/src/abi/types/sol.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::{self, Display, Formatter}; 2 | 3 | /// Represents Solidity types used in the ABI. 4 | #[derive(Debug, Clone, PartialEq)] 5 | pub enum SolType { 6 | // Primitive types 7 | Uint(usize), 8 | Int(usize), 9 | Address, 10 | Bool, 11 | String, 12 | Bytes, 13 | FixedBytes(usize), 14 | 15 | // Container types 16 | Array(Box), 17 | FixedArray(Box, usize), 18 | Tuple(Vec), 19 | 20 | // User-defined types 21 | Struct { 22 | name: String, 23 | fields: Vec<(String, SolType)>, 24 | }, 25 | } 26 | 27 | impl SolType { 28 | #[must_use] 29 | pub fn abi_type(&self) -> String { 30 | self.to_string() 31 | } 32 | 33 | #[must_use] 34 | pub fn abi_type_internal(&self) -> String { 35 | match self { 36 | Self::Struct { name, .. } => format!("struct {name}"), 37 | _ => self.to_string(), 38 | } 39 | } 40 | } 41 | 42 | impl Display for SolType { 43 | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { 44 | match self { 45 | Self::Uint(bits) => write!(f, "uint{bits}"), 46 | Self::Int(bits) => write!(f, "int{bits}"), 47 | Self::Address => write!(f, "address"), 48 | Self::Bool => write!(f, "bool"), 49 | Self::String => write!(f, "string"), 50 | Self::Bytes => write!(f, "bytes"), 51 | Self::FixedBytes(size) => write!(f, "bytes{size}"), 52 | Self::Array(inner) => write!(f, "{inner}[]"), 53 | Self::FixedArray(inner, size) => write!(f, "{inner}[{size}]"), 54 | Self::Tuple(types) => { 55 | write!(f, "(")?; 56 | for (i, ty) in types.iter().enumerate() { 57 | if i > 0 { 58 | write!(f, ",")?; 59 | } 60 | write!(f, "{ty}")?; 61 | } 62 | write!(f, ")") 63 | } 64 | Self::Struct { .. } => write!(f, "tuple"), 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /crates/sdk-derive/derive-core/src/attr/artifacts_dir.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | use darling::FromMeta; 3 | use std::{ 4 | fmt, 5 | path::{Path, PathBuf}, 6 | str::FromStr, 7 | }; 8 | 9 | #[derive(Debug, PartialEq, Clone)] 10 | pub struct Artifacts(pub PathBuf); 11 | 12 | impl Artifacts { 13 | const DEFAULT_PATH: &'static str = "artifacts"; 14 | 15 | pub fn new>(path: P) -> Self { 16 | Self(path.as_ref().to_path_buf()) 17 | } 18 | 19 | #[must_use] 20 | pub fn path(&self) -> &Path { 21 | &self.0 22 | } 23 | } 24 | 25 | impl Default for Artifacts { 26 | fn default() -> Self { 27 | Self::new(Self::DEFAULT_PATH) 28 | } 29 | } 30 | 31 | impl FromStr for Artifacts { 32 | type Err = String; 33 | 34 | fn from_str(s: &str) -> Result { 35 | if s.trim().is_empty() { 36 | Err("Artifacts path cannot be empty".to_string()) 37 | } else { 38 | Ok(Self::new(s)) 39 | } 40 | } 41 | } 42 | 43 | impl FromMeta for Artifacts { 44 | fn from_string(value: &str) -> darling::Result { 45 | value.parse().map_err(darling::Error::custom) 46 | } 47 | } 48 | 49 | impl fmt::Display for Artifacts { 50 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 51 | write!(f, "{}", self.0.display()) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /crates/sdk-derive/derive-core/src/attr/mod.rs: -------------------------------------------------------------------------------- 1 | pub(crate) mod artifacts_dir; 2 | pub(crate) mod function_id; 3 | pub(crate) mod mode; 4 | 5 | pub use artifacts_dir::Artifacts; 6 | pub use function_id::FunctionIDAttribute; 7 | pub use mode::Mode; 8 | -------------------------------------------------------------------------------- /crates/sdk-derive/derive-core/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Core functionality for the router macro implementation. 2 | //! This crate provides the base functionality used by the proc-macro crate. 3 | 4 | mod abi; 5 | pub mod attr; 6 | pub mod client; 7 | mod codec; 8 | mod method; 9 | pub mod router; 10 | mod signature; 11 | pub mod sol_input; 12 | pub mod storage; 13 | mod utils; 14 | -------------------------------------------------------------------------------- /crates/sdk-derive/derive-core/src/snapshots/fluentbase_sdk_derive_core__sol_input__tests__sol_struct_to_rust_tokens.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: crates/sdk-derive/derive-core/src/sol_input.rs 3 | expression: formatted 4 | --- 5 | #[derive(::fluentbase_sdk::codec::Codec, Debug, Clone, PartialEq, Eq)] 6 | pub struct User { 7 | pub name: String, 8 | pub age: U256, 9 | } 10 | -------------------------------------------------------------------------------- /crates/sdk-derive/derive-core/src/snapshots/fluentbase_sdk_derive_core__sol_input__tests__sol_to_rust_trait_nested_struct.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: crates/sdk-derive/derive-core/src/sol_input.rs 3 | expression: formatted 4 | --- 5 | #[derive(::fluentbase_sdk::codec::Codec, Debug, Clone, PartialEq, Eq)] 6 | pub struct Inner { 7 | pub x: U256, 8 | } 9 | #[derive(::fluentbase_sdk::codec::Codec, Debug, Clone, PartialEq, Eq)] 10 | pub struct Outer { 11 | pub inner: Inner, 12 | pub note: String, 13 | } 14 | pub trait IProgram { 15 | fn ping(&self, input: Outer) -> Outer; 16 | } 17 | -------------------------------------------------------------------------------- /crates/sdk-derive/derive-core/src/snapshots/fluentbase_sdk_derive_core__sol_input__tests__sol_to_sol_client_nested_struct.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: crates/sdk-derive/derive-core/src/sol_input.rs 3 | expression: formatted 4 | --- 5 | #[derive(::fluentbase_sdk::codec::Codec, Debug, Clone, PartialEq, Eq)] 6 | pub struct Inner { 7 | pub x: U256, 8 | } 9 | #[derive(::fluentbase_sdk::codec::Codec, Debug, Clone, PartialEq, Eq)] 10 | pub struct Outer { 11 | pub inner: Inner, 12 | pub note: String, 13 | } 14 | #[client(mode = "solidity")] 15 | pub trait IProgram { 16 | fn ping(&self, input: Outer) -> Outer; 17 | } 18 | -------------------------------------------------------------------------------- /crates/sdk-derive/derive-core/src/snapshots/fluentbase_sdk_derive_core__storage__tests__direct_storage_types.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: crates/sdk-derive/derive-core/src/storage.rs 3 | expression: formatted 4 | --- 5 | pub struct Owner {} 6 | impl Owner { 7 | const SLOT: fluentbase_sdk::U256 = fluentbase_sdk::U256::from_limbs([ 8 | 0u64, 0u64, 0u64, 0u64, 9 | ]); 10 | fn get(sdk: &SDK) -> Address { 11 | let key = Self::key(sdk); 12 |

>::get(sdk, key) 13 | } 14 | fn set(sdk: &mut SDK, value: Address) { 15 | let key = Self::key(sdk); 16 |
>::set(sdk, key, value) 17 | } 18 | fn key(_sdk: &SDK) -> fluentbase_sdk::U256 { 19 | Self::SLOT 20 | } 21 | } 22 | pub struct Paused {} 23 | impl Paused { 24 | const SLOT: fluentbase_sdk::U256 = fluentbase_sdk::U256::from_limbs([ 25 | 1u64, 0u64, 0u64, 0u64, 26 | ]); 27 | fn get(sdk: &SDK) -> bool { 28 | let key = Self::key(sdk); 29 | >::get(sdk, key) 30 | } 31 | fn set(sdk: &mut SDK, value: bool) { 32 | let key = Self::key(sdk); 33 | >::set(sdk, key, value) 34 | } 35 | fn key(_sdk: &SDK) -> fluentbase_sdk::U256 { 36 | Self::SLOT 37 | } 38 | } 39 | pub struct SmallValue {} 40 | impl SmallValue { 41 | const SLOT: fluentbase_sdk::U256 = fluentbase_sdk::U256::from_limbs([ 42 | 2u64, 0u64, 0u64, 0u64, 43 | ]); 44 | fn get(sdk: &SDK) -> u8 { 45 | let key = Self::key(sdk); 46 | >::get(sdk, key) 47 | } 48 | fn set(sdk: &mut SDK, value: u8) { 49 | let key = Self::key(sdk); 50 | >::set(sdk, key, value) 51 | } 52 | fn key(_sdk: &SDK) -> fluentbase_sdk::U256 { 53 | Self::SLOT 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /crates/sdk-derive/derive-core/src/snapshots/fluentbase_sdk_derive_core__storage__tests__primitive_storage.snap: -------------------------------------------------------------------------------- 1 | --- 2 | source: crates/sdk-derive/derive-core/src/storage.rs 3 | expression: formatted 4 | --- 5 | pub struct Owner {} 6 | impl Owner { 7 | const SLOT: fluentbase_sdk::U256 = fluentbase_sdk::U256::from_limbs([ 8 | 0u64, 0u64, 0u64, 0u64, 9 | ]); 10 | fn get(sdk: &SDK) -> Address { 11 | let key = Self::key(sdk); 12 |
>::get(sdk, key) 13 | } 14 | fn set(sdk: &mut SDK, value: Address) { 15 | let key = Self::key(sdk); 16 |
>::set(sdk, key, value) 17 | } 18 | fn key(_sdk: &SDK) -> fluentbase_sdk::U256 { 19 | Self::SLOT 20 | } 21 | } 22 | pub struct Paused {} 23 | impl Paused { 24 | const SLOT: fluentbase_sdk::U256 = fluentbase_sdk::U256::from_limbs([ 25 | 1u64, 0u64, 0u64, 0u64, 26 | ]); 27 | fn get(sdk: &SDK) -> bool { 28 | let key = Self::key(sdk); 29 | >::get(sdk, key) 30 | } 31 | fn set(sdk: &mut SDK, value: bool) { 32 | let key = Self::key(sdk); 33 | >::set(sdk, key, value) 34 | } 35 | fn key(_sdk: &SDK) -> fluentbase_sdk::U256 { 36 | Self::SLOT 37 | } 38 | } 39 | pub struct TotalSupply {} 40 | impl TotalSupply { 41 | const SLOT: fluentbase_sdk::U256 = fluentbase_sdk::U256::from_limbs([ 42 | 2u64, 0u64, 0u64, 0u64, 43 | ]); 44 | fn get(sdk: &SDK) -> U256 { 45 | let key = Self::key(sdk); 46 | >::get(sdk, key) 47 | } 48 | fn set(sdk: &mut SDK, value: U256) { 49 | let key = Self::key(sdk); 50 | >::set(sdk, key, value) 51 | } 52 | fn key(_sdk: &SDK) -> fluentbase_sdk::U256 { 53 | Self::SLOT 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /crates/sdk-derive/derive-core/src/utils/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod selector; 2 | -------------------------------------------------------------------------------- /crates/sdk-derive/docs/storage.md: -------------------------------------------------------------------------------- 1 | # Solidity Storage Macro 2 | 3 | Implements Solidity-compatible storage in Fluentbase contracts following [Solidity's storage layout specification](https://docs.soliditylang.org/en/latest/internals/layout_in_storage.html). Provides significant code size reduction through direct storage access for primitive types. 4 | 5 | ## Usage 6 | 7 | ```rust,ignore 8 | solidity_storage! { 9 | // Simple values 10 | Address Owner; // Slot 0 11 | bool Paused; // Slot 1 12 | 13 | // Mappings 14 | mapping(Address => U256) Balance; // Slot 2 15 | mapping(Address => mapping(Address => U256)) Allowance; // Slot 3 16 | 17 | // Arrays 18 | U256[] Values; // Slot 4 19 | 20 | // Custom types (must implement Codec) 21 | MyStruct Data; // Slot 5 22 | } 23 | ``` 24 | 25 | ## Storage Key Calculation 26 | 27 | - **Simple variables**: `key = slot` 28 | - **Mappings**: `key = keccak256(h(k) . p)` where `h(k)` is the padded key and `p` is the slot 29 | - **Nested mappings**: `key = keccak256(h(k2) . keccak256(h(k1) . p))` 30 | - **Arrays**: Element at index `i` is at `keccak256(slot) + i` 31 | 32 | ## Direct Storage vs Encoding/Decoding 33 | 34 | The macro automatically selects the most efficient storage method: 35 | 36 | - **`DirectStorage`**: For types ≤ 32 bytes (integers, booleans, addresses, small byte arrays) 37 | - **`StorageValueSolidity`**: For complex types requiring serialization 38 | 39 | ## Generated API 40 | 41 | For each variable `Name`, the macro generates: 42 | 43 | - A struct `Name` with `SLOT` constant 44 | - Methods `get(sdk, ...)` and `set(sdk, ..., value)` 45 | 46 | For examples, see the [fluentbase examples repository](https://github.com/fluentlabs-xyz/fluentbase/tree/next/examples/storage). 47 | -------------------------------------------------------------------------------- /crates/sdk-derive/src/contract.rs: -------------------------------------------------------------------------------- 1 | use proc_macro::TokenStream; 2 | use quote::quote; 3 | use syn::GenericParam; 4 | 5 | pub(crate) fn impl_derive_contract(ast: &syn::DeriveInput) -> TokenStream { 6 | let struct_name = &ast.ident; 7 | ast.generics 8 | .params 9 | .iter() 10 | .find(|param| match param { 11 | GenericParam::Lifetime(_) => false, 12 | GenericParam::Type(val) => val.ident == "SDK", 13 | GenericParam::Const(_) => false, 14 | }) 15 | .unwrap_or_else(|| panic!("missing SDK generic inside struct: {}", struct_name)); 16 | let (impl_generics, type_generics, _where_clause) = ast.generics.split_for_impl(); 17 | let output = quote! { 18 | impl #impl_generics #struct_name #type_generics { 19 | pub fn new(sdk: SDK) -> Self { 20 | #struct_name { sdk } 21 | } 22 | } 23 | }; 24 | TokenStream::from(output) 25 | } 26 | -------------------------------------------------------------------------------- /crates/sdk-derive/src/utils.rs: -------------------------------------------------------------------------------- 1 | pub fn calculate_keccak256_bytes(signature: &str) -> [u8; N] { 2 | use crypto_hashes::{digest::Digest, sha3::Keccak256}; 3 | let mut hash = Keccak256::new(); 4 | hash.update(signature); 5 | let mut dst = [0u8; N]; 6 | dst.copy_from_slice(hash.finalize().as_slice()[0..N].as_ref()); 7 | dst 8 | } 9 | 10 | pub fn calculate_keccak256_id(signature: &str) -> u32 { 11 | u32::from_be_bytes(calculate_keccak256_bytes::<4>(signature.trim_matches('"'))) 12 | } 13 | 14 | pub fn calculate_keccak256(signature: &str) -> [u8; 32] { 15 | let mut val = [0u8; 32]; 16 | val.copy_from_slice(calculate_keccak256_bytes::<32>(signature.trim_matches('"')).as_slice()); 17 | val 18 | } 19 | -------------------------------------------------------------------------------- /crates/sdk-derive/tests/ui.rs: -------------------------------------------------------------------------------- 1 | #[test] 2 | fn test_ui() { 3 | let t = trybuild::TestCases::new(); 4 | t.pass("tests/ui/**/pass/*.rs"); 5 | t.compile_fail("tests/ui/**/fail/*.rs"); 6 | } 7 | -------------------------------------------------------------------------------- /crates/sdk-derive/tests/ui/router/fail/function_id_type_mismatch.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | extern crate alloc; 3 | extern crate fluentbase_sdk; 4 | use alloc::string::String; 5 | use fluentbase_sdk::{ 6 | basic_entrypoint, 7 | derive::{router, Contract}, 8 | SharedAPI, 9 | }; 10 | 11 | #[derive(Contract)] 12 | struct App { 13 | sdk: SDK, 14 | } 15 | 16 | pub trait RouterAPI { 17 | // Method expects a String but function_id declares an address parameter 18 | fn greeting(&self, message: String) -> String; 19 | } 20 | 21 | #[router(mode = "solidity")] 22 | impl RouterAPI for App { 23 | // This should fail because the function ID specifies address type 24 | // but the method takes a String 25 | #[function_id("greeting(address)", validate(true))] 26 | fn greeting(&self, message: String) -> String { 27 | message 28 | } 29 | } 30 | 31 | impl App { 32 | pub fn deploy(&self) {} 33 | } 34 | 35 | basic_entrypoint!(App); 36 | -------------------------------------------------------------------------------- /crates/sdk-derive/tests/ui/router/fail/function_id_type_mismatch.stderr: -------------------------------------------------------------------------------- 1 | error: Function ID mismatch: Expected 0xf8194e48 for 'greeting(string)', but got 0xa21d05d9 2 | --> tests/ui/router/fail/function_id_type_mismatch.rs:25:19 3 | | 4 | 25 | #[function_id("greeting(address)", validate(true))] 5 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 6 | | 7 | = note: You're seeing this error because you have validation enabled (validate(true)) 8 | = help: To fix this, you can either: 9 | = help: 1. Use the expected function ID: #[function_id("greeting(string)")] 10 | = help: 2. Remove the validate parameter entirely: #[function_id("greeting(address)")] 11 | = help: 3. Or explicitly disable validation: #[function_id("greeting(address)", validate(false))] 12 | -------------------------------------------------------------------------------- /crates/sdk-derive/tests/ui/router/fail/incorrect_fallback_signature.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | extern crate alloc; 3 | extern crate fluentbase_sdk; 4 | use fluentbase_sdk::{ 5 | basic_entrypoint, 6 | derive::{router, Contract}, 7 | SharedAPI, 8 | }; 9 | 10 | #[derive(Contract)] 11 | struct App { 12 | sdk: SDK, 13 | } 14 | 15 | pub trait RouterAPI { 16 | // Fallback must have no parameters and no return value 17 | fn fallback(&self, data: u64) -> bool; 18 | 19 | // Regular method for the router to have something to process 20 | fn regular_method(&self); 21 | } 22 | 23 | #[router(mode = "solidity")] 24 | impl RouterAPI for App { 25 | fn fallback(&self, data: u64) -> bool { 26 | // Should cause an error as fallback cannot have parameters or return value 27 | data > 10 28 | } 29 | 30 | #[function_id("regularMethod()", validate(true))] 31 | fn regular_method(&self) { 32 | // Normal method 33 | } 34 | } 35 | 36 | impl App { 37 | pub fn deploy(&self) {} 38 | } 39 | 40 | basic_entrypoint!(App); 41 | -------------------------------------------------------------------------------- /crates/sdk-derive/tests/ui/router/fail/incorrect_fallback_signature.stderr: -------------------------------------------------------------------------------- 1 | error: fallback method must have signature 'fn fallback(&self)' with no parameters and no return value 2 | --> tests/ui/router/fail/incorrect_fallback_signature.rs:25:5 3 | | 4 | 25 | fn fallback(&self, data: u64) -> bool { 5 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 6 | 7 | error: Failed to process router implementation due to method parsing errors 8 | --> tests/ui/router/fail/incorrect_fallback_signature.rs:23:1 9 | | 10 | 23 | #[router(mode = "solidity")] 11 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 12 | | 13 | = note: this error originates in the attribute macro `router` (in Nightly builds, run with -Z macro-backtrace for more info) 14 | -------------------------------------------------------------------------------- /crates/sdk-derive/tests/ui/router/fail/invalid_selector_validation.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | extern crate alloc; 3 | extern crate fluentbase_sdk; 4 | use alloc::string::String; 5 | use fluentbase_sdk::{ 6 | basic_entrypoint, 7 | derive::{router, Contract}, 8 | SharedAPI, 9 | }; 10 | 11 | #[derive(Contract)] 12 | struct App { 13 | sdk: SDK, 14 | } 15 | 16 | pub trait RouterAPI { 17 | fn greeting(&self, message: String) -> String; 18 | } 19 | 20 | #[router(mode = "solidity")] 21 | impl RouterAPI for App { 22 | // This should fail because the selector 0xDEADBEEF doesn't match 23 | // the calculated selector for greeting(string) 24 | #[function_id("0xDEADBEEF", validate(true))] 25 | fn greeting(&self, message: String) -> String { 26 | message 27 | } 28 | } 29 | 30 | impl App { 31 | pub fn deploy(&self) {} 32 | } 33 | 34 | basic_entrypoint!(App); 35 | -------------------------------------------------------------------------------- /crates/sdk-derive/tests/ui/router/fail/invalid_selector_validation.stderr: -------------------------------------------------------------------------------- 1 | error: Function ID mismatch: Expected 0xf8194e48 for 'greeting(string)', but got 0xdeadbeef 2 | --> tests/ui/router/fail/invalid_selector_validation.rs:24:19 3 | | 4 | 24 | #[function_id("0xDEADBEEF", validate(true))] 5 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 6 | | 7 | = note: You're seeing this error because you have validation enabled (validate(true)) 8 | = help: To fix this, you can either: 9 | = help: 1. Use the expected function ID: #[function_id("greeting(string)")] 10 | = help: 2. Remove the validate parameter entirely: #[function_id("your_signature")] 11 | = help: 3. Or explicitly disable validation: #[function_id("your_signature", validate(false))] 12 | -------------------------------------------------------------------------------- /crates/sdk-derive/tests/ui/router/fail/no_public_methods_direct_impl.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | extern crate alloc; 3 | extern crate fluentbase_sdk; 4 | use fluentbase_sdk::{ 5 | basic_entrypoint, 6 | derive::{router, Contract}, 7 | }; 8 | 9 | #[derive(Contract)] 10 | struct App { 11 | sdk: SDK, 12 | } 13 | 14 | // Direct implementation without using public methods 15 | #[router(mode = "solidity")] 16 | impl App { 17 | // Private method - this should cause an error since in direct implementation 18 | // only public methods are included in routing 19 | fn private_method(&self, value: u32) -> u32 { 20 | value 21 | } 22 | 23 | // Another private method 24 | fn another_private_method(&self, message: String) -> String { 25 | message 26 | } 27 | 28 | // Regular deployment method - not public but special case 29 | fn deploy(&self) {} 30 | } 31 | 32 | basic_entrypoint!(App); 33 | -------------------------------------------------------------------------------- /crates/sdk-derive/tests/ui/router/fail/no_public_methods_direct_impl.stderr: -------------------------------------------------------------------------------- 1 | error: Router has no methods. Make sure your implementation contains at least one public method that is not named 'deploy'. 2 | --> tests/ui/router/fail/no_public_methods_direct_impl.rs:16:1 3 | | 4 | 16 | / impl App { 5 | 17 | | // Private method - this should cause an error since in direct implementation 6 | 18 | | // only public methods are included in routing 7 | 19 | | fn private_method(&self, value: u32) -> u32 { 8 | ... | 9 | 29 | | fn deploy(&self) {} 10 | 30 | | } 11 | | |_^ 12 | | 13 | = help: Check that methods are public (pub fn) for regular implementations 14 | = help: Consider marking your methods as public: pub fn method_name(...) 15 | -------------------------------------------------------------------------------- /crates/sdk-derive/tests/ui/router/fail/without_mode.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | extern crate alloc; 4 | extern crate fluentbase_sdk; 5 | 6 | use fluentbase_sdk::{ 7 | basic_entrypoint, 8 | derive::{router, Contract}, 9 | }; 10 | 11 | #[derive(Contract)] 12 | struct MyContract { 13 | sdk: SDK, 14 | } 15 | 16 | #[router] 17 | impl MyContract { 18 | fn private_method(&self, a: u32) -> u64 { 19 | a as u64 20 | } 21 | } 22 | 23 | basic_entrypoint!(MyContract); 24 | -------------------------------------------------------------------------------- /crates/sdk-derive/tests/ui/router/fail/without_mode.stderr: -------------------------------------------------------------------------------- 1 | error: Missing field `mode` 2 | --> tests/ui/router/fail/without_mode.rs:16:1 3 | | 4 | 16 | #[router] 5 | | ^^^^^^^^^ 6 | | 7 | = note: this error originates in the attribute macro `router` (in Nightly builds, run with -Z macro-backtrace for more info) 8 | -------------------------------------------------------------------------------- /crates/sdk-derive/tests/ui/router/pass/direct_impl.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | extern crate alloc; 3 | extern crate fluentbase_sdk; 4 | use alloc::vec::Vec; 5 | use fluentbase_sdk::{ 6 | basic_entrypoint, 7 | derive::{router, Contract}, 8 | Address, 9 | Bytes, 10 | SharedAPI, 11 | I256, 12 | U256, 13 | }; 14 | 15 | #[derive(Contract)] 16 | struct App { 17 | sdk: SDK, 18 | } 19 | 20 | #[router(mode = "solidity")] 21 | impl App { 22 | #[function_id("addressTest(address)", validate(true))] 23 | pub fn address_test(&self, addr: Address) -> Address { 24 | addr 25 | } 26 | 27 | #[function_id("bytesTest(bytes)", validate(true))] 28 | pub fn bytes_test(&self, data: Bytes) -> Bytes { 29 | data 30 | } 31 | 32 | #[function_id("fixedBytesTest(bytes32)", validate(true))] 33 | pub fn fixed_bytes_test(&self, data: [u8; 32]) -> [u8; 32] { 34 | data 35 | } 36 | 37 | #[function_id("uint256Test(uint256)", validate(true))] 38 | pub fn uint256_test(&self, value: U256) -> U256 { 39 | value 40 | } 41 | 42 | #[function_id("int256Test(int256)", validate(true))] 43 | pub fn int256_test(&self, value: I256) -> I256 { 44 | value 45 | } 46 | 47 | #[function_id("boolTest(bool)", validate(true))] 48 | pub fn bool_test(&self, value: bool) -> bool { 49 | value 50 | } 51 | 52 | #[function_id("arrayTest(uint256[])", validate(true))] 53 | pub fn array_test(&self, values: Vec) -> Vec { 54 | values 55 | } 56 | 57 | #[function_id("multipleParams(address,uint256,bytes)", validate(true))] 58 | pub fn multiple_params(&self, addr: Address, amount: U256, data: Bytes) -> bool { 59 | !addr.is_zero() && !amount.is_zero() && !data.is_empty() 60 | } 61 | 62 | #[function_id("complexReturn(uint64)", validate(true))] 63 | pub fn complex_return(&self, value: u64) -> (Address, U256, bool) { 64 | (Address::default(), U256::from(value), true) 65 | } 66 | } 67 | 68 | impl App { 69 | pub fn deploy(&self) {} 70 | } 71 | 72 | basic_entrypoint!(App); 73 | -------------------------------------------------------------------------------- /crates/sdk-derive/tests/ui/router/pass/trait_impl.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | extern crate alloc; 3 | extern crate fluentbase_sdk; 4 | use alloc::vec::Vec; 5 | use fluentbase_sdk::{ 6 | basic_entrypoint, 7 | derive::{router, Contract}, 8 | Address, 9 | Bytes, 10 | SharedAPI, 11 | I256, 12 | U256, 13 | }; 14 | 15 | #[derive(Contract)] 16 | struct App { 17 | sdk: SDK, 18 | } 19 | 20 | pub trait SolidityTypesAPI { 21 | // Test various Solidity types mapping to Rust types 22 | fn address_test(&self, addr: Address) -> Address; 23 | fn bytes_test(&self, data: Bytes) -> Bytes; 24 | fn fixed_bytes_test(&self, data: [u8; 32]) -> [u8; 32]; 25 | fn uint256_test(&self, value: U256) -> U256; 26 | fn int256_test(&self, value: I256) -> I256; 27 | fn bool_test(&self, value: bool) -> bool; 28 | fn array_test(&self, values: Vec) -> Vec; 29 | fn multiple_params(&self, addr: Address, amount: U256, data: Bytes) -> bool; 30 | fn complex_return(&self, value: u64) -> (Address, U256, bool); 31 | } 32 | 33 | #[router(mode = "solidity")] 34 | impl SolidityTypesAPI for App { 35 | #[function_id("addressTest(address)", validate(true))] 36 | fn address_test(&self, addr: Address) -> Address { 37 | addr 38 | } 39 | 40 | #[function_id("bytesTest(bytes)", validate(true))] 41 | fn bytes_test(&self, data: Bytes) -> Bytes { 42 | data 43 | } 44 | 45 | #[function_id("fixedBytesTest(bytes32)", validate(true))] 46 | fn fixed_bytes_test(&self, data: [u8; 32]) -> [u8; 32] { 47 | data 48 | } 49 | 50 | #[function_id("uint256Test(uint256)", validate(true))] 51 | fn uint256_test(&self, value: U256) -> U256 { 52 | value 53 | } 54 | 55 | #[function_id("int256Test(int256)", validate(true))] 56 | fn int256_test(&self, value: I256) -> I256 { 57 | value 58 | } 59 | 60 | #[function_id("boolTest(bool)", validate(true))] 61 | fn bool_test(&self, value: bool) -> bool { 62 | value 63 | } 64 | 65 | #[function_id("arrayTest(uint256[])", validate(true))] 66 | fn array_test(&self, values: Vec) -> Vec { 67 | values 68 | } 69 | 70 | #[function_id("multipleParams(address,uint256,bytes)", validate(true))] 71 | fn multiple_params(&self, addr: Address, amount: U256, data: Bytes) -> bool { 72 | !addr.is_zero() && !amount.is_zero() && !data.is_empty() 73 | } 74 | 75 | #[function_id("complexReturn(uint64)", validate(true))] 76 | fn complex_return(&self, value: u64) -> (Address, U256, bool) { 77 | (Address::default(), U256::from(value), true) 78 | } 79 | } 80 | 81 | impl App { 82 | pub fn deploy(&self) {} 83 | } 84 | 85 | basic_entrypoint!(App); 86 | -------------------------------------------------------------------------------- /crates/sdk-testing/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fluentbase-sdk-testing" 3 | version = "0.1.0" 4 | authors.workspace = true 5 | repository.workspace = true 6 | edition.workspace = true 7 | readme.workspace = true 8 | license.workspace = true 9 | keywords.workspace = true 10 | categories.workspace = true 11 | 12 | [dependencies] 13 | fluentbase-codec = { workspace = true } 14 | fluentbase-genesis = { workspace = true } 15 | fluentbase-runtime = { workspace = true, features = ["std"] } 16 | fluentbase-sdk = { workspace = true } 17 | fluentbase-types = { workspace = true } 18 | 19 | hashbrown = { workspace = true } 20 | revm = { workspace = true } 21 | rwasm = { workspace = true } 22 | hex = { workspace = true } 23 | 24 | [features] 25 | default = ["std", "fluentbase-runtime/debug-print"] 26 | std = [ 27 | "fluentbase-codec/std", 28 | "fluentbase-genesis/std", 29 | "fluentbase-runtime/std", 30 | "fluentbase-sdk/std", 31 | "rwasm/std", 32 | "revm/std", 33 | ] 34 | -------------------------------------------------------------------------------- /crates/sdk-testing/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod evm; 2 | mod host; 3 | 4 | pub use evm::*; 5 | pub use fluentbase_sdk::include_this_wasm; 6 | pub use host::*; 7 | -------------------------------------------------------------------------------- /crates/sdk/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fluentbase-sdk" 3 | description = "Fluentbase SDK" 4 | version = "0.1.0" 5 | edition = "2021" 6 | 7 | [dependencies] 8 | fluentbase-codec = { workspace = true } 9 | fluentbase-types = { workspace = true } 10 | fluentbase-sdk-derive = { workspace = true } 11 | hashbrown = { workspace = true } 12 | 13 | [dev-dependencies] 14 | 15 | [features] 16 | default = ["std"] 17 | std = [ 18 | "fluentbase-types/std", 19 | "fluentbase-codec/std", 20 | ] 21 | debug-print = [] 22 | -------------------------------------------------------------------------------- /crates/sdk/src/constructor.rs: -------------------------------------------------------------------------------- 1 | use crate::leb128; 2 | use alloc::vec::Vec; 3 | 4 | /// Encodes a custom section for a WebAssembly (WASM) module. 5 | fn encode_wasm_custom_section(name: &str, payload: &[u8]) -> Vec { 6 | let mut section = Vec::new(); 7 | 8 | let name_length = leb128::write::unsigned(name.as_bytes().len() as u64); 9 | let content_length = 10 | leb128::write::unsigned((name_length.len() + name.len() + payload.len()) as u64); 11 | 12 | section.push(0x00); // Section ID 0x00 for custom sections. 13 | section.extend(content_length); // Size of all following data in a section encoded as leb128 14 | section.extend(name_length); // Size of utf-8 encoded name, encoded as leb128 15 | section.extend_from_slice(name.as_bytes()); // Name encoded as utf-8 16 | section.extend(payload); // Provided payload 17 | section 18 | } 19 | 20 | /// Packs constructor parameters into a WASM custom section labeled "input". 21 | /// 22 | /// The resulting section can be appended to the end of an existing WASM binary. 23 | /// During deployment, these parameters will be accessible via the 24 | /// `sdk.input()` function, allowing the "deploy" function to retrieve 25 | /// necessary data. 26 | pub fn encode_constructor_params(payload: &[u8]) -> Vec { 27 | encode_wasm_custom_section("input", payload) 28 | } 29 | 30 | #[cfg(test)] 31 | mod tests { 32 | use super::*; 33 | 34 | #[test] 35 | fn test_encode_wasm_input_section() { 36 | let payload = vec![1, 2, 3, 4]; 37 | let result = encode_constructor_params(&payload); 38 | 39 | let expected_prefix = vec![0x00, 0x0A, 0x05, b'i', b'n', b'p', b'u', b't']; // header for "input" with payload 40 | let expected_result = [expected_prefix, payload.clone()].concat(); 41 | 42 | assert_eq!(result, expected_result); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /crates/sdk/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(feature = "std"), no_std)] 2 | 3 | extern crate alloc; 4 | extern crate core; 5 | 6 | mod allocator; 7 | #[cfg(not(feature = "std"))] 8 | mod bindings; 9 | pub mod constructor; 10 | pub mod entrypoint; 11 | pub mod leb128; 12 | mod macros; 13 | pub mod panic; 14 | #[cfg(not(feature = "std"))] 15 | pub mod rwasm; 16 | pub mod shared; 17 | pub mod storage; 18 | 19 | pub use allocator::*; 20 | pub use fluentbase_codec as codec; 21 | pub use fluentbase_sdk_derive as derive; 22 | pub use fluentbase_types::*; 23 | pub use hashbrown; 24 | 25 | #[cfg(feature = "std")] 26 | #[macro_export] 27 | macro_rules! include_this_wasm { 28 | () => { 29 | include_bytes!(env!("FLUENTBASE_WASM_ARTIFACT_PATH")) 30 | }; 31 | } 32 | -------------------------------------------------------------------------------- /crates/sdk/src/macros.rs: -------------------------------------------------------------------------------- 1 | #[macro_export] 2 | macro_rules! debug_log { 3 | ($msg:tt) => {{ 4 | #[cfg(target_arch = "wasm32")] 5 | unsafe { $crate::rwasm::_debug_log($msg.as_ptr(), $msg.len() as u32) } 6 | #[cfg(feature = "std")] 7 | println!("{}", $msg); 8 | }}; 9 | ($($arg:tt)*) => {{ 10 | let msg = alloc::format!($($arg)*); 11 | debug_log!(msg); 12 | }}; 13 | } 14 | 15 | #[macro_export] 16 | macro_rules! define_allocator { 17 | () => { 18 | #[cfg(target_arch = "wasm32")] 19 | #[global_allocator] 20 | static ALLOCATOR: $crate::HeapBaseAllocator = $crate::HeapBaseAllocator {}; 21 | }; 22 | } 23 | 24 | #[macro_export] 25 | macro_rules! define_panic_handler { 26 | () => { 27 | #[cfg(target_arch = "wasm32")] 28 | #[panic_handler] 29 | #[inline(always)] 30 | unsafe fn panic(info: &core::panic::PanicInfo) -> ! { 31 | $crate::panic::handle_panic_info(info) 32 | } 33 | }; 34 | } 35 | -------------------------------------------------------------------------------- /crates/sdk/src/panic.rs: -------------------------------------------------------------------------------- 1 | #[cfg(target_arch = "wasm32")] 2 | pub unsafe fn handle_panic_info(info: &core::panic::PanicInfo) -> ! { 3 | use crate::{native_api::NativeAPI, rwasm::RwasmContext, ExitCode}; 4 | let panic_message = alloc::format!("{}", info.message()); 5 | let native_sdk = RwasmContext {}; 6 | native_sdk.write(panic_message.as_bytes()); 7 | native_sdk.exit(ExitCode::Panic.into_i32()) 8 | } 9 | -------------------------------------------------------------------------------- /crates/types/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fluentbase-types" 3 | version = "0.1.0" 4 | authors.workspace = true 5 | repository.workspace = true 6 | edition.workspace = true 7 | readme.workspace = true 8 | license.workspace = true 9 | keywords.workspace = true 10 | categories.workspace = true 11 | 12 | [dependencies] 13 | serde = { workspace = true, optional = true } 14 | byteorder = { workspace = true, default-features = false } 15 | rwasm = { workspace = true } 16 | alloy-primitives = { workspace = true } 17 | alloy-rlp = { workspace = true } 18 | strum_macros = { workspace = true } 19 | revm-primitives = { workspace = true, default-features = false } 20 | hashbrown = { workspace = true } 21 | fluentbase-codec = { workspace = true } 22 | auto_impl = { workspace = true } 23 | bincode = { workspace = true } 24 | 25 | [dev-dependencies] 26 | hex-literal = { workspace = true } 27 | 28 | [features] 29 | default = ["std"] 30 | serde = ["dep:serde", "alloy-primitives/serde", "revm-primitives/serde"] 31 | std = [ 32 | "rwasm/std", 33 | "alloy-primitives/std", 34 | "byteorder/std", 35 | "fluentbase-codec/std", 36 | ] 37 | optimism = ["revm-primitives/optimism"] 38 | -------------------------------------------------------------------------------- /crates/types/src/context.rs: -------------------------------------------------------------------------------- 1 | use alloy_primitives::{Address, Bytes, B256, U256}; 2 | use auto_impl::auto_impl; 3 | 4 | mod v1; 5 | 6 | #[auto_impl(&)] 7 | pub trait BlockContextReader { 8 | fn block_chain_id(&self) -> u64; 9 | fn block_coinbase(&self) -> Address; 10 | fn block_timestamp(&self) -> u64; 11 | fn block_number(&self) -> u64; 12 | fn block_difficulty(&self) -> U256; 13 | fn block_prev_randao(&self) -> B256; 14 | fn block_gas_limit(&self) -> u64; 15 | fn block_base_fee(&self) -> U256; 16 | } 17 | 18 | #[auto_impl(&)] 19 | pub trait TxContextReader { 20 | fn tx_gas_limit(&self) -> u64; 21 | fn tx_nonce(&self) -> u64; 22 | fn tx_gas_price(&self) -> U256; 23 | fn tx_gas_priority_fee(&self) -> Option; 24 | fn tx_origin(&self) -> Address; 25 | fn tx_value(&self) -> U256; 26 | } 27 | 28 | #[auto_impl(&)] 29 | pub trait ContractContextReader { 30 | fn contract_address(&self) -> Address; 31 | fn contract_bytecode_address(&self) -> Address; 32 | fn contract_caller(&self) -> Address; 33 | fn contract_is_static(&self) -> bool; 34 | fn contract_value(&self) -> U256; 35 | fn contract_gas_limit(&self) -> u64; 36 | } 37 | 38 | pub use self::v1::{BlockContextV1, ContractContextV1, SharedContextInputV1, TxContextV1}; 39 | 40 | #[auto_impl(&)] 41 | pub trait SharedContextReader: 42 | BlockContextReader + TxContextReader + ContractContextReader 43 | { 44 | } 45 | 46 | #[derive(Clone, Debug, PartialEq)] 47 | pub enum SharedContextInput { 48 | V1(SharedContextInputV1), 49 | } 50 | 51 | impl SharedContextInput { 52 | fn version(&self) -> u8 { 53 | match self { 54 | SharedContextInput::V1(_) => 0x01, 55 | } 56 | } 57 | 58 | pub fn decode(buf: &[u8]) -> Result { 59 | let config = bincode::config::legacy(); 60 | let result = bincode::decode_from_slice(buf, config)?; 61 | Ok(Self::V1(result.0)) 62 | } 63 | 64 | pub fn encode(&self) -> Result { 65 | match self { 66 | SharedContextInput::V1(value) => { 67 | let config = bincode::config::legacy(); 68 | let result: Bytes = bincode::encode_to_vec(value, config)?.into(); 69 | Ok(result) 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /crates/types/src/context/v1/block_context.rs: -------------------------------------------------------------------------------- 1 | use crate::context::BlockContextReader; 2 | use alloy_primitives::{Address, B256, U256}; 3 | 4 | #[derive(Default, Clone, Debug, PartialEq)] 5 | pub struct BlockContextV1 { 6 | pub chain_id: u64, 7 | pub coinbase: Address, 8 | pub timestamp: u64, 9 | pub number: u64, 10 | pub difficulty: U256, 11 | pub prev_randao: B256, 12 | pub gas_limit: u64, 13 | pub base_fee: U256, 14 | } 15 | 16 | impl BlockContextReader for BlockContextV1 { 17 | fn block_chain_id(&self) -> u64 { 18 | self.chain_id 19 | } 20 | 21 | fn block_coinbase(&self) -> Address { 22 | self.coinbase 23 | } 24 | 25 | fn block_timestamp(&self) -> u64 { 26 | self.timestamp 27 | } 28 | 29 | fn block_number(&self) -> u64 { 30 | self.number 31 | } 32 | 33 | fn block_difficulty(&self) -> U256 { 34 | self.difficulty 35 | } 36 | 37 | fn block_prev_randao(&self) -> B256 { 38 | self.prev_randao 39 | } 40 | 41 | fn block_gas_limit(&self) -> u64 { 42 | self.gas_limit 43 | } 44 | 45 | fn block_base_fee(&self) -> U256 { 46 | self.base_fee 47 | } 48 | } 49 | 50 | impl From<&revm_primitives::Env> for BlockContextV1 { 51 | fn from(value: &revm_primitives::Env) -> Self { 52 | Self { 53 | chain_id: value.cfg.chain_id, 54 | coinbase: value.block.coinbase, 55 | timestamp: value.block.timestamp.as_limbs()[0], 56 | number: value.block.number.as_limbs()[0], 57 | difficulty: value.block.difficulty, 58 | prev_randao: value.block.prevrandao.unwrap_or_default(), 59 | gas_limit: value.block.gas_limit.as_limbs()[0], 60 | base_fee: value.block.basefee, 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /crates/types/src/context/v1/tx_context.rs: -------------------------------------------------------------------------------- 1 | use crate::context::TxContextReader; 2 | use alloy_primitives::{Address, U256}; 3 | 4 | #[derive(Default, Clone, Debug, PartialEq)] 5 | pub struct TxContextV1 { 6 | pub gas_limit: u64, 7 | pub nonce: u64, 8 | pub gas_price: U256, 9 | pub gas_priority_fee: Option, 10 | pub origin: Address, 11 | // pub blob_hashes: Vec, 12 | // pub max_fee_per_blob_gas: Option, 13 | pub value: U256, 14 | } 15 | 16 | impl TxContextReader for TxContextV1 { 17 | fn tx_gas_limit(&self) -> u64 { 18 | self.gas_limit 19 | } 20 | 21 | fn tx_nonce(&self) -> u64 { 22 | self.nonce 23 | } 24 | 25 | fn tx_gas_price(&self) -> U256 { 26 | self.gas_price 27 | } 28 | 29 | fn tx_gas_priority_fee(&self) -> Option { 30 | self.gas_priority_fee 31 | } 32 | 33 | fn tx_origin(&self) -> Address { 34 | self.origin 35 | } 36 | 37 | fn tx_value(&self) -> U256 { 38 | self.value 39 | } 40 | } 41 | 42 | impl From<&revm_primitives::Env> for TxContextV1 { 43 | fn from(value: &revm_primitives::Env) -> Self { 44 | Self { 45 | gas_limit: value.tx.gas_limit, 46 | nonce: value.tx.nonce.unwrap_or_default(), 47 | gas_price: value.tx.gas_price, 48 | gas_priority_fee: value.tx.gas_priority_fee, 49 | origin: value.tx.caller, 50 | // data: value.tx.data.clone(), 51 | // blob_hashes: value.tx.blob_hashes.clone(), 52 | // max_fee_per_blob_gas: value.tx.max_fee_per_blob_gas, 53 | value: value.tx.value, 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /crates/types/src/genesis.rs: -------------------------------------------------------------------------------- 1 | use alloy_primitives::{address, Address}; 2 | 3 | /// An address of EVM runtime that is used to execute EVM program 4 | pub const PRECOMPILE_EVM_RUNTIME: Address = address!("0000000000000000000000000000000000520001"); 5 | /// A verifier for Fairblock attestations 6 | pub const PRECOMPILE_FAIRBLOCK_VERIFIER: Address = 7 | address!("0000000000000000000000000000000000005202"); 8 | 9 | /// An address for SVM runtime 10 | pub const PRECOMPILE_SVM_RUNTIME: Address = address!("0000000000000000000000000000000000520003"); 11 | pub const PRECOMPILE_WRAPPED_ETH: Address = address!("0000000000000000000000000000000000520004"); 12 | pub const PRECOMPILE_WEBAUTHN_VERIFIER: Address = 13 | address!("0000000000000000000000000000000000520005"); 14 | pub const PRECOMPILE_OAUTH2_VERIFIER: Address = 15 | address!("0000000000000000000000000000000000520006"); 16 | pub const PRECOMPILE_NITRO_VERIFIER: Address = address!("0000000000000000000000000000000000520007"); 17 | pub const PRECOMPILE_ERC20: Address = address!("0000000000000000000000000000000000520008"); 18 | 19 | const fn evm_address(value: u8) -> Address { 20 | Address::with_last_byte(value) 21 | } 22 | 23 | pub const PRECOMPILE_SECP256K1_RECOVER: Address = evm_address(0x01); 24 | pub const PRECOMPILE_SHA256: Address = evm_address(0x02); 25 | pub const PRECOMPILE_RIPEMD160: Address = evm_address(0x03); 26 | pub const PRECOMPILE_IDENTITY: Address = evm_address(0x04); 27 | pub const PRECOMPILE_BIG_MODEXP: Address = evm_address(0x05); 28 | pub const PRECOMPILE_BN256_ADD: Address = evm_address(0x06); 29 | pub const PRECOMPILE_BN256_MUL: Address = evm_address(0x07); 30 | pub const PRECOMPILE_BN256_PAIR: Address = evm_address(0x08); 31 | pub const PRECOMPILE_BLAKE2F: Address = evm_address(0x09); 32 | pub const PRECOMPILE_KZG_POINT_EVALUATION: Address = evm_address(0x0a); 33 | pub const PRECOMPILE_BLS12_381_G1_ADD: Address = evm_address(0x0b); 34 | pub const PRECOMPILE_BLS12_381_G1_MSM: Address = evm_address(0x0c); 35 | pub const PRECOMPILE_BLS12_381_G2_ADD: Address = evm_address(0x0d); 36 | pub const PRECOMPILE_BLS12_381_G2_MSM: Address = evm_address(0x0e); 37 | pub const PRECOMPILE_BLS12_381_PAIRING: Address = evm_address(0x0f); 38 | pub const PRECOMPILE_BLS12_381_MAP_G1: Address = evm_address(0x10); 39 | pub const PRECOMPILE_BLS12_381_MAP_G2: Address = evm_address(0x11); 40 | 41 | // "R native" + keccak256("multicall(bytes[])")[..4] 42 | pub const PRECOMPILE_NATIVE_MULTICALL: Address = 43 | address!("52206e61746976650000000000000000ac9650d8"); 44 | 45 | pub struct GenesisContractBuildOutput { 46 | pub name: &'static str, 47 | pub wasm_bytecode: &'static [u8], 48 | pub rwasm_bytecode: &'static [u8], 49 | pub rwasm_bytecode_hash: [u8; 32], 50 | pub wasmtime_module_bytes: &'static [u8], 51 | } 52 | -------------------------------------------------------------------------------- /crates/types/src/native_api.rs: -------------------------------------------------------------------------------- 1 | use crate::BytecodeOrHash; 2 | use alloc::vec; 3 | use alloy_primitives::{Bytes, B256}; 4 | 5 | /// A trait for providing shared API functionality. 6 | pub trait NativeAPI { 7 | fn keccak256(data: &[u8]) -> B256; 8 | fn sha256(data: &[u8]) -> B256; 9 | fn secp256k1_recover(digest: &B256, sig: &[u8; 64], rec_id: u8) -> Option<[u8; 65]>; 10 | fn debug_log(message: &str); 11 | 12 | fn read(&self, target: &mut [u8], offset: u32); 13 | fn input_size(&self) -> u32; 14 | fn write(&self, value: &[u8]); 15 | fn forward_output(&self, offset: u32, len: u32); 16 | fn exit(&self, exit_code: i32) -> !; 17 | fn output_size(&self) -> u32; 18 | fn read_output(&self, target: &mut [u8], offset: u32); 19 | fn state(&self) -> u32; 20 | fn fuel(&self) -> u64; 21 | fn charge_fuel_manually(&self, fuel_consumed: u64, fuel_refunded: i64) -> u64; 22 | fn charge_fuel(&self, fuel_consumed: u64); 23 | fn exec>( 24 | &self, 25 | code_hash: I, 26 | input: &[u8], 27 | fuel_limit: Option, 28 | state: u32, 29 | ) -> (u64, i64, i32); 30 | fn resume( 31 | &self, 32 | call_id: u32, 33 | return_data: &[u8], 34 | exit_code: i32, 35 | fuel_consumed: u64, 36 | fuel_refunded: i64, 37 | ) -> (u64, i64, i32); 38 | 39 | #[deprecated(note = "don't use")] 40 | fn preimage_size(&self, hash: &B256) -> u32; 41 | #[deprecated(note = "don't use")] 42 | fn preimage_copy(&self, hash: &B256, target: &mut [u8]); 43 | 44 | fn input(&self) -> Bytes { 45 | let input_size = self.input_size(); 46 | let mut buffer = vec![0u8; input_size as usize]; 47 | self.read(&mut buffer, 0); 48 | buffer.into() 49 | } 50 | 51 | fn return_data(&self) -> Bytes { 52 | let output_size = self.output_size(); 53 | let mut buffer = vec![0u8; output_size as usize]; 54 | self.read_output(&mut buffer, 0); 55 | buffer.into() 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /crates/types/src/preimage.rs: -------------------------------------------------------------------------------- 1 | use crate::{Address, B256}; 2 | 3 | pub fn calc_preimage_address(preimage_hash: &B256) -> Address { 4 | let preimage_hash: [u8; 20] = preimage_hash.0[12..].try_into().unwrap(); 5 | Address::from(preimage_hash) 6 | } 7 | -------------------------------------------------------------------------------- /crates/types/src/rwasm.rs: -------------------------------------------------------------------------------- 1 | use crate::{create_import_linker, sys_func_idx::SysFuncIdx, Bytes, STATE_DEPLOY, STATE_MAIN}; 2 | use alloc::{boxed::Box, string::ToString, vec}; 3 | use rwasm::legacy::{ 4 | engine::{bytecode::Instruction, RwasmConfig, StateRouterConfig}, 5 | rwasm::{BinaryFormat, BinaryFormatWriter, RwasmModule}, 6 | Config, 7 | Error, 8 | }; 9 | 10 | pub struct RwasmCompilationResult { 11 | pub rwasm_bytecode: Bytes, 12 | pub constructor_params: Bytes, 13 | } 14 | 15 | pub fn default_compilation_config() -> Config { 16 | let mut config = RwasmModule::default_config(None); 17 | config.rwasm_config(RwasmConfig { 18 | state_router: Some(StateRouterConfig { 19 | states: Box::new([ 20 | ("deploy".to_string(), STATE_DEPLOY), 21 | ("main".to_string(), STATE_MAIN), 22 | ]), 23 | opcode: Instruction::Call(SysFuncIdx::STATE.into()), 24 | }), 25 | entrypoint_name: None, 26 | import_linker: Some(create_import_linker()), 27 | wrap_import_functions: true, 28 | translate_drop_keep: false, 29 | allow_malformed_entrypoint_func_type: false, 30 | use_32bit_mode: false, 31 | builtins_consume_fuel: true, 32 | }); 33 | config 34 | } 35 | 36 | pub fn compile_wasm_to_rwasm_with_config( 37 | wasm_binary: &[u8], 38 | config: Config, 39 | ) -> Result { 40 | let (rwasm_module, constructor_params) = 41 | RwasmModule::compile_and_retrieve_input(wasm_binary, &config)?; 42 | let length = rwasm_module.encoded_length(); 43 | let mut rwasm_bytecode = vec![0u8; length]; 44 | let mut binary_format_writer = BinaryFormatWriter::new(&mut rwasm_bytecode); 45 | rwasm_module 46 | .write_binary(&mut binary_format_writer) 47 | .expect("failed to encode rwasm bytecode"); 48 | Ok(RwasmCompilationResult { 49 | rwasm_bytecode: rwasm_bytecode.into(), 50 | constructor_params: constructor_params.into(), 51 | }) 52 | } 53 | 54 | pub fn compile_wasm_to_rwasm(wasm_binary: &[u8]) -> Result { 55 | compile_wasm_to_rwasm_with_config(wasm_binary, default_compilation_config()) 56 | } 57 | -------------------------------------------------------------------------------- /e2e/.gitignore: -------------------------------------------------------------------------------- 1 | /tmp 2 | flamegraph.svg -------------------------------------------------------------------------------- /e2e/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fluentbase-e2e" 3 | version = "0.1.0" 4 | authors.workspace = true 5 | repository.workspace = true 6 | edition.workspace = true 7 | readme.workspace = true 8 | license.workspace = true 9 | keywords.workspace = true 10 | categories.workspace = true 11 | 12 | [dependencies] 13 | fluentbase-codec = { workspace = true } 14 | fluentbase-genesis = { workspace = true } 15 | fluentbase-runtime = { workspace = true } 16 | fluentbase-sdk = { workspace = true } 17 | fluentbase-sdk-testing = { workspace = true } 18 | fluentbase-types = { workspace = true } 19 | 20 | fluentbase-contracts-nitro = { path = "../contracts/nitro" } 21 | 22 | fluentbase-examples-abi-solidity = { path = "../examples/abi-solidity" } 23 | fluentbase-examples-checkmate = { path = "../examples/checkmate" } 24 | fluentbase-examples-client-solidity = { path = "../examples/client-solidity" } 25 | fluentbase-examples-constructor-params = { path = "../examples/constructor-params" } 26 | fluentbase-examples-erc20 = { path = "../examples/erc20" } 27 | fluentbase-examples-greeting = { path = "../examples/greeting" } 28 | fluentbase-examples-json = { path = "../examples/json" } 29 | fluentbase-examples-keccak = { path = "../examples/keccak" } 30 | fluentbase-examples-panic = { path = "../examples/panic" } 31 | fluentbase-examples-router-solidity = { path = "../examples/router-solidity" } 32 | fluentbase-examples-rwasm = { path = "../examples/rwasm" } 33 | fluentbase-examples-secp256k1 = { path = "../examples/secp256k1" } 34 | fluentbase-examples-simple-storage = { path = "../examples/simple-storage" } 35 | fluentbase-examples-storage = { path = "../examples/storage" } 36 | fluentbase-examples-tiny-keccak = { path = "../examples/tiny-keccak" } 37 | 38 | rwasm = { workspace = true } 39 | revm = { workspace = true } 40 | hex-literal = { workspace = true } 41 | hex = { workspace = true } 42 | alloy-sol-types = { workspace = true } 43 | wat = { version = "1.223.0" } 44 | 45 | tikv-jemallocator = "0.6.0" 46 | 47 | [build-dependencies] 48 | fluentbase-build = { workspace = true } 49 | cargo_metadata = "0.19.1" 50 | 51 | [features] 52 | default = ["std", "fluentbase-runtime/debug-print"] 53 | std = [ 54 | "fluentbase-codec/std", 55 | "fluentbase-genesis/std", 56 | "fluentbase-runtime/std", 57 | "fluentbase-sdk/std", 58 | "rwasm/std", 59 | "revm/std", 60 | ] 61 | -------------------------------------------------------------------------------- /e2e/Makefile: -------------------------------------------------------------------------------- 1 | FILES = assets/HelloWorld.bin assets/Storage.bin assets/CallWasm.bin assets/ERC20.bin assets/DelegateCaller.bin assets/Multicall.bin assets/Router.bin assets/ContractDeployer.bin 2 | 3 | assets/%.bin: assets/%.sol 4 | solc --bin --overwrite $< -o assets/ 5 | 6 | all: $(FILES) 7 | -------------------------------------------------------------------------------- /e2e/assets/CallWasm.bin: -------------------------------------------------------------------------------- 1 | 608060405260b780600f5f395ff3fe6080604052348015600e575f5ffd5b50600436106026575f3560e01c806365becaf314602a575b5f5ffd5b60306032565b005b5f73111111111111111111111111111111111111111190505f60405180602001604052805f81525090505f5f9050604051825160208401818184375f5f83855f8a6107d0f1935050505050505056fea26469706673582212207eef72b1ab13ead60c06c9a0f00f0a2c74c2438d873e963f3b2bf9a2e092874564736f6c634300081c0033 -------------------------------------------------------------------------------- /e2e/assets/CallWasm.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.24; 3 | 4 | contract CallWasm { 5 | constructor() payable { 6 | } 7 | function callWasm() public { 8 | address target = 0x1111111111111111111111111111111111111111; 9 | bytes memory data = ""; 10 | bool success = false; 11 | assembly { 12 | let freeMemoryPointer := mload(0x40) 13 | 14 | let dataLength := mload(data) 15 | let dataPointer := add(data, 0x20) 16 | calldatacopy(freeMemoryPointer, dataPointer, dataLength) 17 | 18 | 19 | success := call( 20 | 2000, 21 | target, 22 | 0, 23 | freeMemoryPointer, 24 | dataLength, 25 | 0, 26 | 0 27 | ) 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /e2e/assets/ContractDeployer.bin: -------------------------------------------------------------------------------- 1 | 6080604052348015600e575f5ffd5b506102978061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610028575f3560e01c80627743601461002c575b5f5ffd5b610046600480360381019061004191906101c2565b61005c565b6040516100539190610248565b60405180910390f35b5f8151602083015ff0905080610070575f5ffd5b919050565b5f604051905090565b5f5ffd5b5f5ffd5b5f5ffd5b5f5ffd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6100d48261008e565b810181811067ffffffffffffffff821117156100f3576100f261009e565b5b80604052505050565b5f610105610075565b905061011182826100cb565b919050565b5f67ffffffffffffffff8211156101305761012f61009e565b5b6101398261008e565b9050602081019050919050565b828183375f83830152505050565b5f61016661016184610116565b6100fc565b9050828152602081018484840111156101825761018161008a565b5b61018d848285610146565b509392505050565b5f82601f8301126101a9576101a8610086565b5b81356101b9848260208601610154565b91505092915050565b5f602082840312156101d7576101d661007e565b5b5f82013567ffffffffffffffff8111156101f4576101f3610082565b5b61020084828501610195565b91505092915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f61023282610209565b9050919050565b61024281610228565b82525050565b5f60208201905061025b5f830184610239565b9291505056fea264697066735822122012ac71e0739f9f61f25ba6b050bb74e8bfd86db2c89e88dae97ced168d3c21b664736f6c634300081c0033 -------------------------------------------------------------------------------- /e2e/assets/ContractDeployer.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.28; 3 | 4 | contract ContractDeployer { 5 | function deploy(bytes memory bytecode) public returns (address contractAddress) { 6 | assembly { 7 | contractAddress := create(0, add(bytecode, 0x20), mload(bytecode)) 8 | if iszero(contractAddress) { 9 | revert(0, 0) 10 | } 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /e2e/assets/DelegateCaller.bin: -------------------------------------------------------------------------------- 1 | 6080604052348015600e575f5ffd5b506105278061001c5f395ff3fe608060405234801561000f575f5ffd5b506004361061003f575f3560e01c806387dd399714610043578063c137b6af14610073578063cc4b2091146100a3575b5f5ffd5b61005d600480360381019061005891906103dc565b6100c1565b60405161006a9190610477565b60405180910390f35b61008d600480360381019061008891906103dc565b610201565b60405161009a9190610477565b60405180910390f35b6100ab610341565b6040516100b89190610477565b60405180910390f35b60605f6040516024016040516020818303038152906040527fcc4b2091000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090505f5f8473ffffffffffffffffffffffffffffffffffffffff168360405161017091906104db565b5f60405180830381855af49150503d805f81146101a8576040519150601f19603f3d011682016040523d82523d5f602084013e6101ad565b606091505b50915091508181906101f5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ec9190610477565b60405180910390fd5b50809350505050919050565b60605f6040516024016040516020818303038152906040527f45773e4e000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090505f5f8473ffffffffffffffffffffffffffffffffffffffff16836040516102b091906104db565b5f60405180830381855af49150503d805f81146102e8576040519150601f19603f3d011682016040523d82523d5f602084013e6102ed565b606091505b5091509150818190610335576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161032c9190610477565b60405180910390fd5b50809350505050919050565b60606040518060400160405280601481526020017f48656c6c6f2066726f6d2064656c656761746f72000000000000000000000000815250905090565b5f5ffd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6103ab82610382565b9050919050565b6103bb816103a1565b81146103c5575f5ffd5b50565b5f813590506103d6816103b2565b92915050565b5f602082840312156103f1576103f061037e565b5b5f6103fe848285016103c8565b91505092915050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f61044982610407565b6104538185610411565b9350610463818560208601610421565b61046c8161042f565b840191505092915050565b5f6020820190508181035f83015261048f818461043f565b905092915050565b5f81519050919050565b5f81905092915050565b5f6104b582610497565b6104bf81856104a1565b93506104cf818560208601610421565b80840191505092915050565b5f6104e682846104ab565b91508190509291505056fea26469706673582212200e820917c19ab34f116bdc7821d13f8221aa763ca2d5903cd8555053d1920e5e64736f6c634300081c0033 -------------------------------------------------------------------------------- /e2e/assets/DelegateCaller.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.24; 3 | 4 | contract DelegateCaller { 5 | function sayHelloMyself(address _target) public returns (string memory) { 6 | bytes memory data = abi.encodeWithSignature("sayHelloFromDelegator()"); 7 | 8 | (bool success, bytes memory returnData) = _target.delegatecall(data); 9 | 10 | require(success, string(returnData)); 11 | 12 | return string(returnData); 13 | } 14 | 15 | function sayHelloFromDelegator() public pure returns (string memory){ 16 | return "Hello from delegator"; 17 | } 18 | 19 | function executeDelegateCall(address _target) public returns (string memory) { 20 | bytes memory data = abi.encodeWithSignature("sayHelloWorld()"); 21 | 22 | (bool success, bytes memory returnData) = _target.delegatecall(data); 23 | 24 | require(success, string(returnData)); 25 | 26 | return string(returnData); 27 | } 28 | } -------------------------------------------------------------------------------- /e2e/assets/ERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.2; 3 | 4 | contract ERC20 { 5 | mapping(address => uint) public balances; 6 | mapping(address => mapping(address => uint)) public allowance; 7 | uint public totalSupply = 99000000000000 * 10 ** 18; 8 | string public name = "Test89"; 9 | string public symbol = "Test89"; 10 | uint public decimals = 18; 11 | 12 | 13 | event Transfer(address indexed from, address indexed to, uint value); 14 | event Approval(address indexed owner, address indexed spender, uint value); 15 | 16 | constructor() { 17 | balances[msg.sender] = totalSupply; 18 | } 19 | 20 | function balanceOf(address owner) public view returns(uint) { 21 | return balances[owner]; 22 | } 23 | 24 | function transfer(address to, uint value) public returns(bool) { 25 | require(balanceOf(msg.sender) >= value, 'balance too low'); 26 | balances[to] += value; 27 | balances[msg.sender] -= value; 28 | emit Transfer(msg.sender, to, value); 29 | return true; 30 | } 31 | 32 | function transferFrom(address from, address to, uint value) public returns(bool) { 33 | require(balanceOf(from) >= value, 'balance too low'); 34 | require(allowance[from][msg.sender] >= value, 'allowance too low'); 35 | balances[to] += value; 36 | balances[from] -= value; 37 | emit Transfer(from, to, value); 38 | return true; 39 | } 40 | 41 | function approve(address spender, uint value) public returns (bool) { 42 | allowance[msg.sender][spender] = value; 43 | emit Approval(msg.sender, spender, value); 44 | return true; 45 | } 46 | } -------------------------------------------------------------------------------- /e2e/assets/HelloWorld.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.24; 3 | 4 | contract HelloWorld { 5 | constructor() payable { 6 | } 7 | function sayHelloWorld() public pure returns (string memory) { 8 | return "Hello, World"; 9 | } 10 | function getBalanceAsStr(address addr) public view returns (string memory) { 11 | uint256 balance = addr.balance; 12 | return toString(balance); 13 | } 14 | function getSelfBalanceAsStr() public view returns (string memory) { 15 | uint256 balance = address(this).balance; 16 | return toString(balance); 17 | } 18 | function toString(uint256 value) internal pure returns (string memory) { 19 | if (value == 0) { 20 | return "0"; 21 | } 22 | uint256 temp = value; 23 | uint256 digits; 24 | while (temp != 0) { 25 | digits++; 26 | temp /= 10; 27 | } 28 | bytes memory buffer = new bytes(digits); 29 | while (value != 0) { 30 | digits--; 31 | buffer[digits] = bytes1(uint8(48 + (value % 10))); 32 | value /= 10; 33 | } 34 | return string(buffer); 35 | } 36 | } -------------------------------------------------------------------------------- /e2e/assets/Multicall.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.20; 3 | 4 | contract Multicall { 5 | /** 6 | * @dev Executes a batch of function calls on this contract. 7 | * @param data An array of encoded function calls 8 | * @return results An array containing the results of each function call 9 | */ 10 | function multicall(bytes[] calldata data) external returns (bytes[] memory results) { 11 | results = new bytes[](data.length); 12 | 13 | // Execute each call and store its result 14 | for (uint256 i = 0; i < data.length; i++) { 15 | (bool success, bytes memory result) = address(this).delegatecall(data[i]); 16 | require(success, "Multicall: call failed"); 17 | results[i] = result; 18 | } 19 | 20 | return results; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /e2e/assets/Router.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.20; 3 | 4 | import "./Multicall.sol"; 5 | 6 | contract Router is Multicall { 7 | /// @notice Simple echo function that returns the input message 8 | /// @param message The message to echo back 9 | /// @return The same message that was passed in 10 | function greeting(string memory message) public pure returns (string memory) { 11 | return message; 12 | } 13 | 14 | /// @notice Another echo function with a different name 15 | /// @param message The message to echo back 16 | /// @return The same message that was passed in 17 | function customGreeting(string memory message) public pure returns (string memory) { 18 | return message; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /e2e/assets/Storage.bin: -------------------------------------------------------------------------------- 1 | 608060405260645f81905550606460015f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2081905550606460025f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f3073ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20819055506103ed806100d95f395ff3fe608060405234801561000f575f5ffd5b5060043610610034575f3560e01c806320965255146100385780635524107714610056575b5f5ffd5b610040610072565b60405161004d91906102cd565b60405180910390f35b610070600480360381019061006b9190610314565b6101b5565b005b5f5f5460015f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054146100f3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100ea90610399565b60405180910390fd5b5f5460025f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f3073ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054146101ae576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101a590610399565b60405180910390fd5b5f54905090565b805f819055508060015f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20819055508060025f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f3073ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20819055507f63a242a632efe33c0e210e04e4173612a17efa4f16aa4890bc7e46caece80de05f546040516102aa91906102cd565b60405180910390a150565b5f819050919050565b6102c7816102b5565b82525050565b5f6020820190506102e05f8301846102be565b92915050565b5f5ffd5b6102f3816102b5565b81146102fd575f5ffd5b50565b5f8135905061030e816102ea565b92915050565b5f60208284031215610329576103286102e6565b5b5f61033684828501610300565b91505092915050565b5f82825260208201905092915050565b7f76616c7565206d69736d617463680000000000000000000000000000000000005f82015250565b5f610383600e8361033f565b915061038e8261034f565b602082019050919050565b5f6020820190508181035f8301526103b081610377565b905091905056fea264697066735822122061269adcb11593665acb508e72791816b149c91b305750fe0fb7fade620f86a164736f6c634300081c0033 -------------------------------------------------------------------------------- /e2e/assets/Storage.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.24; 3 | 4 | contract Storage { 5 | event Test(uint256); 6 | uint256 private value; 7 | mapping(address => uint256) private balances; 8 | mapping(address => mapping(address => uint256)) private allowances; 9 | constructor() payable { 10 | value = 100; 11 | balances[msg.sender] = 100; 12 | allowances[msg.sender][address(this)] = 100; 13 | } 14 | function setValue(uint256 newValue) public { 15 | value = newValue; 16 | balances[msg.sender] = newValue; 17 | allowances[msg.sender][address(this)] = newValue; 18 | emit Test(value); 19 | } 20 | function getValue() public view returns (uint256) { 21 | require(balances[msg.sender] == value, "value mismatch"); 22 | require(allowances[msg.sender][address(this)] == value, "value mismatch"); 23 | return value; 24 | } 25 | } -------------------------------------------------------------------------------- /e2e/src/bench/bench.md: -------------------------------------------------------------------------------- 1 | | Test Case | Only Compile | Compile and Run | Run Precompile | Run Sp1 | 2 | |-----------|--------------|-----------------|----------------|------------| 3 | | shakmaty | 11,258,677 | 11,420,253 | 3,585 | 23,254,445 | 4 | | router | 11,483,502 | 11,841,037 | 6,169 | 8,300,796 | 5 | | panic | 6,699,106 | 6,985,947 | 5,067 | 4,847,334 | 6 | | keccak | 6,900,567 | 6,955,931 | 1,911 | 4,835,453 | 7 | | greeting | 6,688,298 | 6,718,250 | 1,779 | 1,258,643 | -------------------------------------------------------------------------------- /e2e/src/bench/erc20.rs: -------------------------------------------------------------------------------- 1 | extern crate test; 2 | 3 | use crate::EXAMPLE_ERC20; 4 | use fluentbase_sdk::Address; 5 | use fluentbase_sdk_testing::EvmTestingContext; 6 | use hex_literal::hex; 7 | use test::Bencher; 8 | 9 | #[bench] 10 | fn bench_evm_erc20(b: &mut Bencher) { 11 | let mut ctx = EvmTestingContext::default(); 12 | const OWNER_ADDRESS: Address = Address::ZERO; 13 | let contract_address = ctx.deploy_evm_tx( 14 | OWNER_ADDRESS, 15 | hex::decode(include_bytes!("../../assets/ERC20.bin")) 16 | .unwrap() 17 | .into(), 18 | ); 19 | 20 | let transfer_coin = |ctx: &mut EvmTestingContext| { 21 | ctx.call_evm_tx( 22 | OWNER_ADDRESS, 23 | contract_address, 24 | hex!("a9059cbb00000000000000000000000011111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000001").into(), 25 | None, 26 | None, 27 | ); 28 | }; 29 | 30 | b.iter(|| { 31 | transfer_coin(&mut ctx); 32 | }); 33 | } 34 | 35 | #[bench] 36 | fn bench_wasm_erc20(b: &mut Bencher) { 37 | let mut ctx = EvmTestingContext::default(); 38 | const OWNER_ADDRESS: Address = Address::ZERO; 39 | let contract_address = ctx.deploy_evm_tx(OWNER_ADDRESS, EXAMPLE_ERC20.into()); 40 | 41 | let transfer_coin = |ctx: &mut EvmTestingContext| { 42 | ctx.call_evm_tx( 43 | OWNER_ADDRESS, 44 | contract_address, 45 | hex!("a9059cbb00000000000000000000000011111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000001").into(), 46 | None, 47 | None, 48 | ); 49 | }; 50 | 51 | b.iter(|| { 52 | transfer_coin(&mut ctx); 53 | }); 54 | } 55 | -------------------------------------------------------------------------------- /e2e/src/bench/greeting.rs: -------------------------------------------------------------------------------- 1 | extern crate test; 2 | 3 | use crate::EXAMPLE_GREETING; 4 | use fluentbase_sdk::{Address, Bytes}; 5 | use fluentbase_sdk_testing::EvmTestingContext; 6 | use hex_literal::hex; 7 | use test::Bencher; 8 | 9 | #[bench] 10 | fn bench_evm_greeting(b: &mut Bencher) { 11 | let mut ctx = EvmTestingContext::default(); 12 | const OWNER_ADDRESS: Address = Address::ZERO; 13 | let contract_address = ctx.deploy_evm_tx( 14 | OWNER_ADDRESS, 15 | hex::decode(include_bytes!("../../assets/HelloWorld.bin")) 16 | .unwrap() 17 | .into(), 18 | ); 19 | 20 | let hello_world = |ctx: &mut EvmTestingContext| { 21 | ctx.call_evm_tx( 22 | OWNER_ADDRESS, 23 | contract_address, 24 | hex!("45773e4e").into(), 25 | None, 26 | None, 27 | ); 28 | }; 29 | 30 | b.iter(|| { 31 | hello_world(&mut ctx); 32 | }); 33 | } 34 | 35 | #[bench] 36 | fn bench_wasm_greeting(b: &mut Bencher) { 37 | let mut ctx = EvmTestingContext::default(); 38 | const OWNER_ADDRESS: Address = Address::ZERO; 39 | let contract_address = ctx.deploy_evm_tx(OWNER_ADDRESS, EXAMPLE_GREETING.into()); 40 | 41 | let hello_world = |ctx: &mut EvmTestingContext| { 42 | ctx.call_evm_tx( 43 | OWNER_ADDRESS, 44 | contract_address, 45 | Bytes::default(), 46 | None, 47 | None, 48 | ); 49 | }; 50 | 51 | b.iter(|| { 52 | hello_world(&mut ctx); 53 | }); 54 | } 55 | -------------------------------------------------------------------------------- /e2e/src/constructor.rs: -------------------------------------------------------------------------------- 1 | use fluentbase_sdk_testing::EvmTestingContext; 2 | use alloc::vec::Vec; 3 | use fluentbase_sdk::{constructor::encode_constructor_params, Address, Bytes}; 4 | use hex_literal::hex; 5 | 6 | #[test] 7 | fn test_deploy_with_constructor_params() { 8 | let mut ctx = EvmTestingContext::default(); 9 | const DEPLOYER_ADDRESS: Address = Address::ZERO; 10 | let bytecode: Vec = crate::EXAMPLE_CONSTRUCTOR_PARAMS.into(); 11 | let constructor_params: Vec = 12 | hex!("68656c6c6fffffffffffffffffffffffffffffffffffffffffffffffffffffff").into(); 13 | let encoded_params = encode_constructor_params(&constructor_params); 14 | let mut input: Vec = Vec::new(); 15 | input.extend(bytecode); 16 | input.extend(encoded_params); 17 | let contract_address = ctx.deploy_evm_tx(DEPLOYER_ADDRESS, input.into()); 18 | println!("contract address: {:?}", contract_address); 19 | let result = ctx.call_evm_tx( 20 | DEPLOYER_ADDRESS, 21 | contract_address, 22 | Bytes::default(), 23 | None, 24 | None, 25 | ); 26 | println!("gas used: {:?}", result.gas_used()); 27 | assert!(result.is_success()); 28 | let bytes = result.output().unwrap_or_default(); 29 | assert_eq!(constructor_params, bytes.to_vec()); 30 | } 31 | -------------------------------------------------------------------------------- /e2e/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(soft_unstable)] 2 | #![feature(test)] 3 | 4 | extern crate alloc; 5 | extern crate core; 6 | 7 | #[cfg(test)] 8 | mod bench; 9 | #[cfg(test)] 10 | mod bridge; 11 | #[cfg(test)] 12 | mod builtins; 13 | #[cfg(test)] 14 | mod constructor; 15 | #[cfg(test)] 16 | mod deployer; 17 | #[cfg(test)] 18 | mod evm; 19 | #[cfg(test)] 20 | mod gas; 21 | #[cfg(test)] 22 | mod multicall; 23 | #[cfg(test)] 24 | mod nitro; 25 | #[cfg(test)] 26 | mod router; 27 | #[cfg(test)] 28 | mod stateless; 29 | #[cfg(test)] 30 | mod wasm; 31 | 32 | pub const EXAMPLE_ABI_SOLIDITY: &[u8] = fluentbase_examples_abi_solidity::WASM_BYTECODE; 33 | pub const EXAMPLE_CHECKMATE: &[u8] = fluentbase_examples_checkmate::WASM_BYTECODE; 34 | pub const EXAMPLE_CLIENT_SOLIDITY: &[u8] = fluentbase_examples_client_solidity::WASM_BYTECODE; 35 | pub const EXAMPLE_CONSTRUCTOR_PARAMS: &[u8] = fluentbase_examples_constructor_params::WASM_BYTECODE; 36 | pub const EXAMPLE_ERC20: &[u8] = fluentbase_examples_erc20::WASM_BYTECODE; 37 | pub const EXAMPLE_GREETING: &[u8] = fluentbase_examples_greeting::WASM_BYTECODE; 38 | pub const EXAMPLE_JSON: &[u8] = fluentbase_examples_json::WASM_BYTECODE; 39 | pub const EXAMPLE_KECCAK256: &[u8] = fluentbase_examples_keccak::WASM_BYTECODE; 40 | pub const EXAMPLE_PANIC: &[u8] = fluentbase_examples_panic::WASM_BYTECODE; 41 | pub const EXAMPLE_ROUTER_SOLIDITY: &[u8] = fluentbase_examples_router_solidity::WASM_BYTECODE; 42 | pub const EXAMPLE_RWASM: &[u8] = fluentbase_examples_rwasm::WASM_BYTECODE; 43 | pub const EXAMPLE_SECP256K1: &[u8] = fluentbase_examples_secp256k1::WASM_BYTECODE; 44 | pub const EXAMPLE_SIMPLE_STORAGE: &[u8] = fluentbase_examples_simple_storage::WASM_BYTECODE; 45 | pub const EXAMPLE_STORAGE: &[u8] = fluentbase_examples_storage::WASM_BYTECODE; 46 | pub const EXAMPLE_TINY_KECCAK256: &[u8] = fluentbase_examples_tiny_keccak::WASM_BYTECODE; 47 | -------------------------------------------------------------------------------- /e2e/src/router.rs: -------------------------------------------------------------------------------- 1 | use fluentbase_sdk_testing::EvmTestingContext; 2 | use fluentbase_codec::SolidityABI; 3 | use fluentbase_sdk::{address, Address, U256}; 4 | use hex_literal::hex; 5 | 6 | #[test] 7 | fn test_client_solidity() { 8 | let mut ctx = EvmTestingContext::default(); 9 | const DEPLOYER_ADDRESS: Address = address!("1231238908230948230948209348203984029834"); 10 | ctx.add_balance(DEPLOYER_ADDRESS, U256::from(10e18)); 11 | 12 | let (contract_address, _) = ctx.deploy_evm_tx_with_nonce( 13 | DEPLOYER_ADDRESS, 14 | crate::EXAMPLE_ROUTER_SOLIDITY.into(), 15 | 0, 16 | ); 17 | println!("contract_address: {:?}", contract_address); 18 | 19 | let (client_address, _) = ctx.deploy_evm_tx_with_nonce( 20 | DEPLOYER_ADDRESS, 21 | crate::EXAMPLE_CLIENT_SOLIDITY.into(), 22 | 1, 23 | ); 24 | println!("client_address: {:?}", client_address); 25 | 26 | ctx.add_balance(contract_address, U256::from(10e18)); 27 | ctx.add_balance(client_address, U256::from(10e18)); 28 | 29 | let client_input = hex!("f60ea708000000000000000000000000f91c20c0cafbfdc150adff51bbfc5808edde7cb50000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a4100000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000b48656c6c6f20576f726c64000000000000000000000000000000000000000000"); 30 | 31 | println!("calling client..."); 32 | let result = ctx.call_evm_tx( 33 | DEPLOYER_ADDRESS, 34 | client_address, 35 | client_input.into(), 36 | None, 37 | None, 38 | ); 39 | 40 | println!("result: {:?}", result); 41 | 42 | assert_eq!(result.is_success(), true); 43 | 44 | let output = result.output(); 45 | println!("output: {:?}", output); 46 | let msg_b = result.output().unwrap(); 47 | 48 | let msg: String = SolidityABI::decode(msg_b, 0).unwrap(); 49 | 50 | assert_eq!(msg, "Hello World"); 51 | } 52 | -------------------------------------------------------------------------------- /e2e/src/stateless.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | EXAMPLE_GREETING, 3 | EXAMPLE_PANIC, 4 | EXAMPLE_ROUTER_SOLIDITY, 5 | EXAMPLE_RWASM, 6 | EXAMPLE_TINY_KECCAK256, 7 | }; 8 | use core::str::from_utf8; 9 | use fluentbase_sdk_testing::run_with_default_context; 10 | use hex_literal::hex; 11 | 12 | #[test] 13 | fn test_example_greeting() { 14 | let (output, exit_code) = 15 | run_with_default_context(EXAMPLE_GREETING.to_vec(), "Hello, World".as_bytes()); 16 | assert_eq!(exit_code, 0); 17 | assert_eq!(output.clone(), "Hello, World".as_bytes().to_vec()); 18 | } 19 | 20 | #[test] 21 | fn test_example_keccak256() { 22 | let (output, exit_code) = 23 | run_with_default_context(EXAMPLE_TINY_KECCAK256.to_vec(), "Hello, World".as_bytes()); 24 | assert_eq!(exit_code, 0); 25 | assert_eq!( 26 | output[0..32], 27 | hex!("a04a451028d0f9284ce82243755e245238ab1e4ecf7b9dd8bf4734d9ecfd0529").to_vec() 28 | ); 29 | } 30 | 31 | #[test] 32 | fn test_example_rwasm() { 33 | let input_data = EXAMPLE_GREETING; 34 | let (output, exit_code) = run_with_default_context(EXAMPLE_RWASM.to_vec(), input_data); 35 | assert_eq!(exit_code, 0); 36 | assert_eq!(output[0], 0xef); 37 | } 38 | 39 | #[test] 40 | fn test_example_panic() { 41 | let (output, exit_code) = run_with_default_context(EXAMPLE_PANIC.to_vec(), &[]); 42 | assert_eq!(from_utf8(&output[..]).unwrap(), "it's panic time",); 43 | assert_eq!(exit_code, -1); 44 | } 45 | 46 | #[test] 47 | fn test_example_router() { 48 | let (output, exit_code) = run_with_default_context(EXAMPLE_ROUTER_SOLIDITY.to_vec(), &hex!("f8194e480000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000e2248656c6c6f2c20576f726c6422000000000000000000000000000000000000")); 49 | assert_eq!(&output, &hex!("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000e2248656c6c6f2c20576f726c6422000000000000000000000000000000000000")); 50 | assert_eq!(exit_code, 0); 51 | } 52 | -------------------------------------------------------------------------------- /examples/abi-solidity/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fluentbase-examples-abi-solidity" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | fluentbase-sdk = { workspace = true } 8 | hex-literal = { workspace = true } 9 | 10 | [dev-dependencies] 11 | fluentbase-sdk-testing = { workspace = true } 12 | 13 | [build-dependencies] 14 | fluentbase-build = { workspace = true } 15 | fluentbase-sdk = { workspace = true } 16 | hex-literal = { workspace = true } 17 | 18 | [features] 19 | default = ["std"] 20 | std = ["fluentbase-sdk/std"] 21 | -------------------------------------------------------------------------------- /examples/abi-solidity/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | fluentbase_build::build_default_example_contract(); 3 | } 4 | -------------------------------------------------------------------------------- /examples/abi-solidity/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(target_arch = "wasm32"))] 2 | pub const WASM_BYTECODE: &[u8] = fluentbase_sdk::include_this_wasm!(); 3 | -------------------------------------------------------------------------------- /examples/abi-solidity/src/main.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(target_arch = "wasm32", no_std, no_main)] 2 | extern crate fluentbase_sdk; 3 | 4 | use fluentbase_sdk::{bytes::BytesMut, codec::SolidityABI, entrypoint, SharedAPI, U256}; 5 | 6 | pub fn main_entry(mut sdk: impl SharedAPI) { 7 | let input = sdk.input(); 8 | let value: U256 = 9 | SolidityABI::decode(&input, 0).unwrap_or_else(|_| panic!("malformed ABI input")); 10 | let value = value * U256::from(2); 11 | let mut output = BytesMut::new(); 12 | SolidityABI::encode(&value, &mut output, 0).unwrap_or_else(|_| panic!("decode ABI failed")); 13 | sdk.write(&output); 14 | } 15 | 16 | entrypoint!(main_entry); 17 | 18 | #[cfg(test)] 19 | mod tests { 20 | use super::*; 21 | use fluentbase_sdk_testing::HostTestingContext; 22 | use hex_literal::hex; 23 | 24 | #[test] 25 | fn test_contract_works() { 26 | let sdk = HostTestingContext::default().with_input(hex!( 27 | "000000000000000000000000000000000000000000000000000000000000007b" 28 | )); 29 | main_entry(sdk.clone()); 30 | let output = sdk.take_output(); 31 | let value = U256::from_be_slice(&output); 32 | assert_eq!(value, U256::from(246)); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /examples/checkmate/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fluentbase-examples-checkmate" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | fluentbase-sdk = { workspace = true } 8 | 9 | # shakmaty 10 | shakmaty = { git = "https://github.com/niklasf/shakmaty", default-features = false, features = [ 11 | "alloc", 12 | ] } 13 | 14 | [dev-dependencies] 15 | fluentbase-sdk-testing = { workspace = true } 16 | 17 | [build-dependencies] 18 | fluentbase-build = { workspace = true } 19 | fluentbase-sdk = { workspace = true } 20 | 21 | [features] 22 | default = ["std"] 23 | std = ["fluentbase-sdk/std"] 24 | -------------------------------------------------------------------------------- /examples/checkmate/README.md: -------------------------------------------------------------------------------- 1 | # Chess validator 2 | 3 | An example of integrating external Rust libraries (like Shakmaty chess engine) into Fluent Network. 4 | -------------------------------------------------------------------------------- /examples/checkmate/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | fluentbase_build::build_default_example_contract(); 3 | } 4 | -------------------------------------------------------------------------------- /examples/checkmate/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(target_arch = "wasm32"))] 2 | pub const WASM_BYTECODE: &[u8] = fluentbase_sdk::include_this_wasm!(); 3 | -------------------------------------------------------------------------------- /examples/client-solidity/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "fluentbase-examples-client-solidity" 4 | version = "0.1.0" 5 | 6 | [dependencies] 7 | fluentbase-sdk = { workspace = true } 8 | 9 | [dev-dependencies] 10 | hex = "0.4.3" 11 | 12 | [build-dependencies] 13 | fluentbase-build = { workspace = true } 14 | fluentbase-sdk = { workspace = true } 15 | 16 | [features] 17 | default = ["std"] 18 | std = ["fluentbase-sdk/std"] 19 | -------------------------------------------------------------------------------- /examples/client-solidity/README.md: -------------------------------------------------------------------------------- 1 | # Client solidity mode 2 | 3 | An example of generating WASM contract clients using traits to simplify cross-contract calls in Fluent Network. 4 | -------------------------------------------------------------------------------- /examples/client-solidity/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | fluentbase_build::build_default_example_contract(); 3 | } 4 | -------------------------------------------------------------------------------- /examples/client-solidity/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(target_arch = "wasm32"))] 2 | pub const WASM_BYTECODE: &[u8] = fluentbase_sdk::include_this_wasm!(); 3 | -------------------------------------------------------------------------------- /examples/constructor-params/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fluentbase-examples-constructor-params" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | fluentbase-sdk = { workspace = true } 8 | 9 | [dev-dependencies] 10 | fluentbase-sdk-testing = { workspace = true } 11 | 12 | [build-dependencies] 13 | fluentbase-build = { workspace = true } 14 | fluentbase-sdk = { workspace = true } 15 | 16 | [features] 17 | default = ["std"] 18 | std = ["fluentbase-sdk/std"] 19 | -------------------------------------------------------------------------------- /examples/constructor-params/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | fluentbase_build::build_default_example_contract(); 3 | } 4 | -------------------------------------------------------------------------------- /examples/constructor-params/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(target_arch = "wasm32"))] 2 | pub const WASM_BYTECODE: &[u8] = fluentbase_sdk::include_this_wasm!(); 3 | -------------------------------------------------------------------------------- /examples/constructor-params/src/main.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(target_arch = "wasm32", no_std, no_main)] 2 | #![allow(dead_code)] 3 | extern crate alloc; 4 | extern crate fluentbase_sdk; 5 | 6 | use fluentbase_sdk::{derive::solidity_storage, entrypoint, SharedAPI, U256}; 7 | 8 | solidity_storage! { 9 | U256 Value; 10 | } 11 | 12 | fn deploy(mut sdk: impl SharedAPI) { 13 | let mut input = [0u8; 32]; 14 | sdk.read(&mut input, 0); 15 | let value = U256::from_le_bytes(input); 16 | sdk.write_storage(Value::SLOT, value); 17 | } 18 | 19 | fn main_entry(mut sdk: impl SharedAPI) { 20 | let value = sdk.storage(&Value::SLOT); 21 | sdk.write(&value.to_le_bytes::<32>()); 22 | } 23 | 24 | entrypoint!(main_entry, deploy); 25 | 26 | #[cfg(test)] 27 | mod tests { 28 | use super::*; 29 | use fluentbase_sdk::{address, ContractContextV1, U256}; 30 | use fluentbase_sdk_testing::HostTestingContext; 31 | 32 | #[test] 33 | fn test_constructor_params() { 34 | let context = ContractContextV1 { 35 | address: address!("1111111111111111111111111111111111111111"), 36 | bytecode_address: address!("2222222222222222222222222222222222222222"), 37 | caller: address!("3333333333333333333333333333333333333333"), 38 | is_static: false, 39 | value: U256::ZERO, 40 | gas_limit: 0, 41 | }; 42 | let sdk = HostTestingContext::default() 43 | .with_input(U256::from(123).to_le_bytes::<32>()) 44 | .with_contract_context(context.clone()); 45 | deploy(sdk.clone()); 46 | let sdk = sdk.with_input(vec![]); 47 | main_entry(sdk.clone()); 48 | let output = sdk.take_output(); 49 | let value = U256::from_le_slice(&output); 50 | assert_eq!(value, U256::from(123)); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /examples/erc20/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fluentbase-examples-erc20" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | fluentbase-sdk = { workspace = true } 8 | 9 | # for Solidity ABI 10 | alloy-sol-types = { workspace = true } 11 | 12 | # for hex macro 13 | hex-literal = { version = "0.4.1", default-features = false } 14 | 15 | [dev-dependencies] 16 | serial_test = "3.0.0" 17 | fluentbase-sdk-testing = { workspace = true } 18 | 19 | [build-dependencies] 20 | fluentbase-build = { workspace = true } 21 | fluentbase-sdk = { workspace = true } 22 | alloy-sol-types = { workspace = true } 23 | 24 | [features] 25 | default = ["std"] 26 | std = ["fluentbase-sdk/std"] 27 | -------------------------------------------------------------------------------- /examples/erc20/README.md: -------------------------------------------------------------------------------- 1 | # ERC-20 (rust) 2 | 3 | An example of ERC-20 token written in Rust. 4 | -------------------------------------------------------------------------------- /examples/erc20/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | fluentbase_build::build_default_example_contract(); 3 | } 4 | -------------------------------------------------------------------------------- /examples/erc20/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(target_arch = "wasm32"))] 2 | pub const WASM_BYTECODE: &[u8] = fluentbase_sdk::include_this_wasm!(); 3 | -------------------------------------------------------------------------------- /examples/greeting/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fluentbase-examples-greeting" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | fluentbase-sdk = { workspace = true } 8 | 9 | [dev-dependencies] 10 | fluentbase-sdk-testing = { workspace = true } 11 | 12 | [build-dependencies] 13 | fluentbase-build = { workspace = true } 14 | fluentbase-sdk = { workspace = true } 15 | 16 | [features] 17 | default = ["std"] 18 | std = ["fluentbase-sdk/std"] 19 | -------------------------------------------------------------------------------- /examples/greeting/README.md: -------------------------------------------------------------------------------- 1 | # Greeting 2 | 3 | An example of the minimal contract. 4 | -------------------------------------------------------------------------------- /examples/greeting/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | fluentbase_build::build_default_example_contract(); 3 | } 4 | -------------------------------------------------------------------------------- /examples/greeting/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(target_arch = "wasm32"))] 2 | pub const WASM_BYTECODE: &[u8] = fluentbase_sdk::include_this_wasm!(); 3 | -------------------------------------------------------------------------------- /examples/greeting/src/main.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(target_arch = "wasm32", no_std, no_main)] 2 | extern crate alloc; 3 | extern crate fluentbase_sdk; 4 | 5 | use fluentbase_sdk::{entrypoint, SharedAPI}; 6 | 7 | #[allow(dead_code)] 8 | fn fib(n: i32) -> i32 { 9 | if n <= 0 { 10 | 0 11 | } else if n == 1 { 12 | 1 13 | } else { 14 | fib(n - 1) + fib(n - 2) 15 | } 16 | } 17 | 18 | pub fn main_entry(mut sdk: impl SharedAPI) { 19 | // calculate a fib of 47 20 | // fib(core::hint::black_box(47)); 21 | // write "Hello, World" message into output 22 | sdk.write("Hello, World".as_bytes()); 23 | } 24 | 25 | entrypoint!(main_entry); 26 | 27 | #[cfg(test)] 28 | mod tests { 29 | use super::*; 30 | use fluentbase_sdk_testing::{include_this_wasm, run_with_default_context, HostTestingContext}; 31 | const WASM_BYTECODE: &[u8] = include_this_wasm!(); 32 | 33 | #[test] 34 | fn test_contract_works() { 35 | let sdk = HostTestingContext::default(); 36 | main_entry(sdk.clone()); 37 | let output = sdk.take_output(); 38 | assert_eq!(&output, "Hello, World".as_bytes()); 39 | } 40 | 41 | #[test] 42 | fn test_contract_works_in_emulated_environment() { 43 | let (output, exit_code) = 44 | run_with_default_context(WASM_BYTECODE.to_vec(), "Hello, World".as_bytes()); 45 | assert_eq!(exit_code, 0); 46 | assert_eq!(output.clone(), "Hello, World".as_bytes().to_vec()); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /examples/json/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fluentbase-examples-json" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | fluentbase-sdk = { workspace = true } 8 | serde = { workspace = true } 9 | serde-json-core = { version = "0.6.0" } 10 | 11 | [dev-dependencies] 12 | fluentbase-sdk-testing = { workspace = true } 13 | serde_json = "1.0" 14 | 15 | [build-dependencies] 16 | fluentbase-build = { workspace = true } 17 | fluentbase-sdk = { workspace = true } 18 | serde = { workspace = true } 19 | 20 | [features] 21 | default = ["std"] 22 | std = ["fluentbase-sdk/std"] 23 | -------------------------------------------------------------------------------- /examples/json/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | fluentbase_build::build_default_example_contract(); 3 | } 4 | -------------------------------------------------------------------------------- /examples/json/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(target_arch = "wasm32"))] 2 | pub const WASM_BYTECODE: &[u8] = fluentbase_sdk::include_this_wasm!(); 3 | -------------------------------------------------------------------------------- /examples/json/src/main.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(target_arch = "wasm32", no_std, no_main)] 2 | extern crate core; 3 | extern crate fluentbase_sdk; 4 | 5 | use fluentbase_sdk::{alloc_slice, entrypoint, SharedAPI}; 6 | use serde::{Deserialize, Serialize}; 7 | 8 | #[derive(Serialize, Deserialize)] 9 | struct JsonInput<'a> { 10 | message: &'a str, 11 | } 12 | 13 | pub fn main_entry(mut sdk: impl SharedAPI) { 14 | // read input 15 | let input_size = sdk.input_size() as usize; 16 | let mut buffer = alloc_slice(input_size); 17 | sdk.read(&mut buffer, 0); 18 | // parse json and extract name 19 | let (json_input, _) = serde_json_core::from_slice::(&buffer) 20 | .unwrap_or_else(|_| panic!("invalid JSON input")); 21 | // write name as output 22 | sdk.write(json_input.message.as_bytes()); 23 | } 24 | 25 | entrypoint!(main_entry); 26 | 27 | #[cfg(test)] 28 | mod tests { 29 | use super::*; 30 | use fluentbase_sdk_testing::HostTestingContext; 31 | 32 | #[test] 33 | fn test_contract_works() { 34 | let sdk = HostTestingContext::default().with_input("{\"message\": \"Hello, World\"}"); 35 | main_entry(sdk.clone()); 36 | let output = sdk.take_output(); 37 | assert_eq!(&output, "Hello, World".as_bytes()); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /examples/keccak/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fluentbase-examples-keccak" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | fluentbase-sdk = { workspace = true } 8 | 9 | [dev-dependencies] 10 | fluentbase-sdk-testing = { workspace = true } 11 | 12 | [build-dependencies] 13 | fluentbase-build = { workspace = true } 14 | fluentbase-sdk = { workspace = true } 15 | 16 | [features] 17 | default = ["std"] 18 | std = ["fluentbase-sdk/std"] 19 | -------------------------------------------------------------------------------- /examples/keccak/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | fluentbase_build::build_default_example_contract(); 3 | } 4 | -------------------------------------------------------------------------------- /examples/keccak/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(target_arch = "wasm32"))] 2 | pub const WASM_BYTECODE: &[u8] = fluentbase_sdk::include_this_wasm!(); 3 | -------------------------------------------------------------------------------- /examples/keccak/src/main.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(target_arch = "wasm32", no_std, no_main)] 2 | extern crate fluentbase_sdk; 3 | 4 | use fluentbase_sdk::{alloc_slice, entrypoint, SharedAPI}; 5 | 6 | pub fn main_entry(mut sdk: impl SharedAPI) { 7 | let input_size = sdk.input_size(); 8 | let input = alloc_slice(input_size as usize); 9 | sdk.read(input, 0); 10 | let hash = sdk.keccak256(input); // calculate the hash via syscall to builtin keccak256 11 | sdk.write(&hash.as_slice()); 12 | } 13 | 14 | entrypoint!(main_entry); 15 | 16 | #[cfg(test)] 17 | mod tests { 18 | use super::*; 19 | use fluentbase_sdk::{hex}; 20 | use fluentbase_sdk_testing::HostTestingContext; 21 | 22 | #[test] 23 | fn test_contract_works() { 24 | let sdk = HostTestingContext::default().with_input("Hello, World"); 25 | main_entry(sdk.clone()); 26 | let output = sdk.take_output(); 27 | assert_eq!( 28 | &output[0..32], 29 | hex!("a04a451028d0f9284ce82243755e245238ab1e4ecf7b9dd8bf4734d9ecfd0529") 30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /examples/panic/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fluentbase-examples-panic" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | fluentbase-sdk = { workspace = true } 8 | 9 | [dev-dependencies] 10 | fluentbase-sdk-testing = { workspace = true } 11 | 12 | [build-dependencies] 13 | fluentbase-build = { workspace = true } 14 | fluentbase-sdk = { workspace = true } 15 | 16 | [features] 17 | default = ["std"] 18 | std = ["fluentbase-sdk/std"] 19 | -------------------------------------------------------------------------------- /examples/panic/README.md: -------------------------------------------------------------------------------- 1 | # Panic 2 | 3 | An example of the panic handling in Rust contracts. 4 | -------------------------------------------------------------------------------- /examples/panic/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | fluentbase_build::build_default_example_contract(); 3 | } 4 | -------------------------------------------------------------------------------- /examples/panic/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(target_arch = "wasm32"))] 2 | pub const WASM_BYTECODE: &[u8] = fluentbase_sdk::include_this_wasm!(); 3 | -------------------------------------------------------------------------------- /examples/panic/src/main.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(target_arch = "wasm32", no_std, no_main)] 2 | #![allow(unused)] 3 | extern crate fluentbase_sdk; 4 | 5 | use fluentbase_sdk::{entrypoint, SharedAPI}; 6 | 7 | pub fn main_entry(mut sdk: impl SharedAPI) { 8 | // panic with some message 9 | panic!("it's panic time"); 10 | } 11 | 12 | entrypoint!(main_entry); 13 | 14 | #[cfg(test)] 15 | mod tests { 16 | use super::*; 17 | use fluentbase_sdk_testing::HostTestingContext; 18 | 19 | #[should_panic(expected = "it's panic time")] 20 | #[test] 21 | fn tets_contract_works() { 22 | let sdk = HostTestingContext::default(); 23 | main_entry(sdk); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /examples/router-solidity/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "fluentbase-examples-router-solidity" 4 | version = "0.1.0" 5 | 6 | [dependencies] 7 | fluentbase-sdk = { workspace = true } 8 | 9 | [dev-dependencies] 10 | alloy-sol-types = { workspace = true, default-features = false } 11 | fluentbase-sdk-testing = { workspace = true } 12 | hex = "0.4.3" 13 | 14 | [build-dependencies] 15 | fluentbase-build = { workspace = true } 16 | fluentbase-sdk = { workspace = true } 17 | 18 | [features] 19 | default = ["std"] 20 | std = ["fluentbase-sdk/std"] 21 | -------------------------------------------------------------------------------- /examples/router-solidity/README.md: -------------------------------------------------------------------------------- 1 | # Router macro (solidity mode) 2 | 3 | An example of the `router!` macro usage. For real world example, you can check the [ERC-20](../erc20) example. 4 | -------------------------------------------------------------------------------- /examples/router-solidity/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | fluentbase_build::build_default_example_contract(); 3 | } 4 | -------------------------------------------------------------------------------- /examples/router-solidity/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(target_arch = "wasm32"))] 2 | pub const WASM_BYTECODE: &[u8] = fluentbase_sdk::include_this_wasm!(); 3 | -------------------------------------------------------------------------------- /examples/rwasm/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fluentbase-examples-rwasm" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | fluentbase-sdk = { workspace = true } 8 | rwasm = { workspace = true } 9 | 10 | [build-dependencies] 11 | fluentbase-build = { workspace = true } 12 | fluentbase-sdk = { workspace = true } 13 | rwasm = { workspace = true } 14 | 15 | [features] 16 | default = ["std"] 17 | std = ["fluentbase-sdk/std", "rwasm/std"] 18 | -------------------------------------------------------------------------------- /examples/rwasm/README.md: -------------------------------------------------------------------------------- 1 | # RWASM 2 | 3 | A compiler contract that transforms WebAssembly bytecode into rWASM format inside Fluent Network. 4 | -------------------------------------------------------------------------------- /examples/rwasm/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | fluentbase_build::build_default_example_contract(); 3 | } 4 | -------------------------------------------------------------------------------- /examples/rwasm/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(target_arch = "wasm32"))] 2 | pub const WASM_BYTECODE: &[u8] = fluentbase_sdk::include_this_wasm!(); 3 | -------------------------------------------------------------------------------- /examples/rwasm/src/main.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(target_arch = "wasm32", no_std, no_main)] 2 | extern crate fluentbase_sdk; 3 | 4 | use fluentbase_sdk::{alloc_slice, create_import_linker, entrypoint, SharedAPI}; 5 | use rwasm::legacy::rwasm::{BinaryFormat, BinaryFormatWriter, RwasmModule}; 6 | 7 | pub fn main_entry(mut sdk: impl SharedAPI) { 8 | let wasm_binary = sdk.input(); 9 | let import_linker = create_import_linker(); 10 | let rwasm_module = 11 | RwasmModule::compile(wasm_binary.as_ref(), Some(import_linker)).expect("failed to compile"); 12 | let encoded_length = rwasm_module.encoded_length(); 13 | let rwasm_bytecode = alloc_slice(encoded_length); 14 | let mut binary_format_writer = BinaryFormatWriter::new(rwasm_bytecode); 15 | let n_bytes = rwasm_module 16 | .write_binary(&mut binary_format_writer) 17 | .expect("failed to encode rWASM"); 18 | assert_eq!(n_bytes, encoded_length, "encoded bytes mismatch"); 19 | sdk.write(rwasm_bytecode); 20 | } 21 | 22 | entrypoint!(main_entry); 23 | -------------------------------------------------------------------------------- /examples/secp256k1/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "fluentbase-examples-secp256k1" 4 | version = "0.1.0" 5 | 6 | [dependencies] 7 | fluentbase-sdk = { workspace = true } 8 | libsecp256k1 = { version = "0.7.1", default-features = false, features = [ 9 | "static-context", 10 | "hmac", 11 | ] } 12 | #secp256k1 = { version = "0.30.0", default-features = false, features = ["recovery", "alloc"] } 13 | secp256k1-sys = { version = "0.10.1", default-features = false, features = [ 14 | "alloc", 15 | "recovery", 16 | ] } 17 | 18 | [dev-dependencies] 19 | tiny-keccak = { workspace = true } 20 | fluentbase-sdk-testing = { workspace = true } 21 | hex = "0.4.3" 22 | hex-literal = "1.0.0" 23 | 24 | [build-dependencies] 25 | fluentbase-build = { workspace = true } 26 | fluentbase-sdk = { workspace = true } 27 | 28 | [features] 29 | default = ["std"] 30 | std = ["fluentbase-sdk/std"] 31 | -------------------------------------------------------------------------------- /examples/secp256k1/README.md: -------------------------------------------------------------------------------- 1 | # Keccak 2 | 3 | A WebAssembly-compatible smart contract that computes the Keccak-256 hash of input data using the Fluentbase SDK. 4 | -------------------------------------------------------------------------------- /examples/secp256k1/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | fluentbase_build::build_default_example_contract(); 3 | } 4 | -------------------------------------------------------------------------------- /examples/secp256k1/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(target_arch = "wasm32"))] 2 | pub const WASM_BYTECODE: &[u8] = fluentbase_sdk::include_this_wasm!(); 3 | -------------------------------------------------------------------------------- /examples/simple-storage/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fluentbase-examples-simple-storage" 3 | version = "0.1.0" 4 | authors.workspace = true 5 | repository.workspace = true 6 | edition.workspace = true 7 | readme.workspace = true 8 | license.workspace = true 9 | keywords.workspace = true 10 | categories.workspace = true 11 | 12 | [dependencies] 13 | fluentbase-sdk = { workspace = true } 14 | hex-literal = { version = "0.4.1", default-features = false } 15 | 16 | [dev-dependencies] 17 | fluentbase-sdk-testing = { workspace = true } 18 | 19 | [build-dependencies] 20 | fluentbase-build = { workspace = true } 21 | fluentbase-sdk = { workspace = true } 22 | 23 | [features] 24 | default = ["std"] 25 | std = ["fluentbase-sdk/std"] 26 | -------------------------------------------------------------------------------- /examples/simple-storage/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | fluentbase_build::build_default_example_contract(); 3 | } 4 | -------------------------------------------------------------------------------- /examples/simple-storage/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(target_arch = "wasm32"))] 2 | pub const WASM_BYTECODE: &[u8] = fluentbase_sdk::include_this_wasm!(); 3 | -------------------------------------------------------------------------------- /examples/simple-storage/src/main.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(target_arch = "wasm32", no_std, no_main)] 2 | use fluentbase_sdk::{derive::solidity_storage, entrypoint, Address, SharedAPI, U256}; 3 | 4 | solidity_storage! { 5 | mapping(Address => U256) Values; 6 | } 7 | 8 | pub fn deploy(mut sdk: impl SharedAPI) { 9 | sdk.write_storage(U256::from(1), U256::from(2)); 10 | } 11 | 12 | pub fn main_entry(sdk: impl SharedAPI) { 13 | let value = sdk.storage(&U256::from(1)); 14 | assert_eq!(value.data, U256::from(2)); 15 | } 16 | 17 | entrypoint!(main_entry, deploy); 18 | 19 | #[cfg(test)] 20 | mod tests { 21 | use super::*; 22 | use fluentbase_sdk_testing::HostTestingContext; 23 | 24 | #[test] 25 | fn test_simple_storage_set_and_get() { 26 | let sdk = HostTestingContext::default(); 27 | deploy(sdk.clone()); 28 | main_entry(sdk.clone()); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /examples/storage/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fluentbase-examples-storage" 3 | version = "0.1.0" 4 | authors.workspace = true 5 | repository.workspace = true 6 | edition.workspace = true 7 | readme.workspace = true 8 | license.workspace = true 9 | keywords.workspace = true 10 | categories.workspace = true 11 | 12 | [dependencies] 13 | fluentbase-sdk = { workspace = true } 14 | 15 | [dev-dependencies] 16 | serial_test = "3.0.0" 17 | fluentbase-sdk-testing = { workspace = true } 18 | 19 | [build-dependencies] 20 | fluentbase-build = { workspace = true } 21 | fluentbase-sdk = { workspace = true } 22 | 23 | [features] 24 | default = ["std"] 25 | std = ["fluentbase-sdk/std"] 26 | -------------------------------------------------------------------------------- /examples/storage/README.md: -------------------------------------------------------------------------------- 1 | # Storage 2 | 3 | An example of the `solidity_storage!` macro usage. For real world example, you can check the [ERC-20](../erc20) example. 4 | -------------------------------------------------------------------------------- /examples/storage/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | fluentbase_build::build_default_example_contract(); 3 | } 4 | -------------------------------------------------------------------------------- /examples/storage/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(target_arch = "wasm32"))] 2 | pub const WASM_BYTECODE: &[u8] = fluentbase_sdk::include_this_wasm!(); 3 | -------------------------------------------------------------------------------- /examples/tiny-keccak/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fluentbase-examples-tiny-keccak" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | fluentbase-sdk = { workspace = true } 8 | tiny-keccak = { workspace = true } 9 | 10 | [dev-dependencies] 11 | fluentbase-sdk-testing = { workspace = true } 12 | 13 | [build-dependencies] 14 | fluentbase-build = { workspace = true } 15 | fluentbase-sdk = { workspace = true } 16 | tiny-keccak = { workspace = true } 17 | 18 | [features] 19 | default = ["std"] 20 | std = ["fluentbase-sdk/std"] 21 | -------------------------------------------------------------------------------- /examples/tiny-keccak/README.md: -------------------------------------------------------------------------------- 1 | # Tiny Keccak 2 | 3 | > WARN: Don't use `tiny-keccak` as keccak256 function, because Fluent provides an optimized version in the SDK 4 | 5 | An example of running custom hashing function like Keccak256 -------------------------------------------------------------------------------- /examples/tiny-keccak/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | fluentbase_build::build_default_example_contract(); 3 | } 4 | -------------------------------------------------------------------------------- /examples/tiny-keccak/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(not(target_arch = "wasm32"))] 2 | pub const WASM_BYTECODE: &[u8] = fluentbase_sdk::include_this_wasm!(); 3 | -------------------------------------------------------------------------------- /examples/tiny-keccak/src/main.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(target_arch = "wasm32", no_std, no_main)] 2 | extern crate fluentbase_sdk; 3 | 4 | use fluentbase_sdk::{alloc_slice, entrypoint, SharedAPI}; 5 | use tiny_keccak::{Hasher, Keccak}; 6 | 7 | pub fn main_entry(mut sdk: impl SharedAPI) { 8 | // get the size of the input and allocate memory for input 9 | let input_size = sdk.input_size(); 10 | let input = alloc_slice(input_size as usize); 11 | // copy input to the allocated memory 12 | sdk.read(input, 0); 13 | // calculate keccak256 hash 14 | let mut keccak256 = Keccak::v256(); 15 | let mut output = [0u8; 32]; 16 | keccak256.update(input); 17 | keccak256.finalize(&mut output); 18 | // write both hashes to output (multiple writes do append) 19 | sdk.write(&output); 20 | } 21 | 22 | entrypoint!(main_entry); 23 | 24 | #[cfg(test)] 25 | mod tests { 26 | use super::*; 27 | use fluentbase_sdk::hex; 28 | use fluentbase_sdk_testing::HostTestingContext; 29 | 30 | #[test] 31 | fn test_contract_works() { 32 | let sdk = HostTestingContext::default().with_input("Hello, World"); 33 | main_entry(sdk.clone()); 34 | let output = sdk.take_output(); 35 | assert_eq!( 36 | &output[0..32], 37 | hex!("a04a451028d0f9284ce82243755e245238ab1e4ecf7b9dd8bf4734d9ecfd0529") 38 | ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /rust-toolchain: -------------------------------------------------------------------------------- 1 | nightly-2025-01-27 --------------------------------------------------------------------------------