An Ethereum SDK for MoonBit. In a browser it wraps the
EIP-1193 provider that extensions
such as MetaMask inject as globalThis.ethereum; anywhere else it speaks
JSON-RPC over HTTP to a node. Either way the surface is the same typed, async
MoonBit functions.
documentation: a cookbook whose every recipe carries a demo you can drive against your own wallet, and a reference for what is wrapped — anything unwrapped is still reachable through
Provider::request.
moon add poteto0/endorThen import the packages you need in your moon.pkg:
import {
"poteto0/endor/provider", // @provider — Provider, typed RPC, errors
"poteto0/endor/provider/browser", // @browser — the injected wallet
"poteto0/endor/ffi/js", // @js — spawn (bridge async to the JS event loop)
}
A browser wallet is needed to sign; it is not needed to read. Point the SDK
at a node URL and the same typed helpers work with no extension installed —
and on any backend, not only js:
import {
"poteto0/endor/provider", // @provider — Provider, typed RPC, errors
"poteto0/endor/provider/http", // @http — HttpProvider, HttpTransport
"poteto0/endor/provider/http/endpoint", // @endpoint — a node at a URL
}
async fn read_chain_over_http(
url : String,
) -> @endor.ChainId raise @provider.ProviderError {
@provider.chain_id(@endpoint.at(url))
}
There is no FFI under this. @endpoint.at uses moonbitlang/async's HTTP
client, which is fetch on js and sockets with TLS on native and wasm,
so the call above compiles and runs in a browser, in a CLI and on a server. A
hosted provider that wants a key takes headers~:
async fn read_chain_from_a_paid_node(
url : String,
key : String,
) -> @endor.ChainId raise @provider.ProviderError {
@provider.chain_id(@endpoint.at(url, headers={ "Authorization": "Bearer \{key}" }))
}
HttpProvider is a Provider like any other, so everything above it — the
typed reads, Contract::call, the ABI layer — is unchanged. What HTTP cannot
serve, it says so about: every wallet_* method and eth_requestAccounts
raise UnsupportedMethod, since there is nothing behind a URL to prompt the
user. HttpTransport stays a trait for a caller whose HTTP is its own —
retries, a connection pool, a proxy — and for wasm-gc, the one backend
@endpoint cannot reach.
Read without a wallet is
the whole recipe: headers, errors, and what an endpoint refuses.
The domain types are re-exported from the root package, so
"poteto0/endor" gives you @endor.Address, @endor.ChainId, and friends when
you need to spell a type out.
endor-cli is a separate module and a separate install — a binary rather than a
dependency, so nothing it needs ends up in your module's resolution:
moon install poteto0/endor-cli/endor-cliIt generates MoonBit contract presets from JSON ABI documents
(endor-cli init, then endor-cli abi). Point it at a compiler artifact —
solc --combined-json abi,bin, a Foundry or Hardhat one — and the preset gets a
deploy too, with the creation code embedded. Experimental, and not
required to use the SDK — cmd/README.md has the details.
