Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
6 changes: 6 additions & 0 deletions .changeset/calm-moles-sell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@thirdweb-dev/react": patch
"@thirdweb-dev/sdk": patch
---

Fix using external signers with ThirdwebSDKProvider
53 changes: 52 additions & 1 deletion packages/react/src/Provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import {
} from "@thirdweb-dev/sdk";
import type { ThirdwebStorage } from "@thirdweb-dev/storage";
import { Signer } from "ethers";
import React, { createContext, useEffect, useMemo } from "react";
import React, { createContext, useEffect, useMemo, useState } from "react";
import invariant from "tiny-invariant";
import {
WagmiProvider,
Expand Down Expand Up @@ -587,3 +587,54 @@ export function useActiveChainId(): SUPPORTED_CHAIN_ID | undefined {
const sdk = useSDK();
return (sdk as any)?._chainId;
}

/**
* @internal
*/
export function useActiveSigner(): Signer | undefined {
const sdk = useSDK();
const [signer, setSigner] = useState<Signer | undefined>(sdk?.getSigner());
useEffect(() => {
if (sdk) {
sdk.wallet.events.on("signerChanged", (newSigner: Signer | undefined) => {
setSigner(newSigner);
});
return () => {
sdk.wallet.events.off("signerChanged");
};
}
}, [sdk]);
return signer;
}

/**
* @internal
*/
export function useActiveSignerAddress(): string | undefined {
const signer = useActiveSigner();
const [address, setAddress] = useState<string | undefined>(undefined);
useEffect(() => {
if (signer) {
signer.getAddress().then((a) => {
setAddress(a);
});
}
}, [signer]);
return address;
}

/**
* @internal
*/
export function useActiveSignerChainId(): number | undefined {
const signer = useActiveSigner();
const [chainId, setChainId] = useState<number | undefined>(undefined);
useEffect(() => {
if (signer) {
signer.getChainId().then((id) => {
setChainId(id);
});
}
}, [signer]);
return chainId;
}
13 changes: 8 additions & 5 deletions packages/react/src/hooks/async/contracts.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import { useActiveChainId, useSDK } from "../../Provider";
import {
useActiveChainId,
useActiveSignerAddress,
useActiveSignerChainId,
useSDK,
} from "../../Provider";
import { ContractAddress, RequiredParam } from "../../types";
import {
cacheKeys,
createCacheKeyWithNetwork,
createContractCacheKey,
} from "../../utils/cache-keys";
import { useQueryWithNetwork } from "../query-utils/useQueryWithNetwork";
import { useAddress } from "../useAddress";
import { useChainId } from "../useChainId";
import {
useMutation,
useQuery,
Expand Down Expand Up @@ -152,8 +155,8 @@ export function useContract<
const sdk = useSDK();
const queryClient = useQueryClient();
const activeChainId = useActiveChainId();
const wallet = useAddress();
const walletChainId = useChainId();
const wallet = useActiveSignerAddress();
const walletChainId = useActiveSignerChainId();

// it's there because we put it there.
const sdkTimestamp = (sdk as any)?._constructedAt;
Expand Down
2 changes: 1 addition & 1 deletion packages/sdk/src/core/sdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -409,8 +409,8 @@ export class ThirdwebSDK extends RPCConnectionHandler {
}

private updateContractSignerOrProvider() {
this.wallet.connect(this.getSignerOrProvider());
this.auth.updateSignerOrProvider(this.getSignerOrProvider());
this.wallet.onNetworkUpdated(this.getSignerOrProvider());
this.deployer.updateSignerOrProvider(this.getSignerOrProvider());
this._publisher.updateSignerOrProvider(this.getSignerOrProvider());
for (const [, contract] of this.contractCache) {
Expand Down
24 changes: 20 additions & 4 deletions packages/sdk/src/core/wallet/UserWallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,23 @@ import { RPCConnectionHandler } from "../classes/rpc-connection-handler";
import { NetworkOrSignerOrProvider, TransactionResult } from "../types";
import type { IERC20 } from "@thirdweb-dev/contracts-js";
import ERC20Abi from "@thirdweb-dev/contracts-js/dist/abis/IERC20.json";
import { ethers, BigNumber, providers } from "ethers";
import { ethers, BigNumber, providers, Signer } from "ethers";
import EventEmitter from "eventemitter3";
import invariant from "tiny-invariant";

/**
*
* {@link UserWallet} events that you can subscribe to using `sdk.wallet.events`.
*
* @public
*/
export interface UserWalletEvents {
/**
* Emitted when `sdk.wallet.connect()` is called.
*/
signerChanged: [Signer | undefined];
}

/**
* Connect and Interact with a user wallet
* @example
Expand All @@ -25,22 +39,24 @@ import invariant from "tiny-invariant";
export class UserWallet {
private connection: RPCConnectionHandler;
private options: SDKOptions;
public events = new EventEmitter<UserWalletEvents>();

constructor(network: NetworkOrSignerOrProvider, options: SDKOptions) {
this.connection = new RPCConnectionHandler(network, options);
this.options = options;
this.events = new EventEmitter();
}

// TODO connect()
// TODO disconnect()
// TODO switchChain()
// TODO event listener
// TODO tokens()
// TODO NFTs()

// TODO this will become the source of truth of the signer and have every contract read from it
onNetworkUpdated(network: NetworkOrSignerOrProvider): void {
// TODO separate signer and provider logics
public connect(network: NetworkOrSignerOrProvider) {
this.connection.updateSignerOrProvider(network);
this.events.emit("signerChanged", this.connection.getSigner());
}

/**
Expand Down
1 change: 0 additions & 1 deletion packages/solana/src/classes/user-wallet.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// import { getPayer } from "../utils/local-config";
import { CurrencyValue, WalletSigner } from "../types/common";
import { toCurrencyValue } from "../utils/token";
import {
Expand Down