EIPs
EIP-1193 — Ethereum Provider JavaScript API
The Provider envelope every wallet implements. A Provider is a four-field object:
import type {
EventMap,
EventName,
Provider,
RequestArguments,
} from "@ethernauta/eip/1193";
// `Provider` is structurally:
// request: (args: RequestArguments) => Promise<unknown>
// on: <E>(event: E, listener: (payload: EventMap[E]) => void) => void
// removeListener: <E>(event: E, listener: (payload: EventMap[E]) => void) => void
// emit: <E>(event: E, payload: EventMap[E]) => void
declare const example: Provider;
const args: RequestArguments = { method: "eth_chainId" };
const events: EventName = "accountsChanged";
const payload: EventMap["accountsChanged"] = [];
void example;
void args;
void events;
void payload; That’s all. Method routing, allowlists, caching, confirmation policy — none of that is part of 1193. See Concepts → 1193 is a transport.
import { create_provider } from "@ethernauta/eip/1193";
declare function dispatch(method: string, params: readonly unknown[] | object | undefined): Promise<unknown>;
const provider = create_provider({
request: async ({ method, params }) => dispatch(method, params),
}); Surface
Provider
| Export | Type | Purpose |
|---|---|---|
create_provider | (options) => Provider | Build a 1193 provider with the four-field shape. |
Provider, RequestArguments, CreateProviderOptions | types | Inferred shapes. |
RequestArgumentsSchema | Valibot schema | Validate incoming request calls. |
Errors
EIP-1193 defines a standard error space (4001 user rejected, 4100 unauthorized, 4200 unsupported method, 4900/4901 disconnected, …):
| Export | Code | Purpose |
|---|---|---|
ERROR_CODE | enum-like | All standard codes by name. |
invalid_params | -32602 | Bad params. |
unauthorized | 4100 | Not authorized by user. |
user_rejected | 4001 | User clicked “reject.” |
unsupported_method | 4200 | Method not implemented. |
unrecognized_chain | 4902 | Chain not added to wallet. |
chain_disconnected | 4901 | Disconnected from chain. |
provider_error | -32603 | Internal provider error. |
disconnected | 4900 | No connection. |
ErrorCode | type | Discriminated union of the above. |
Events
import { create_emitter } from "@ethernauta/eip/1193";
const emitter = create_emitter();
emitter.on("accountsChanged", (accounts) => {
console.log(accounts);
});
emitter.on("chainChanged", (chain_id) => {
console.log(chain_id);
});
const new_accounts: string[] = [];
emitter.emit("accountsChanged", new_accounts); | Event | Payload |
|---|---|
connect | { chain_id } |
disconnect | ProviderRpcError |
accountsChanged | Address[] |
chainChanged | Uint (decimal chain ID as bigint) |
message | EthSubscription \| ... |
| Export | Purpose |
|---|---|
create_emitter | Build an event emitter conforming to 1193 semantics. |
Emitter, EventMap, EventName, EthSubscription, ProviderMessage, ProviderConnectInfo | types |
Convenience watchers
import { watch_accounts, watch_chain } from "@ethernauta/eip/1193";
import type { Provider } from "@ethernauta/eip/1193";
declare const provider: Provider;
const unsubscribe_accounts = watch_accounts(provider, (accounts) => {
console.log("now exposed:", accounts);
});
const unsubscribe_chain = watch_chain(provider, (chain_id) => {
console.log("active chain:", chain_id);
});
void unsubscribe_accounts;
void unsubscribe_chain; Return unsubscribe functions; cleanly handle accountsChanged / chainChanged together with initial-state fetching.
Consumer side — turning a 1193 provider into resolvers
The library’s typical dapp pattern doesn’t request directly; it adapts the provider into resolver shapes:
import { create_provider } from "@ethernauta/transport";
import { eth_blockNumber, eth_sendTransaction } from "@ethernauta/eth";
import type { Provider } from "@ethernauta/eip/1193";
import { AddressSchema, BytesSchema, UintSchema } from "@ethernauta/core";
import { parse } from "valibot";
declare const injected: Provider;
const provider = create_provider(injected);
const to = parse(AddressSchema, "0x70997970C51812dc3A010C7d01b50e0d17dc79C8");
const value = parse(UintSchema, "0x0");
const input = parse(BytesSchema, "0x");
const block = await eth_blockNumber()(provider.reader({ chain_id: "eip155:1" }));
const hash = await eth_sendTransaction([{ to, value, input }])(
provider.signer({ chain_id: "eip155:1" }),
); create_provider in @ethernauta/eip/1193 builds a provider (the wallet side, producing the four-field envelope). create_provider in @ethernauta/transport consumes a provider (the dapp side, adapting it into resolver shapes). Same name, opposite sides of the same envelope — pick the import by what your code is doing.
See also
- EIP-6963 — discover providers when there may be more than one.
- Concepts → 1193 is a transport — why the envelope is intentionally four fields.
- Concepts → the wallet contract — what the Ethernauta wallet routes where.