Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
28 changes: 28 additions & 0 deletions packages/thirdweb/scripts/wallets/extra-wallets.json
Original file line number Diff line number Diff line change
Expand Up @@ -91,5 +91,33 @@
"native": null,
"universal": null
}
},
{
"id": "abstract",
"name": "Abstract Global Wallet",
"homepage": "https://abs.xyz/",
"image_id": "abstract.png",
"app": {
"browser": null,
"ios": null,
"android": null,
"mac": null,
"windows": null,
"linux": null,
"chrome": null,
"firefox": null,
"safari": null,
"edge": null,
"opera": null
},
"rdns": "xyz.abs",
"mobile": {
"native": null,
"universal": null
},
"desktop": {
"native": null,
"universal": null
}
}
]
136 changes: 136 additions & 0 deletions packages/thirdweb/src/adapters/eip1193/from-eip1193.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import { trackConnect } from "../../analytics/track/connect.js";
import type { Chain } from "../../chains/types.js";
import { getCachedChainIfExists } from "../../chains/utils.js";
import {
autoConnectEip1193Wallet,
connectEip1193Wallet,
} from "../../wallets/injected/index.js";
import type { Account, Wallet } from "../../wallets/interfaces/wallet.js";
import { createWalletEmitter } from "../../wallets/wallet-emitter.js";
import type { WalletId } from "../../wallets/wallet-types.js";
import type { EIP1193Provider } from "./types.js";

export type FromEip1193AdapterOptions = {
provider: EIP1193Provider | (() => Promise<EIP1193Provider>);
walletId?: WalletId;
};

/**
* Converts an EIP1193 provider to a Thirdweb wallet.
*
* @param options - The options for converting an EIP1193 provider to a Thirdweb wallet.
* @returns A Thirdweb wallet.
* @example
* ```ts
* import { EIP1193 } from "thirdweb/wallets";
* const wallet = EIP1193.fromProvider({ provider });
*
* // ... now you can use wallet with ConnectButton, useConnect, etc
* ```
* @walletUtils
*/
export function fromProvider(options: FromEip1193AdapterOptions): Wallet {
const id: WalletId = options.walletId ?? "adapter";
const emitter = createWalletEmitter();
let account: Account | undefined = undefined;
let chain: Chain | undefined = undefined;
let provider: EIP1193Provider | undefined = undefined;
const getProvider = async () => {
if (!provider) {
provider =
typeof options.provider === "function"
? await options.provider()
: options.provider;
}
return provider;
};

Check warning on line 46 in packages/thirdweb/src/adapters/eip1193/from-eip1193.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/adapters/eip1193/from-eip1193.ts#L33-L46

Added lines #L33 - L46 were not covered by tests

const unsubscribeChain = emitter.subscribe("chainChanged", (newChain) => {
chain = newChain;
});

Check warning on line 50 in packages/thirdweb/src/adapters/eip1193/from-eip1193.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/adapters/eip1193/from-eip1193.ts#L48-L50

Added lines #L48 - L50 were not covered by tests

function reset() {
account = undefined;
chain = undefined;
}

Check warning on line 55 in packages/thirdweb/src/adapters/eip1193/from-eip1193.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/adapters/eip1193/from-eip1193.ts#L52-L55

Added lines #L52 - L55 were not covered by tests

let handleDisconnect = async () => {};

Check warning on line 57 in packages/thirdweb/src/adapters/eip1193/from-eip1193.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/adapters/eip1193/from-eip1193.ts#L57

Added line #L57 was not covered by tests

const unsubscribeDisconnect = emitter.subscribe("disconnect", () => {
reset();
unsubscribeChain();
unsubscribeDisconnect();
});

Check warning on line 63 in packages/thirdweb/src/adapters/eip1193/from-eip1193.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/adapters/eip1193/from-eip1193.ts#L59-L63

Added lines #L59 - L63 were not covered by tests

emitter.subscribe("accountChanged", (_account) => {
account = _account;
});

Check warning on line 67 in packages/thirdweb/src/adapters/eip1193/from-eip1193.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/adapters/eip1193/from-eip1193.ts#L65-L67

Added lines #L65 - L67 were not covered by tests

let handleSwitchChain: (chain: Chain) => Promise<void> = async () => {
throw new Error("Not implemented");
};

Check warning on line 71 in packages/thirdweb/src/adapters/eip1193/from-eip1193.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/adapters/eip1193/from-eip1193.ts#L69-L71

Added lines #L69 - L71 were not covered by tests

return {
id: options.walletId as WalletId,
subscribe: emitter.subscribe,
getConfig: () => undefined,
getChain() {
if (!chain) {
return undefined;
}

Check warning on line 80 in packages/thirdweb/src/adapters/eip1193/from-eip1193.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/adapters/eip1193/from-eip1193.ts#L73-L80

Added lines #L73 - L80 were not covered by tests

chain = getCachedChainIfExists(chain.id) || chain;
return chain;
},
getAccount: () => account,
connect: async (connectOptions) => {
const [connectedAccount, connectedChain, doDisconnect, doSwitchChain] =
await connectEip1193Wallet({
id,
provider: await getProvider(),
client: connectOptions.client,
chain: connectOptions.chain,
emitter,
});

Check warning on line 94 in packages/thirdweb/src/adapters/eip1193/from-eip1193.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/adapters/eip1193/from-eip1193.ts#L82-L94

Added lines #L82 - L94 were not covered by tests
// set the states
account = connectedAccount;
chain = connectedChain;
handleDisconnect = doDisconnect;
handleSwitchChain = doSwitchChain;
trackConnect({
client: connectOptions.client,
walletType: id,
walletAddress: account.address,
});

Check warning on line 104 in packages/thirdweb/src/adapters/eip1193/from-eip1193.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/adapters/eip1193/from-eip1193.ts#L96-L104

Added lines #L96 - L104 were not covered by tests
// return account
return account;
},
autoConnect: async (connectOptions) => {
const [connectedAccount, connectedChain, doDisconnect, doSwitchChain] =
await autoConnectEip1193Wallet({
id,
provider: await getProvider(),
emitter,
chain: connectOptions.chain,
client: connectOptions.client,
});

Check warning on line 116 in packages/thirdweb/src/adapters/eip1193/from-eip1193.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/adapters/eip1193/from-eip1193.ts#L106-L116

Added lines #L106 - L116 were not covered by tests
// set the states
account = connectedAccount;
chain = connectedChain;
handleDisconnect = doDisconnect;
handleSwitchChain = doSwitchChain;
trackConnect({
client: connectOptions.client,
walletType: id,
walletAddress: account.address,
});

Check warning on line 126 in packages/thirdweb/src/adapters/eip1193/from-eip1193.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/adapters/eip1193/from-eip1193.ts#L118-L126

Added lines #L118 - L126 were not covered by tests
// return account
return account;
},
disconnect: async () => {
reset();
await handleDisconnect();
},
switchChain: (c) => handleSwitchChain(c),
};
}

Check warning on line 136 in packages/thirdweb/src/adapters/eip1193/from-eip1193.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/adapters/eip1193/from-eip1193.ts#L128-L136

Added lines #L128 - L136 were not covered by tests
11 changes: 11 additions & 0 deletions packages/thirdweb/src/adapters/eip1193/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export {
type FromEip1193AdapterOptions,
fromProvider,
} from "./from-eip1193.js";

export {
type ToEip1193ProviderOptions,
toProvider,
} from "./to-eip1193.js";

export type { EIP1193Provider } from "./types.js";
111 changes: 111 additions & 0 deletions packages/thirdweb/src/adapters/eip1193/to-eip1193.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import type { Account } from "viem/accounts";

import type { Chain } from "../../chains/types.js";
import type { ThirdwebClient } from "../../client/client.js";
import { getRpcClient } from "../../rpc/rpc.js";
import { estimateGas } from "../../transaction/actions/estimate-gas.js";
import { sendTransaction } from "../../transaction/actions/send-transaction.js";
import { prepareTransaction } from "../../transaction/prepare-transaction.js";
import type { Wallet } from "../../wallets/interfaces/wallet.js";
import type { EIP1193Provider } from "./types.js";

export type ToEip1193ProviderOptions = {
wallet: Wallet;
chain: Chain;
client: ThirdwebClient;
connectOverride?: (wallet: Wallet) => Promise<Account>;
};

/**
* Converts an EIP1193 provider to a Thirdweb wallet.
*
* @param options - The options for converting an EIP1193 provider to a Thirdweb wallet.
* @returns A Thirdweb wallet.
* @example
* ```ts
* import { EIP1193 } from "thirdweb/wallets";
* const provider = EIP1193.toProvider({ wallet, chain, client });
*
* // ... now you can use this providers with third party libraries
* ```
* @walletUtils
*/
export function toProvider(options: ToEip1193ProviderOptions): EIP1193Provider {
const { chain, client, wallet, connectOverride } = options;
const rpcClient = getRpcClient({ client, chain });
return {
on: wallet.subscribe,
removeListener: () => {

Check warning on line 38 in packages/thirdweb/src/adapters/eip1193/to-eip1193.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/adapters/eip1193/to-eip1193.ts#L34-L38

Added lines #L34 - L38 were not covered by tests
// should invoke the return fn from subscribe instead
},
request: async (request) => {
if (request.method === "eth_sendTransaction") {
const account = wallet.getAccount();
if (!account) {
throw new Error("Account not connected");
}
const result = await sendTransaction({
transaction: prepareTransaction({
...request.params[0],
chain,
client,
}),
account: account,
});
return result.transactionHash;
}
if (request.method === "eth_estimateGas") {
const account = wallet.getAccount();
if (!account) {
throw new Error("Account not connected");
}
return estimateGas({
transaction: prepareTransaction({
...request.params[0],
chain,
client,
}),
account,
});
}
if (request.method === "personal_sign") {
const account = wallet.getAccount();
if (!account) {
throw new Error("Account not connected");
}
return account.signMessage({
message: {
raw: request.params[0],
},
});
}
if (request.method === "eth_signTypedData_v4") {
const account = wallet.getAccount();
if (!account) {
throw new Error("Account not connected");
}
const data = JSON.parse(request.params[1]);
return account.signTypedData(data);
}
if (request.method === "eth_accounts") {
const account = wallet.getAccount();
if (!account) {
throw new Error("Account not connected");
}
return [account.address];
}
if (request.method === "eth_requestAccounts") {
const account = connectOverride
? await connectOverride(wallet)
: await wallet.connect({
client,
});
if (!account) {
throw new Error("Unable to connect wallet");
}
return [account.address];
}
return rpcClient(request);
},
};
}

Check warning on line 111 in packages/thirdweb/src/adapters/eip1193/to-eip1193.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/adapters/eip1193/to-eip1193.ts#L40-L111

Added lines #L40 - L111 were not covered by tests
9 changes: 9 additions & 0 deletions packages/thirdweb/src/adapters/eip1193/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// loose interface on purpose to adapt to any version of viem, ethers, ox, web3js, etc
export type EIP1193Provider = {
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
on(event: any, listener: (params: any) => any): void;
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
removeListener(event: any, listener: (params: any) => any): void;
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
request: (params: any) => Promise<any>;
};
2 changes: 1 addition & 1 deletion packages/thirdweb/src/analytics/track/transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ type TransactionEvent = {
ecosystem?: Ecosystem;
transactionHash?: string;
walletAddress?: string;
walletType?: WalletId;
walletType?: WalletId | ({} & string);
chainId?: number;
contractAddress?: string;
functionName?: string;
Expand Down
3 changes: 3 additions & 0 deletions packages/thirdweb/src/exports/wallets.native.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,9 @@ export type {
WalletConnectSession,
} from "../wallets/wallet-connect/receiver/types.js";

// eip1193
export * as EIP1193 from "../adapters/eip1193/index.js";

// NOT SUPPORTED

export const injectedProvider = () => {
Expand Down
3 changes: 3 additions & 0 deletions packages/thirdweb/src/exports/wallets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,9 @@ export type {
WalletConnectSession,
} from "../wallets/wallet-connect/receiver/types.js";

// eip1193
export * as EIP1193 from "../adapters/eip1193/index.js";

// WEB ONLY EXPORTS

// injected
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useConnectedWallets } from "./useConnectedWallets.js";
* Get the admin wallet for the active wallet
* Useful for smart wallets to get the underlying personal account
* @returns The admin wallet for the active wallet, or the active wallet if it doesn't have an admin account
* @walletConnection
*/
export function useAdminWallet() {
const activeWallet = useActiveWallet();
Expand Down
Loading
Loading