EIPs

EIP-1193 — Ethereum Provider JavaScript API

eips.ethereum.org/EIPS/eip-1193

The Provider envelope every wallet implements. A Provider is a four-field object:

type Provider = {
  request(args: RequestArguments): Promise<unknown>;
  on(event: EventName, listener): void;
  removeListener(event: EventName, listener): void;
  emit(event: EventName, payload): void;
};

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";

const provider = create_provider({
  request: async ({ method, params }) => dispatch(method, params),
});

Surface

Provider

ExportTypePurpose
create_provider(options) => ProviderBuild a 1193 provider with the four-field shape.
Provider, RequestArguments, CreateProviderOptionstypesInferred shapes.
requestArgumentsSchemaValibot schemaValidate incoming request calls.

Errors

EIP-1193 defines a standard error space (4001 user rejected, 4100 unauthorized, 4200 unsupported method, 4900/4901 disconnected, …):

ExportCodePurpose
ERROR_CODEenum-likeAll standard codes by name.
invalid_params-32602Bad params.
unauthorized4100Not authorized by user.
user_rejected4001User clicked “reject.”
unsupported_method4200Method not implemented.
unrecognized_chain4902Chain not added to wallet.
chain_disconnected4901Disconnected from chain.
provider_error-32603Internal provider error.
disconnected4900No connection.
ErrorCodetypeDiscriminated union of the above.

Events

import { create_emitter } from "@ethernauta/eip/1193";

const emitter = create_emitter();

emitter.on("accountsChanged", (accounts) => { ... });
emitter.on("chainChanged", (chain_id) => { ... });

emitter.emit("accountsChanged", new_accounts);
EventPayload
connect{ chain_id }
disconnectProviderRpcError
accountsChangedAddress[]
chainChangedUint (decimal chain ID as bigint)
messageEthSubscription \| ...
ExportPurpose
create_emitterBuild an event emitter conforming to 1193 semantics.
Emitter, EventMap, EventName, EthSubscription, ProviderMessage, ProviderConnectInfotypes

Convenience watchers

import { watch_accounts, watch_chain } from "@ethernauta/eip/1193";

const unsubscribe = watch_accounts(provider, (accounts) => {
  console.log("now exposed:", accounts);
});

watch_chain(provider, (chain_id) => {
  console.log("active chain:", chain_id);
});

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";

const provider = create_provider(window.ethereum);

const block = await eth_block_number()(provider.reader({ chain_id: 1 }));
const hash = await eth_send_transaction({ to, value })(
  provider.signer({ chain_id: 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