eip-1193
Version:
Types for EIP-1193 ethereum provider
541 lines (457 loc) • 17.8 kB
TypeScript
// ------------------------------------------------------------------------------------------------
// TYPES
// ------------------------------------------------------------------------------------------------
export type EIP1193DATA = `0x${string}`;
export type EIP1193BlockTag = EIP1193QUANTITY | 'latest' | 'earliest' | 'pending' | 'safe' | 'finalized';
export type EIP1193INTEGER = EIP1193DATA | number;
export type EIP1898BlockTag =
| EIP1193QUANTITY
| 'latest'
| 'earliest'
| 'pending'
| 'safe'
| 'finalized'
| {blockHash: EIP1193QUANTITY; requireCanonical?: boolean} // EIP-1898
| {blockNumber: EIP1193QUANTITY}; // EIP-1898
export type EIP1193QUANTITY = `0x${string}`;
export type EIP1193ChainId = `0x${string}`;
export type EIP1193Account = `0x${string}`;
export type EIP1193Accounts = EIP1193Account[];
export type EIP1193FeeHistory = {
oldestBlock: string;
reward: EIP1193QUANTITY[][];
baseFeePerGas: string[];
gasUsedRatio: string[];
};
type BaseEIP1193Transaction = {
blockHash: EIP1193DATA;
blockNumber: EIP1193QUANTITY | null;
from: EIP1193Account;
gas: EIP1193QUANTITY;
hash: EIP1193DATA;
input: EIP1193DATA;
nonce: EIP1193QUANTITY;
to: EIP1193Account | null;
transactionIndex: EIP1193QUANTITY | null;
value: EIP1193QUANTITY;
v: EIP1193QUANTITY;
r: EIP1193QUANTITY;
s: EIP1193QUANTITY;
};
export type EIP1193TransactionType0 = BaseEIP1193Transaction & {
type?: '0x0';
gasPrice: EIP1193QUANTITY;
};
export type EIP1193TransactionType1 = BaseEIP1193Transaction & {
type: '0x1';
gasPrice: EIP1193QUANTITY;
chainId: EIP1193ChainId;
accessList?: EIP1193AccessList;
};
export type EIP1193TransactionType2 = BaseEIP1193Transaction & {
type: '0x2';
chainId: EIP1193ChainId;
accessList?: EIP1193AccessList;
maxFeePerGas: EIP1193QUANTITY;
maxPriorityFeePerGas: EIP1193QUANTITY;
};
export type EIP1193Transaction = EIP1193TransactionType0 | EIP1193TransactionType1 | EIP1193TransactionType2;
type BaseEIP1193TransactionData = {
from: EIP1193Account;
to?: EIP1193Account;
gas?: EIP1193QUANTITY;
value?: EIP1193QUANTITY;
data?: EIP1193DATA;
nonce?: EIP1193QUANTITY;
};
export type EIP1193LegacyTransactionData = BaseEIP1193TransactionData & {
type?: '0x0';
gasPrice?: EIP1193QUANTITY;
};
export type EIP1193TransactionDataOfType1 = BaseEIP1193TransactionData & {
type: '0x1';
chainId?: EIP1193ChainId;
accessList?: EIP1193AccessList;
gasPrice?: EIP1193QUANTITY;
};
export type EIP1193AccessListEntry = {address: EIP1193Account; storageKeys: EIP1193DATA[]};
export type EIP1193AccessList = EIP1193AccessListEntry[];
export type EIP1193TransactionDataOfType2 = BaseEIP1193TransactionData & {
type: '0x2';
chainId?: EIP1193ChainId;
accessList?: EIP1193AccessList;
maxFeePerGas?: EIP1193QUANTITY;
maxPriorityFeePerGas?: EIP1193QUANTITY;
};
export type EIP1193TransactionData =
| EIP1193LegacyTransactionData
| EIP1193TransactionDataOfType1
| EIP1193TransactionDataOfType2;
export type EIP1193SyncingStatus = {
startingBlock: EIP1193QUANTITY;
currentBlock: EIP1193QUANTITY;
highestBlock: EIP1193QUANTITY;
};
export type EIP1193Block = {
number: EIP1193QUANTITY;
hash: EIP1193DATA;
parentHash: EIP1193DATA;
nonce: EIP1193DATA;
sha3Uncles: EIP1193DATA;
logsBloom: EIP1193DATA;
transactionsRoot: EIP1193DATA;
stateRoot: EIP1193DATA;
receiptsRoot: EIP1193DATA;
miner: EIP1193Account;
difficulty: EIP1193QUANTITY;
totalDifficulty: EIP1193QUANTITY;
extraData: EIP1193DATA;
size: EIP1193QUANTITY;
gasLimit: EIP1193QUANTITY;
gasUsed: EIP1193QUANTITY;
timestamp: EIP1193QUANTITY;
uncles: EIP1193DATA[];
};
export type EIP1193Log = {
removed: boolean;
logIndex: EIP1193QUANTITY | null;
transactionIndex: EIP1193QUANTITY | null;
transactionHash: EIP1193DATA | null;
blockHash: EIP1193DATA | null;
blockNumber: EIP1193QUANTITY | null;
address: EIP1193Account;
data: EIP1193DATA;
topics: EIP1193DATA[];
};
export type EIP1193TransactionReceipt = {
transactionHash: EIP1193DATA;
transactionIndex: EIP1193QUANTITY;
blockHash: EIP1193DATA;
blockNumber: EIP1193QUANTITY;
from: EIP1193Account;
to: EIP1193Account;
cumulativeGasUsed: EIP1193QUANTITY;
effectiveGasPrice: EIP1193QUANTITY;
gasUsed: EIP1193QUANTITY;
contractAddress: EIP1193Account;
logs: EIP1193Log[];
logsBloom: EIP1193DATA;
type: EIP1193DATA;
root: EIP1193DATA;
status: EIP1193QUANTITY;
};
export type EIP1193PendingBlock = Omit<EIP1193Block, 'number' | 'hash' | 'nonce' | 'logsBloom'> & {
number: null;
hash: null;
nonce: null;
logsBloom: null;
};
export type EIP1193BlockWithTransactions = EIP1193Block & {
transactions: EIP1193Transaction[];
};
export type EIP1193PendingBlockWithTransactions = EIP1193PendingBlock & {
transactions: EIP1193Transaction[];
};
type EIP1193BaseTransactionEIP1193DATA = {
gas?: EIP1193QUANTITY;
gasPrice?: EIP1193QUANTITY;
value?: EIP1193QUANTITY;
data?: EIP1193DATA;
nonce?: EIP1193QUANTITY;
};
export type EIP1193NormalTransactionEIP1193DATA = EIP1193BaseTransactionEIP1193DATA & {
from: EIP1193Account;
to: EIP1193Account;
};
export type EIP1193TransactionContractCreationEIP1193DATA = EIP1193BaseTransactionEIP1193DATA & {
from: EIP1193Account;
data: EIP1193DATA;
};
export type EIP1193TransactionEIP1193DATA =
| EIP1193NormalTransactionEIP1193DATA
| EIP1193TransactionContractCreationEIP1193DATA;
export type EIP1193CallParam = {
from?: EIP1193Account;
to: EIP1193Account;
gas?: EIP1193QUANTITY;
gasPrice?: EIP1193QUANTITY;
value?: EIP1193QUANTITY;
data?: EIP1193DATA;
};
export type EIP1193AddChainParam = {
chainId: EIP1193ChainId;
rpcUrls?: string[];
blockExplorerUrls?: string[];
chainName?: string;
iconUrls?: string[];
nativeCurrency?: {
name: string;
symbol: string;
decimals: number;
};
};
export type EIP1193LogsParam = {
fromBlock?: EIP1193BlockTag;
toBlock?: EIP1193BlockTag;
address?: EIP1193Account | EIP1193Accounts;
topics?: (EIP1193DATA | EIP1193DATA[])[];
blockhash?: EIP1193DATA;
};
export type EIP1193TracedTransaction = {
failed: boolean;
gas: EIP1193QUANTITY;
returnValue: EIP1193DATA;
structLogs: any[]; // TODO
// TODO more
};
export type EIP1193SubscriptionMessage = EIP1193KnownSubscriptionMessage | EIP1193UnknownSubscriptionMessage;
export type EIP1193Message = EIP1193SubscriptionMessage | EIP1193UnknownMessage;
export type EIP1193AddChainError = {
// TODO
};
export type EIP1193SwitchChainError = {
// TODO
};
/*
// TODO
4001 User Rejected Request The user rejected the request.
4100 Unauthorized The requested method and/or account has not been authorized by the user.
4200 Unsupported Method The Provider does not support the requested method.
4900 Disconnected The Provider is disconnected from all chains.
4901 Chain Disconnected The Provider is not connected to the requested chain.
*/
type Listener<Message> = (message: Message) => unknown | Promise<unknown>;
// ------------------------------------------------------------------------------------------------
// REQUEST TYPES
// ------------------------------------------------------------------------------------------------
export type Methods = ReadMethods &
NodeOnlyReadMethods &
WriteMethods &
SignerMethods &
ConnectedAccountMethods &
WalletOnlyMethods;
export type NodeOnlyReadMethods = {
web3_clientVersion: {result: string};
web3_sha: {params: [EIP1193DATA]; result: EIP1193DATA};
net_version: {result: EIP1193ChainId};
net_listening: {result: boolean};
net_peerCount: {result: EIP1193QUANTITY};
eth_protocolVersion: {result: string};
eth_syncing: {result: EIP1193SyncingStatus | false};
eth_coinbase: {result: EIP1193Account};
eth_mining: {result: boolean}; // TODO check
eth_hashrate: {result: unknown}; // TODO
};
export type ReadMethods = {
eth_gasPrice: {result: EIP1193QUANTITY};
eth_blockNumber: {result: EIP1193QUANTITY};
eth_getBalance: {params: [EIP1193Account] | [EIP1193Account, EIP1898BlockTag]; result: EIP1193QUANTITY};
eth_getStorageAt: {
params: [EIP1193Account, EIP1193QUANTITY] | [EIP1193Account, EIP1193QUANTITY, EIP1898BlockTag];
result: EIP1193DATA;
};
eth_getTransactionCount: {params: [EIP1193Account] | [EIP1193Account, EIP1898BlockTag]; result: EIP1193QUANTITY};
eth_getBlockTransactionCountByHash: {params: [EIP1193DATA]; result: EIP1193QUANTITY};
eth_getBlockTransactionCountByNumber: {params: [EIP1193BlockTag]; result: EIP1193QUANTITY};
eth_getUncleCountByBlockHash: {params: [EIP1193DATA]; result: EIP1193QUANTITY};
eth_getUncleCountByBlockNumber: {params: [EIP1193BlockTag]; result: EIP1193QUANTITY};
eth_getCode: {params: [EIP1193Account] | [EIP1193Account, EIP1898BlockTag]; result: EIP1193DATA};
eth_call: {params: [EIP1193CallParam] | [EIP1193CallParam, EIP1898BlockTag]; result: EIP1193DATA};
eth_estimateGas: {params: [EIP1193CallParam] | [EIP1193CallParam, EIP1193BlockTag]; result: EIP1193QUANTITY}; // EIP1898BlockTag ?
eth_getBlockByHash:
| {params: [EIP1193DATA, true]; result: EIP1193BlockWithTransactions | null}
| {params: [EIP1193DATA, false]; result: EIP1193Block | null};
eth_getBlockByNumber:
| {params: [EIP1193BlockTag, true]; result: EIP1193BlockWithTransactions | null}
| {params: [EIP1193BlockTag, false]; result: EIP1193Block | null};
eth_getTransactionByHash: {params: [EIP1193DATA]; result: EIP1193Transaction | null};
eth_getTransactionByBlockHashAndIndex: {params: [EIP1193DATA, EIP1193QUANTITY]; result: EIP1193Transaction | null};
eth_getTransactionByBlockNumberAndIndex: {
params: [EIP1193BlockTag, EIP1193QUANTITY];
result: EIP1193Transaction | null;
};
eth_getTransactionReceipt: {params: [EIP1193DATA]; result: EIP1193TransactionReceipt | null};
eth_getUncleByBlockHashAndIndex: {params: [EIP1193DATA, EIP1193QUANTITY]; result: EIP1193Block | null};
eth_getUncleByBlockNumberAndIndex: {params: [EIP1193BlockTag, EIP1193QUANTITY]; result: EIP1193Block | null};
eth_getLogs: {params: [EIP1193LogsParam]; result: EIP1193Log[]};
eth_chainId: {result: EIP1193ChainId};
eth_subscribe:
| {params: ['newHeads' | 'newPendingTransactions' | 'syncing']; result: string}
| {
params: [
'logs',
{
address: EIP1193Account | EIP1193Account[];
topics: (EIP1193DATA[] | EIP1193DATA)[];
}
];
result: string;
};
eth_unsubscribe: {params: [EIP1193DATA]; result: boolean};
eth_getProof: {params: [EIP1193DATA, EIP1193DATA[]] | [EIP1193DATA, EIP1193DATA[], EIP1898BlockTag]; result: unknown}; // TODO
eth_feeHistory: {params: [EIP1193QUANTITY, EIP1193BlockTag, number[]]; result: EIP1193FeeHistory};
};
export type WriteMethods = {
eth_sendRawTransaction: {params: [EIP1193DATA]; result: EIP1193DATA};
};
export type SignerMethods = {
eth_accounts: {result: EIP1193Accounts};
eth_sign: {params: [EIP1193Account, EIP1193DATA]; result: EIP1193DATA};
eth_signTransaction: {params: [EIP1193TransactionData]; result: EIP1193DATA};
personal_sign: {params: [EIP1193DATA, EIP1193Account]; result: EIP1193DATA};
eth_signTypedData_v4: {params: [EIP1193Account, EIP1193TypedSignatureParam]; result: EIP1193DATA};
eth_signTypedData: {params: [EIP1193Account, EIP1193TypedSignatureParam]; result: EIP1193DATA};
};
export type ConnectedAccountMethods = {
eth_sendTransaction: {params: [EIP1193TransactionData]; result: EIP1193DATA};
};
export type WalletOnlyMethods = {
eth_requestAccounts: {result: EIP1193Accounts};
wallet_switchEthereumChain: {
params: [
{
chainId: EIP1193ChainId;
}
];
result: EIP1193SwitchChainError | null;
};
wallet_addEthereumChain: {params: [EIP1193AddChainParam]; result: EIP1193AddChainError | null};
};
export type DebugOnlyMethods = {
debug_traceTransaction: {params: [EIP1193DATA]; result: EIP1193TracedTransaction};
};
export type WalletMethods = ReadMethods & WriteMethods & SignerMethods & ConnectedAccountMethods & WalletOnlyMethods;
export type EIP1193TypedSignatureParam = {[field: string]: any}; // TODO
export type EIP1193GenericRequest = {
method: string;
params?: Readonly<unknown[]>;
};
export interface EIP1193ProviderRpcError extends Error {
message: string;
code: number;
data?: unknown;
}
export interface EIP1193ConnectInfoMessage {
readonly chainId: EIP1193ChainId;
}
export type EIP1193UnknownMessage = {
readonly type: string;
readonly data: unknown;
};
export type EIP1193UnknownSubscriptionMessage = EIP1193UnknownMessage & {
readonly type: 'eth_subscription';
readonly data: {
readonly subscription: EIP1193DATA;
readonly result: unknown;
};
};
export type EIP1193KnownSubscriptionMessage = EIP1193UnknownMessage & {
readonly type: 'eth_subscription';
readonly data: {
readonly subscription: EIP1193DATA;
readonly result:
| EIP1193Log
| EIP1193Block
| EIP1193DATA // transaction hash
| {
syncing: boolean;
status: {
startingBlock: number;
currentBlock: number;
highestBlock: number;
pulledStates: number;
knownStates: number;
};
};
};
};
// ------------------------------------------------------------------------------------------------
// TOOLS
// ------------------------------------------------------------------------------------------------
// taken from https://dev.to/bwca/deep-readonly-generic-in-typescript-4b04
type DeepReadonly<T> = Readonly<{
[K in keyof T]: T[K] extends number | string | symbol // Is it a primitive? Then make it readonly
? Readonly<T[K]>
: // Is it an array of items? Then make the array readonly and the item as well
T[K] extends Array<infer A>
? Readonly<Array<DeepReadonly<A>>>
: // It is some other object, make it readonly as well
DeepReadonly<T[K]>;
}>;
export type RPCRequestData = {params?: any; result?: any; errors?: any};
export type RPCMethods = Record<string, RPCRequestData>;
export type RemoteRequestCallType<
Method extends string,
Value,
Params extends any[] | Record<string, any> | undefined = undefined
> = Params extends undefined
? {
request: (req: {method: Method}) => Promise<Value>;
}
: Params extends []
? {
request: (req: {method: Method}) => Promise<Value>;
}
: {
request: (req: {method: Method; params: DeepReadonly<Params>}) => Promise<Value>;
};
export type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
export type RequestUnion<T extends RPCMethods> = {
[Property in keyof T]: RemoteRequestCallType<
Property extends string ? Property : never,
T[Property] extends {result: any} ? T[Property]['result'] : undefined,
T[Property] extends {params: any} ? T[Property]['params'] : undefined
>;
}[keyof T];
// ------------------------------------------------------------------------------------------------
// PROVIDERS
// ------------------------------------------------------------------------------------------------
export type RequestRPC<T extends RPCMethods> = UnionToIntersection<RequestUnion<T>> & {
request<U extends {params?: any; result?: any}>(req: {
method: string;
params: DeepReadonly<U['params']>;
}): Promise<U['result']>;
};
export type EIP1193ProviderWithoutEvents = RequestRPC<Methods>;
// export type EIP1193WindowWalletProvider = EIP1193Provider;
export type EIP1193WalletProvider = RequestRPC<WalletMethods>;
export type EIP1193WindowWalletProvider = EIP1193WalletProvider & EIP1193EventsProvider;
export type EIP1193SignerProvider = RequestRPC<SignerMethods>;
export type EIP1193DebugProvider = EIP1193ProviderWithoutEvents & RequestRPC<DebugOnlyMethods>;
export type EIP1193GenericRequestProvider = {
request<T = unknown, V extends EIP1193GenericRequest = EIP1193GenericRequest>(args: V): Promise<T>;
};
// ------------------------------------------------------------------------------------------------
// EVENTS PROVIDERS
// ------------------------------------------------------------------------------------------------
export interface EIP1193OnMessageProvider {
on(eventName: 'message', listener: Listener<EIP1193Message>): this;
removeListener(eventName: 'message', listener: Listener<EIP1193Message>): this;
}
export interface EIP1193OnConnectionProvider {
on(eventName: 'connect', listener: Listener<EIP1193ConnectInfoMessage>): this;
on(eventName: 'disconnect', listener: Listener<EIP1193ProviderRpcError>): this;
removeListener(eventName: 'connect', listener: Listener<EIP1193ConnectInfoMessage>): this;
removeListener(eventName: 'disconnect', listener: Listener<EIP1193ProviderRpcError>): this;
}
export interface EIP1193OnAccountsChangedProvider {
on(eventName: 'accountsChanged', listener: Listener<EIP1193Account[]>): this;
removeListener(eventName: 'accountsChanged', listener: Listener<EIP1193Account[]>): this;
}
export interface EIP1193OnChainChangedProvider {
on(eventName: 'chainChanged', listener: Listener<EIP1193ChainId>): this;
removeListener(eventName: 'chainChanged', listener: Listener<EIP1193ChainId>): this;
}
export interface EIP1193EventsProvider {
on(eventName: 'message', listener: Listener<EIP1193Message>): this;
removeListener(eventName: 'message', listener: Listener<EIP1193Message>): this;
on(eventName: 'connect', listener: Listener<EIP1193ConnectInfoMessage>): this;
on(eventName: 'disconnect', listener: Listener<EIP1193ProviderRpcError>): this;
removeListener(eventName: 'connect', listener: Listener<EIP1193ConnectInfoMessage>): this;
removeListener(eventName: 'disconnect', listener: Listener<EIP1193ProviderRpcError>): this;
on(eventName: 'accountsChanged', listener: Listener<EIP1193Account[]>): this;
removeListener(eventName: 'accountsChanged', listener: Listener<EIP1193Account[]>): this;
on(eventName: 'chainChanged', listener: Listener<EIP1193ChainId>): this;
removeListener(eventName: 'chainChanged', listener: Listener<EIP1193ChainId>): this;
}
export interface EIP1193Provider extends EIP1193ProviderWithoutEvents, EIP1193EventsProvider {}