Current section
Files
Jump to
Current section
Files
src/solc.gleam
// Gleam Solidity Compiler Bindings
//
// This module provides a high-level API for compiling Solidity contracts
// with support for multiple inheritance, error handling, and modern Solidity versions.
import gleam/dict
import gleam/javascript/promise.{type Promise}
import gleam/json
import gleam/list
import gleam/option.{type Option, None, Some}
import solc/download
import solc/types.{
type CompilationInput, type CompilationOutput, type SolcError,
type SolcWrapper,
}
import solc/wrapper
// Download and load a Solidity compiler
pub fn load_solc(
path: String,
version: Option(String),
) -> Promise(Result(SolcWrapper, SolcError)) {
case download.solc_exists(path) {
True -> {
// File exists, try to load it
promise.resolve(wrapper.load_wrapper(path))
}
False -> {
// Download first, then load
use download_result <- promise.map(download.download(path, version))
case download_result {
Ok(_filename) -> wrapper.load_wrapper(path)
Error(err) -> Error(err)
}
}
}
}
// Compile Solidity source code with simple interface
pub fn compile_simple(
solc: SolcWrapper,
contract_name: String,
source_code: String,
) -> Result(CompilationOutput, SolcError) {
let input = create_simple_input(contract_name, source_code)
let input_json = encode_input(input)
case input_json {
Ok(json_string) -> solc.compile(json_string)
Error(msg) -> Error(types.InvalidInput("Failed to encode input: " <> msg))
}
}
// Compile multiple Solidity files
pub fn compile_multiple(
solc: SolcWrapper,
sources: dict.Dict(String, String),
) -> Result(CompilationOutput, SolcError) {
let input = create_multiple_input(sources)
let input_json = encode_input(input)
case input_json {
Ok(json_string) -> solc.compile(json_string)
Error(msg) -> Error(types.InvalidInput("Failed to encode input: " <> msg))
}
}
// Create a simple compilation input for a single contract
fn create_simple_input(
contract_name: String,
source_code: String,
) -> CompilationInput {
let source = types.Source(content: source_code)
let sources = dict.from_list([#(contract_name, source)])
let output_selection =
types.OutputSelection(
selections: dict.from_list([
#(
"*",
dict.from_list([
#("*", ["abi", "evm.bytecode", "evm.deployedBytecode", "metadata"]),
]),
),
]),
)
let settings =
types.CompilationSettings(
output_selection: output_selection,
optimizer: Some(types.OptimizerSettings(enabled: True, runs: 200)),
evm_version: None,
libraries: None,
remappings: None,
)
types.CompilationInput(
language: "Solidity",
sources: sources,
settings: settings,
)
}
// Create compilation input for multiple files
fn create_multiple_input(sources: dict.Dict(String, String)) -> CompilationInput {
let gleam_sources =
dict.map_values(sources, fn(_, content) { types.Source(content: content) })
let output_selection =
types.OutputSelection(
selections: dict.from_list([
#(
"*",
dict.from_list([
#("*", ["abi", "evm.bytecode", "evm.deployedBytecode", "metadata"]),
]),
),
]),
)
let settings =
types.CompilationSettings(
output_selection: output_selection,
optimizer: Some(types.OptimizerSettings(enabled: True, runs: 200)),
evm_version: None,
libraries: None,
remappings: None,
)
types.CompilationInput(
language: "Solidity",
sources: gleam_sources,
settings: settings,
)
}
// Encode compilation input to JSON string
fn encode_input(input: CompilationInput) -> Result(String, String) {
// TODO: Implement proper JSON encoding
// For now, return a basic structure
let json_obj =
json.object([
#("language", json.string(input.language)),
#("sources", encode_sources(input.sources)),
#("settings", encode_settings(input.settings)),
])
Ok(json.to_string(json_obj))
}
// Encode sources to JSON
fn encode_sources(sources: dict.Dict(String, types.Source)) -> json.Json {
let source_pairs = dict.to_list(sources)
let json_pairs =
list.map(source_pairs, fn(pair) {
let #(name, source) = pair
#(name, json.object([#("content", json.string(source.content))]))
})
json.object(json_pairs)
}
// Encode settings to JSON
fn encode_settings(settings: types.CompilationSettings) -> json.Json {
json.object([
#("outputSelection", encode_output_selection(settings.output_selection)),
])
}
// Encode output selection to JSON
fn encode_output_selection(selection: types.OutputSelection) -> json.Json {
let selection_pairs = dict.to_list(selection.selections)
let json_pairs =
list.map(selection_pairs, fn(pair) {
let #(file, contracts) = pair
let contract_pairs = dict.to_list(contracts)
let contract_json_pairs =
list.map(contract_pairs, fn(contract_pair) {
let #(contract, outputs) = contract_pair
#(contract, json.array(from: outputs, of: json.string))
})
#(file, json.object(contract_json_pairs))
})
json.object(json_pairs)
}