Add Support for Compiling and Deploying First Class Functions
- Dominant language
- C++
- Stars
- 25.7k
- Forks
- 6.2k
- Avg merge
- 2d 19h
- Merged PRs (30d)
- 29
Description
## Abstract
Solidity currently doesn’t support deploying standalone functions as contracts. While Solidity is object-oriented by design, there are valid use cases for pure, stateless functions that could be deployed directly without the overhead of a full contract or library structure. Examples include cryptographic hash computations, verifier functions, or any single-purpose computational logic.
## Motivation
The ability to deploy standalone functions would provide several benefits:
- Cheaper deployment for single-purpose computational logic
- Reduced gas costs by eliminating overhead such as function dispatcher and smaller calldata
- Cleaner abstraction for purely functional operations
This would be particularly useful for:
- ZK proof verifiers
- Cryptographic operations
- Pure computational functions
- Stateless verification logic
## Specification
Standalone functions would have the following characteristics:
- Cannot have state variables
- Cannot receive ETH
- Cannot be destroyed
- Must be `pure` or `view`
- Can only have one function per deployment
- Must be `external`
Compilation would generate bytecode that:
- Skips function selector matching
- Directly executes the function logic
- Validate input parameters
- Returns output
### Additional Considerations
While this is currently semi-possible, using a contract that only includes a `fallback` function, i.e, skipping the function dispatcher, `fallback` functions are limited in how they can be declared: `fallback () external [payable]` or `fallback (bytes calldata input) external [payable] returns (bytes memory output)`. The latter declaration allows us even to add custom input and return custom output, however:
- This adds overhead for developers, who will have to manually encode the input, which is also an error-prone process
- The return bytes will have to be manually decoded, too, as well as automatically copied into memory, which could add extra costs.
The proposed solution will allow optionally custom input and output parameters and types.
## Example
```
sample-project
├── verifyProof.sol
└── Verifier.sol
```
`verifyProof.sol`
```solidity
function verifyProof(bytes calldata proof) external pure returns (bool) {
// verification logic
return true;
}
```
`Verifier.sol`
```solidity
// import the function from a file
import { verifyProof } from "./verifyProof.sol";
contract Verifier {
// @param verifyProof the address of the deployed standalone function
function isValidProof(verifyProof _verifyProof, bytes memory proof) external view returns(bool) {
return _verifyProof(proof);
}
}
```
This [gist](https://gist.github.com/cre-mer/b6cdd9174dcb0d6f3d4ac0f22911090b) has an extended example, including a compiled `verifyProof.yul` file, showing how the function object could look like.
## Backwards Compatibility
This feature would be semi-backward compatible. Calling a standalone function, as shown in the example, would not be possible in Solidity. However, this is feasible using low-level calls.
Contributor guide
Research direction
Start by reviewing the standalone-function specification and the examples in verifyProof.sol and Verifier.sol, then study the extended gist and its compiled verifyProof.yul output. Done would mean agreeing on and implementing the language, deployment, calling, and bytecode behavior described here, with repository tests covering the specified constraints and outputs.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp, solidity
- Domain
- blockchain, compilers
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100