Compare commits

...
Author SHA1 Message Date
Jonas DanielsGitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>GitHub Action
57b1f5839d Version Packages (#2669)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: GitHub Action <[email protected]>
2024-04-04 00:48:19 +02:00
Joaquim VergesandGitHub 97a31f57ce feat: add useSendAndConfirmTransaction hook (#2674) 2024-04-03 19:17:14 +00:00
github-actions[bot]andGitHub 319435a331 chore(chains): update chains (#2673) 2024-04-03 12:19:41 -07:00
69ee97981c chore: add more adapter tests (#2672)
Co-authored-by: Jonas Daniels <[email protected]>
2024-04-03 18:35:36 +00:00
44d96309d5 feat: Add provider and signTypedData to ethers5 signer adapter (#2667)
Co-authored-by: Jonas Daniels <[email protected]>
2024-04-03 18:09:54 +00:00
367576ca00 feat: always use new session when calling connect method for WC (#2637)
Co-authored-by: Jonas Daniels <[email protected]>
2024-04-03 17:51:31 +00:00
Jonas DanielsandGitHub 6fc9afa58f test: Update contract deployment tests (#2671) 2024-04-03 17:40:47 +00:00
b4a71d5d5b chore(chains): update chains (#2670)
Co-authored-by: GitHub Action <[email protected]>
2024-04-03 10:03:33 -07:00
127c476cff Fix getAddresses call for accounts converted to viem (#2666)
Co-authored-by: Jonas Daniels <[email protected]>
2024-04-03 09:14:00 -07:00
b3fca9509f chore(chains): update chains (#2668)
Co-authored-by: GitHub Action <[email protected]>
2024-04-03 09:02:15 -07:00
65 changed files with 825 additions and 251 deletions
+7
View File
@@ -1,5 +1,12 @@
# @thirdweb-dev/auth
## 4.1.55
### Patch Changes
- Updated dependencies []:
- @thirdweb-dev/wallets@2.4.33
## 4.1.54
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/auth",
"version": "4.1.54",
"version": "4.1.55",
"main": "dist/thirdweb-dev-auth.cjs.js",
"module": "dist/thirdweb-dev-auth.esm.js",
"browser": {
+6
View File
@@ -1,5 +1,11 @@
# @thirdweb-dev/chains
## 0.1.88
### Patch Changes
- [#2668](https://github.com/thirdweb-dev/js/pull/2668) [`b3fca95`](https://github.com/thirdweb-dev/js/commit/b3fca9509feb0ac6e0ded816f08570b2954f6521) Thanks [@github-actions](https://github.com/apps/github-actions)! - Synced Chains Package
## 0.1.87
### Patch Changes
+34
View File
@@ -0,0 +1,34 @@
import type { Chain } from "../src/types";
export default {
"chain": "Jumbo",
"chainId": 1009,
"explorers": [
{
"name": "Jumboscan",
"url": "https://jumboscan.jumbochain.org",
"standard": "EIP3091"
}
],
"faucets": [],
"features": [
{
"name": "EIP155"
}
],
"infoURL": "https://jumbochain.org",
"name": "Jumbochain Mainnet",
"nativeCurrency": {
"name": "JNFTC",
"symbol": "JNFTC",
"decimals": 18
},
"networkId": 1009,
"rpc": [
"https://1009.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpcpriv.jumbochain.org"
],
"shortName": "Jumboscan",
"slip44": 1,
"slug": "jumbochain",
"testnet": false
} as const satisfies Chain;
+30
View File
@@ -0,0 +1,30 @@
import type { Chain } from "../src/types";
export default {
"chain": "Avalanche",
"chainId": 49053,
"explorers": [],
"faucets": [],
"features": [],
"icon": {
"url": "https://images.ctfassets.net/9bazykntljf6/62CceHSYsRS4D9fgDSkLRB/877cb8f26954e1743ff535fd7fdaf78f/avacloud-placeholder.svg",
"width": 256,
"height": 256,
"format": "svg"
},
"infoURL": "https://avacloud.io",
"name": "QaUser5759 Testnet",
"nativeCurrency": {
"name": "QaUser5759 Testnet Token",
"symbol": "ATZ",
"decimals": 18
},
"networkId": 49053,
"redFlags": [],
"rpc": [
"https://49053.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://subnets.avax.network/defi-kingdoms/dfk-chain/rpc"
],
"shortName": "QaUser5759 Testnet",
"slug": "qauser5759-testnet",
"testnet": true
} as const satisfies Chain;
+36
View File
@@ -0,0 +1,36 @@
import type { Chain } from "../src/types";
export default {
"chain": "ONIGIRI",
"chainId": 5039,
"explorers": [
{
"name": "ONIGIRI Explorer",
"url": "https://subnets-test.avax.network/onigiri",
"standard": "EIP3091"
}
],
"faucets": [],
"features": [
{
"name": "EIP155"
},
{
"name": "EIP1559"
}
],
"infoURL": "https://www.ongr.org/",
"name": "ONIGIRI Test Subnet",
"nativeCurrency": {
"name": "ONIGIRI",
"symbol": "ONGR",
"decimals": 18
},
"networkId": 5039,
"rpc": [
"https://5039.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://subnets.avax.network/onigiri/testnet/rpc"
],
"shortName": "onigiri",
"slug": "onigiri-test-subnet",
"testnet": true
} as const satisfies Chain;
+54
View File
@@ -0,0 +1,54 @@
import type { Chain } from "../src/types";
export default {
"chain": "ETH",
"chainId": 62049,
"explorers": [
{
"name": "optopia-testnet-scan",
"url": "https://scan-testnet.optopia.ai",
"standard": "EIP3091",
"icon": {
"url": "ipfs://bafkreid3xv3zkuo2cygwt7vwm5c2aqjbyhy5qxn7xkc66ajhu2mjh2ybki",
"width": 1000,
"height": 1000,
"format": "png"
}
}
],
"faucets": [],
"features": [
{
"name": "EIP1559"
}
],
"icon": {
"url": "ipfs://bafkreid3xv3zkuo2cygwt7vwm5c2aqjbyhy5qxn7xkc66ajhu2mjh2ybki",
"width": 1000,
"height": 1000,
"format": "png"
},
"infoURL": "https://optopia.ai",
"name": "OPTOPIA Testnet",
"nativeCurrency": {
"name": "Ether",
"symbol": "ETH",
"decimals": 18
},
"networkId": 62049,
"parent": {
"type": "L2",
"chain": "eip155-11155111",
"bridges": [
{
"url": "https://bridge-testnet.optopia.ai"
}
]
},
"rpc": [
"https://62049.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc-testnet.optopia.ai"
],
"shortName": "OPTOPIA-Testnet",
"slug": "optopia-testnet",
"testnet": true
} as const satisfies Chain;
+30
View File
@@ -0,0 +1,30 @@
import type { Chain } from "../src/types";
export default {
"chain": "Avalanche",
"chainId": 66063,
"explorers": [],
"faucets": [],
"features": [],
"icon": {
"url": "https://images.ctfassets.net/9bazykntljf6/62CceHSYsRS4D9fgDSkLRB/877cb8f26954e1743ff535fd7fdaf78f/avacloud-placeholder.svg",
"width": 256,
"height": 256,
"format": "svg"
},
"infoURL": "https://avacloud.io",
"name": "QaUser3324 Testnet",
"nativeCurrency": {
"name": "QaUser3324 Testnet Token",
"symbol": "IYM",
"decimals": 18
},
"networkId": 66063,
"redFlags": [],
"rpc": [
"https://66063.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://subnets.avax.network/defi-kingdoms/dfk-chain/rpc"
],
"shortName": "QaUser3324 Testnet",
"slug": "qauser3324-testnet",
"testnet": true
} as const satisfies Chain;
+34
View File
@@ -0,0 +1,34 @@
import type { Chain } from "../src/types";
export default {
"chain": "BORA",
"chainId": 77001,
"explorers": [
{
"name": "BORAchainscope",
"url": "https://scope.boraportal.com",
"standard": "EIP3091"
}
],
"faucets": [],
"icon": {
"url": "ipfs://QmccGWJcCzQh3rP6ZMdRyTc7JjtusKnXkoUtGUANQgjNqR",
"width": 48,
"height": 48,
"format": "svg"
},
"infoURL": "https://www.boraportal.com",
"name": "BORAchain mainnet",
"nativeCurrency": {
"name": "BGAS",
"symbol": "BGAS",
"decimals": 18
},
"networkId": 77001,
"rpc": [
"https://77001.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://public-node.api.boraportal.io/bora/mainnet"
],
"shortName": "BORAchain",
"slug": "borachain",
"testnet": false
} as const satisfies Chain;
+1
View File
@@ -36,6 +36,7 @@ export default {
"redFlags": [],
"rpc": [
"https://80085.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://quicknode-rpc.berachain.com",
"https://artio.rpc.berachain.com",
"https://rpc.ankr.com/berachain_testnet"
],
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/chains",
"version": "0.1.87",
"version": "0.1.88",
"main": "dist/thirdweb-dev-chains.cjs.js",
"module": "dist/thirdweb-dev-chains.esm.js",
"exports": {
File diff suppressed because one or more lines are too long
+10
View File
@@ -1,5 +1,15 @@
# thirdweb
## 0.13.63
### Patch Changes
- Updated dependencies [[`b3fca95`](https://github.com/thirdweb-dev/js/commit/b3fca9509feb0ac6e0ded816f08570b2954f6521)]:
- @thirdweb-dev/chains@0.1.88
- @thirdweb-dev/sdk@4.0.57
- @thirdweb-dev/wallets@2.4.33
- @thirdweb-dev/auth@4.1.55
## 0.13.62
### Patch Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@thirdweb-dev/cli",
"main": "dist/cli/index.js",
"version": "0.13.62",
"version": "0.13.63",
"repository": "https://github.com/thirdweb-dev/js/tree/main/legacy_packages/cli",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
+10
View File
@@ -1,5 +1,15 @@
# @thirdweb-dev/react-core
## 4.4.31
### Patch Changes
- Updated dependencies [[`b3fca95`](https://github.com/thirdweb-dev/js/commit/b3fca9509feb0ac6e0ded816f08570b2954f6521)]:
- @thirdweb-dev/chains@0.1.88
- @thirdweb-dev/sdk@4.0.57
- @thirdweb-dev/wallets@2.4.33
- @thirdweb-dev/auth@4.1.55
## 4.4.30
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/react-core",
"version": "4.4.30",
"version": "4.4.31",
"repository": "https://github.com/thirdweb-dev/js/tree/main/legacy_packages/react-core",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
@@ -1,5 +1,7 @@
# @thirdweb-dev/react-native-compat
## 0.7.28
## 0.7.27
## 0.7.26
@@ -1,7 +1,7 @@
{
"name": "@thirdweb-dev/react-native-compat",
"description": "Shims for Thirdweb in React Native Projects",
"version": "0.7.27",
"version": "0.7.28",
"author": "thirdweb eng <[email protected]>",
"repository": "https://github.com/thirdweb-dev/js/tree/main/legacy_packages/react-native-compat",
"license": "Apache-2.0",
+10
View File
@@ -1,5 +1,15 @@
# @thirdweb-dev/react-native
## 0.7.28
### Patch Changes
- Updated dependencies [[`b3fca95`](https://github.com/thirdweb-dev/js/commit/b3fca9509feb0ac6e0ded816f08570b2954f6521)]:
- @thirdweb-dev/chains@0.1.88
- @thirdweb-dev/react-core@4.4.31
- @thirdweb-dev/sdk@4.0.57
- @thirdweb-dev/wallets@2.4.33
## 0.7.27
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/react-native",
"version": "0.7.27",
"version": "0.7.28",
"repository": "https://github.com/thirdweb-dev/js/tree/main/legacy_packages/react-native",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
+10
View File
@@ -1,5 +1,15 @@
# @thirdweb-dev/react
## 4.4.31
### Patch Changes
- Updated dependencies [[`b3fca95`](https://github.com/thirdweb-dev/js/commit/b3fca9509feb0ac6e0ded816f08570b2954f6521)]:
- @thirdweb-dev/chains@0.1.88
- @thirdweb-dev/react-core@4.4.31
- @thirdweb-dev/sdk@4.0.57
- @thirdweb-dev/wallets@2.4.33
## 4.4.30
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/react",
"version": "4.4.30",
"version": "4.4.31",
"repository": "https://github.com/thirdweb-dev/js/tree/main/legacy_packages/react",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
Binary file not shown.
+7
View File
@@ -1,5 +1,12 @@
# @thirdweb-dev/sdk
## 4.0.57
### Patch Changes
- Updated dependencies [[`b3fca95`](https://github.com/thirdweb-dev/js/commit/b3fca9509feb0ac6e0ded816f08570b2954f6521)]:
- @thirdweb-dev/chains@0.1.88
## 4.0.56
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/sdk",
"version": "4.0.56",
"version": "4.0.57",
"description": "The main thirdweb SDK.",
"repository": "https://github.com/thirdweb-dev/js/tree/main/legacy_packages/sdk",
"license": "Apache-2.0",
Binary file not shown.
+8
View File
@@ -1,5 +1,13 @@
# @thirdweb-dev/wallets
## 2.4.33
### Patch Changes
- Updated dependencies [[`b3fca95`](https://github.com/thirdweb-dev/js/commit/b3fca9509feb0ac6e0ded816f08570b2954f6521)]:
- @thirdweb-dev/chains@0.1.88
- @thirdweb-dev/sdk@4.0.57
## 2.4.32
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/wallets",
"version": "2.4.32",
"version": "2.4.33",
"main": "dist/thirdweb-dev-wallets.cjs.js",
"module": "dist/thirdweb-dev-wallets.esm.js",
"browser": {
+21
View File
@@ -1,5 +1,26 @@
# thirdweb
## 5.2.0
### Minor Changes
- [#2667](https://github.com/thirdweb-dev/js/pull/2667) [`44d9630`](https://github.com/thirdweb-dev/js/commit/44d96309d5dd069fac5968f2708d555c4453fcfa) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - API update for ethers5 and ethers5 adapters:
- Now all adapter functions take a singular object
- ethers5: fixed adapted signer not containing a provider by default
- ethers5: added support for sign typed data
- [#2674](https://github.com/thirdweb-dev/js/pull/2674) [`97a31f5`](https://github.com/thirdweb-dev/js/commit/97a31f57cee822cb26339e1fbfc80909d1ee6508) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Add `useSendAndConfirmTransaction` hook
### Patch Changes
- [#2666](https://github.com/thirdweb-dev/js/pull/2666) [`127c476`](https://github.com/thirdweb-dev/js/commit/127c476cff1b5f7e67224dff3ed49ea2cbd93027) Thanks [@gregfromstl](https://github.com/gregfromstl)! - fix getAddresses for accounts converted to viem
- [#2637](https://github.com/thirdweb-dev/js/pull/2637) [`367576c`](https://github.com/thirdweb-dev/js/commit/367576ca00470a4b9a39c6fb748545d565d7c353) Thanks [@MananTank](https://github.com/MananTank)! - - Always start a new session when calling `wallet.connect` for WalletConnect
- Fix JSDoc for `useConnectedWallets`
- Add `accountsChanged` event back to `Wallet`
- `wallet.disconnect` method cleanups
## 5.1.1
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "thirdweb",
"version": "5.1.1",
"version": "5.2.0",
"repository": {
"type": "git",
"url": "git+https://github.com/thirdweb-dev/js.git#main"
@@ -0,0 +1,99 @@
import { describe, test, expect } from "vitest";
import { privateKeyAccount } from "../wallets/private-key.js";
import { TEST_CLIENT } from "../../test/src/test-clients.js";
import { toEthersSigner } from "./ethers5.js";
import { ANVIL_CHAIN } from "../../test/src/chains.js";
import * as ethers5 from "ethers5";
import { ANVIL_PKEY_A, TEST_ACCOUNT_B } from "../../test/src/test-wallets.js";
const account = privateKeyAccount({
privateKey: ANVIL_PKEY_A,
client: TEST_CLIENT,
});
describe("ethers5 adapter", () => {
test("should return an ethers 5 signer", async () => {
const signer = await toEthersSigner(
ethers5,
TEST_CLIENT,
account,
ANVIL_CHAIN,
);
expect(signer).toBeDefined();
expect(signer.signMessage).toBeDefined();
});
test("should sign message", async () => {
const signer = await toEthersSigner(
ethers5,
TEST_CLIENT,
account,
ANVIL_CHAIN,
);
const expectedSig = await account.signMessage({ message: "hello world" });
const sig = await signer.signMessage("hello world");
expect(sig).toBe(expectedSig);
});
test("should sign typed data", async () => {
const signer = await toEthersSigner(
ethers5,
TEST_CLIENT,
account,
ANVIL_CHAIN,
);
expect(signer._signTypedData).toBeDefined();
// All properties on a domain are optional
const domain = {
name: "Ether Mail",
version: "1",
chainId: 1,
verifyingContract: "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC",
};
// The named list of all type definitions
const types = {
Person: [
{ name: "name", type: "string" },
{ name: "wallet", type: "address" },
],
Mail: [
{ name: "from", type: "Person" },
{ name: "to", type: "Person" },
{ name: "contents", type: "string" },
],
};
// The data to sign
const value = {
from: {
name: "Cow",
wallet: "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
},
to: {
name: "Bob",
wallet: "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB",
},
contents: "Hello, Bob!",
};
const signature = await signer._signTypedData(domain, types, value);
expect(signature.length).toBe(132);
});
test("should send a tx", async () => {
const signer = await toEthersSigner(
ethers5,
TEST_CLIENT,
account,
ANVIL_CHAIN,
);
const txResponse = await signer.sendTransaction({
to: TEST_ACCOUNT_B.address,
value: 100,
});
expect(txResponse.hash.length).toBe(66);
});
});
+129 -30
View File
@@ -5,11 +5,10 @@ import type { Abi } from "abitype";
import type { AccessList, Hex, TransactionSerializable } from "viem";
import type { ThirdwebClient } from "../client/client.js";
import type { Account } from "../wallets/interfaces/wallet.js";
import { defineChain, getRpcUrlForChain } from "../chains/utils.js";
import { getRpcUrlForChain } from "../chains/utils.js";
import type { Chain } from "../chains/types.js";
import { getContract, type ThirdwebContract } from "../contract/contract.js";
import { uint8ArrayToHex } from "../utils/encoding/hex.js";
import { resolvePromisedValue } from "../utils/promise/resolve-promised-value.js";
import { toHex, uint8ArrayToHex } from "../utils/encoding/hex.js";
import { waitForReceipt } from "../transaction/actions/wait-for-tx-receipt.js";
import { prepareTransaction } from "../transaction/prepare-transaction.js";
import { sendTransaction } from "../transaction/actions/send-transaction.js";
@@ -47,36 +46,44 @@ function assertEthers5(
export const ethers5Adapter = /* @__PURE__ */ (() => {
const ethers = universalethers;
assertEthers5(ethers);
return {
provider: {
/**
* Converts a Thirdweb client and chain ID into an ethers.js provider.
* @param client - The Thirdweb client.
* @param chain - The chain.
* @param options - The options for converting the Thirdweb client and chain ID into an ethers.js provider.
* @param options.client - The Thirdweb client.
* @param options.chain - The chain.
* @returns The ethers.js provider.
* @example
* ```ts
* import { ethers5Adapter } from "thirdweb/adapters/ethers5";
* const provider = ethers5Adapter.provider.toEthers(client, chainId);
* const provider = ethers5Adapter.provider.toEthers({ client, chainId });
* ```
*/
toEthers: (client: ThirdwebClient, chain: Chain) =>
toEthersProvider(ethers, client, chain),
toEthers: (options: { client: ThirdwebClient; chain: Chain }) => {
assertEthers5(ethers);
return toEthersProvider(ethers, options.client, options.chain);
},
},
contract: {
/**
* Converts a ThirdwebContract to an ethers.js Contract.
* @param twContract - The ThirdwebContract to convert.
* @param options - The options for converting the ThirdwebContract to an ethers.js Contract.
* @param options.thirdwebContract - The ThirdwebContract to convert.
* @returns A Promise that resolves to an ethers.js Contract.
* @example
* ```ts
* import { ethers5Adapter } from "thirdweb/adapters/ethers5";
* const ethersContract = await ethers5Adapter.contract.toEthers(twContract);
* const ethersContract = await ethers5Adapter.contract.toEthers({
* thirdwebContract,
* });
* ```
*/
toEthers: (twContract: ThirdwebContract) =>
toEthersContract(ethers, twContract),
toEthers: (options: { thirdwebContract: ThirdwebContract }) => {
assertEthers5(ethers);
return toEthersContract(ethers, options.thirdwebContract);
},
/**
* Creates a ThirdwebContract instance from an ethers.js contract.
* @param options - The options for creating the ThirdwebContract instance.
@@ -92,35 +99,54 @@ export const ethers5Adapter = /* @__PURE__ */ (() => {
* });
* ```
*/
fromEthers: (options: FromEthersContractOptions) =>
fromEthersContract(options),
fromEthers: (options: FromEthersContractOptions) => {
assertEthers5(ethers);
return fromEthersContract(options);
},
},
signer: {
/**
* Converts an ethers5 Signer into a Wallet object.
* @param signer - The ethers5 Signer object.
* @param options - The options for converting the ethers5 Signer into a Wallet object.
* @param options.signer - The ethers5 Signer object.
* @returns - A Promise that resolves to aa Wallet object.
* @example
* ```ts
* import { ethers5Adapter } from "thirdweb/adapters/ethers5";
* const wallet = await ethers5Adapter.signer.fromEthersSigner(signer);
* const wallet = await ethers5Adapter.signer.fromEthersSigner({ signer });
* ```
*/
fromEthers: (signer: ethers5.Signer) => fromEthersSigner(signer),
fromEthers: (options: { signer: ethers5.Signer }) => {
assertEthers5(ethers);
return fromEthersSigner(options.signer);
},
/**
* Converts a Thirdweb wallet to an ethers.js signer.
* @param client - The thirdweb client.
* @param account - The account.
* @param options - The options for converting the Thirdweb wallet to an ethers.js signer.
* @param options.client - The thirdweb client.
* @param options.chain - The chain.
* @param options.account - The account.
* @returns A promise that resolves to an ethers.js signer.
* @example
* ```ts
* import { ethers5Adapter } from "thirdweb/adapters/ethers5";
* const signer = await ethers5Adapter.signer.toEthers(client, chain, account);
* const signer = await ethers5Adapter.signer.toEthers({ client, chain, account });
* ```
*/
toEthers: (client: ThirdwebClient, account: Account) =>
toEthersSigner(ethers, client, account),
toEthers: (options: {
client: ThirdwebClient;
chain: Chain;
account: Account;
}) => {
assertEthers5(ethers);
return toEthersSigner(
ethers,
options.client,
options.account,
options.chain,
);
},
},
};
})();
@@ -240,18 +266,40 @@ async function fromEthersSigner(signer: ethers5.Signer): Promise<Account> {
return account;
}
async function toEthersSigner(
/**
* @internal
*/
export async function toEthersSigner(
ethers: Ethers5,
client: ThirdwebClient,
account: Account,
chain: Chain,
) {
class ThirdwebAdapterSigner extends ethers.Signer {
/**
* @internal
*/
constructor() {
super();
ethers.utils.defineReadOnly(
this,
"provider",
toEthersProvider(ethers, client, chain),
);
}
/**
* @internal
*/
override getAddress(): Promise<string> {
if (!account) {
throw new Error("Account not found");
}
return Promise.resolve(account.address);
}
/**
* @internal
*/
override signMessage(message: string | Uint8Array): Promise<string> {
if (!account) {
throw new Error("Account not found");
@@ -261,6 +309,9 @@ async function toEthersSigner(
typeof message === "string" ? message : uint8ArrayToHex(message),
});
}
/**
* @internal
*/
override async signTransaction(
transaction: ethers5.ethers.utils.Deferrable<ethers5.ethers.providers.TransactionRequest>,
): Promise<string> {
@@ -276,10 +327,11 @@ async function toEthersSigner(
);
}
/**
* @internal
*/
override async sendTransaction(
transaction: ethers5.ethers.utils.Deferrable<
ethers5.ethers.providers.TransactionRequest & { chainId: number }
>,
transaction: ethers5.ethers.utils.Deferrable<ethers5.ethers.providers.TransactionRequest>,
): Promise<ethers5.ethers.providers.TransactionResponse> {
if (!account) {
throw new Error("Account not found");
@@ -290,8 +342,8 @@ async function toEthersSigner(
const awaitedTx = await ethers.utils.resolveProperties(transaction);
const alignedTx = await alignTxFromEthers(awaitedTx, ethers);
const tx = prepareTransaction({
client,
chain: defineChain(await resolvePromisedValue(transaction.chainId)),
client: client,
chain: chain,
accessList: alignedTx.accessList,
data: alignedTx.data,
gas: alignedTx.gas,
@@ -303,7 +355,10 @@ async function toEthersSigner(
to: alignedTx.to ?? undefined,
value: alignedTx.value,
});
const result = await sendTransaction({ transaction: tx, account });
const result = await sendTransaction({
transaction: tx,
account: account,
});
const response: ethers5.ethers.providers.TransactionResponse = {
chainId: tx.chain.id,
@@ -350,6 +405,39 @@ async function toEthersSigner(
return response;
}
// eslint-disable-next-line jsdoc/require-jsdoc
async _signTypedData(
domain: ethers5.ethers.TypedDataDomain,
types: Record<string, ethers5.ethers.TypedDataField[]>,
value: Record<string, any>,
): Promise<string> {
if (!account) {
throw new Error("Account not found");
}
const typedDataEncoder = new ethers.utils._TypedDataEncoder(types);
const typedData = {
primaryType: typedDataEncoder.primaryType,
domain: {
chainId: domain.chainId
? bigNumberIshToNumber(domain.chainId)
: undefined,
name: domain.name ?? undefined,
salt: domain.salt ? toHex(domain.salt.toString()) : undefined,
verifyingContract: domain.verifyingContract ?? undefined,
version: domain.version ?? undefined,
},
types,
message: value,
};
return account.signTypedData(typedData);
}
/**
* @internal
*/
override connect(): ethers5.ethers.Signer {
return this;
}
@@ -472,3 +560,14 @@ async function alignTxFromEthers(
}
}
}
function bigNumberIshToBigint(value: ethers5.BigNumberish): bigint {
if (typeof value === "bigint") {
return value;
}
return BigInt(value.toString());
}
function bigNumberIshToNumber(value: ethers5.BigNumberish): number {
return Number(bigNumberIshToBigint(value));
}
+37 -20
View File
@@ -1,37 +1,43 @@
import { describe, test, expect } from "vitest";
import * as ethers6 from "ethers6";
import { privateKeyAccount } from "../wallets/private-key.js";
import { TEST_CLIENT } from "../../test/src/test-clients.js";
import { toEthersSigner } from "./ethers6.js";
import { ethers6Adapter } from "./ethers6.js";
import { ANVIL_CHAIN } from "../../test/src/chains.js";
const FAKE_PKEY =
"0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
import { ANVIL_PKEY_A, TEST_ACCOUNT_B } from "../../test/src/test-wallets.js";
const account = privateKeyAccount({
privateKey: FAKE_PKEY,
privateKey: ANVIL_PKEY_A,
client: TEST_CLIENT,
});
describe("toEthersSigner", () => {
test("should return an ethers 6 signer", async () => {
const signer = await toEthersSigner(
ethers6,
TEST_CLIENT,
const signer = await ethers6Adapter.signer.toEthers({
client: TEST_CLIENT,
account,
ANVIL_CHAIN,
);
chain: ANVIL_CHAIN,
});
expect(signer).toBeDefined();
expect(signer.signMessage).toBeDefined();
});
test("should sign typed data", async () => {
const signer = await toEthersSigner(
ethers6,
TEST_CLIENT,
test("should sign message", async () => {
const signer = await ethers6Adapter.signer.toEthers({
client: TEST_CLIENT,
account,
ANVIL_CHAIN,
);
chain: ANVIL_CHAIN,
});
const expectedSig = await account.signMessage({ message: "hello world" });
const sig = await signer.signMessage("hello world");
expect(sig).toBe(expectedSig);
});
test("should sign typed data", async () => {
const signer = await ethers6Adapter.signer.toEthers({
client: TEST_CLIENT,
account,
chain: ANVIL_CHAIN,
});
expect(signer.signTypedData).toBeDefined();
// All properties on a domain are optional
@@ -70,8 +76,19 @@ describe("toEthersSigner", () => {
const signature = await signer.signTypedData(domain, types, value);
expect(signature).toMatchInlineSnapshot(
`"0x10d3ce8040590e48889801080ad40f3d514c2c3ce03bbbe3e179bbf5ba56c75425951fa15220f637e2ab79fd033b99c4b340339e00e360316547e956c61ffcb01c"`,
);
expect(signature.length).toBe(132);
});
test("should send a tx", async () => {
const signer = await ethers6Adapter.signer.toEthers({
client: TEST_CLIENT,
account,
chain: ANVIL_CHAIN,
});
const txResponse = await signer.sendTransaction({
to: TEST_ACCOUNT_B.address,
value: 100,
});
expect(txResponse.hash.length).toBe(66);
});
});
+72 -43
View File
@@ -11,6 +11,8 @@ import { getRpcUrlForChain } from "../chains/utils.js";
import type { Chain } from "../chains/types.js";
import { getContract, type ThirdwebContract } from "../contract/contract.js";
import { toHex, uint8ArrayToHex } from "../utils/encoding/hex.js";
import { toSerializableTransaction } from "../transaction/actions/to-serializable-transaction.js";
import type { PreparedTransaction } from "../transaction/prepare-transaction.js";
type Ethers6 = typeof ethers6;
@@ -50,34 +52,36 @@ export const ethers6Adapter = /* @__PURE__ */ (() => {
provider: {
/**
* Converts a Thirdweb client and chain ID into an ethers.js provider.
* @param client - The Thirdweb client.
* @param chain - The chain.
* @param options - The options for converting the Thirdweb client and chain ID into an ethers.js provider.
* @param options.client - The Thirdweb client.
* @param options.chain - The chain.
* @returns The ethers.js provider.
* @example
* ```ts
* import { ethers6Adapter } from "thirdweb/adapters/ethers6";
* const provider = ethers6Adapter.provider.toEthers(client, chainId);
* const provider = ethers6Adapter.provider.toEthers({ client, chainId });
* ```
*/
toEthers: (client: ThirdwebClient, chain: Chain) => {
toEthers: (options: { client: ThirdwebClient; chain: Chain }) => {
assertEthers6(ethers);
return toEthersProvider(ethers, client, chain);
return toEthersProvider(ethers, options.client, options.chain);
},
},
contract: {
/**
* Converts a ThirdwebContract to an ethers.js Contract.
* @param twContract - The ThirdwebContract to convert.
* @param options - The options for converting the ThirdwebContract to an ethers.js Contract.
* @param options.thirdwebContract - The ThirdwebContract to convert.
* @returns A Promise that resolves to an ethers.js Contract.
* @example
* ```ts
* import { ethers6Adapter } from "thirdweb/adapters/ethers6";
* const ethersContract = await ethers6Adapter.contract.toEthers(twContract);
* const ethersContract = await ethers6Adapter.contract.toEthers({ thirdwebContract });
* ```
*/
toEthers: (twContract: ThirdwebContract) => {
toEthers: (options: { thirdwebContract: ThirdwebContract }) => {
assertEthers6(ethers);
return toEthersContract(ethers, twContract);
return toEthersContract(ethers, options.thirdwebContract);
},
/**
* Creates a ThirdwebContract instance from an ethers.js contract.
@@ -102,34 +106,45 @@ export const ethers6Adapter = /* @__PURE__ */ (() => {
signer: {
/**
* Converts an ethers6 Signer into an Wallet object.
* @param signer - The ethers6 Signer object.
* @param options - The options for converting the ethers6 Signer into a Wallet object.
* @param options.signer - The ethers6 Signer object.
* @returns - A Promise that resolves to an Wallet object.
* @example
* ```ts
* import { ethers6Adapter } from "thirdweb/adapters/ethers6";
* const wallet = await ethers6Adapter.signer.fromEthersSigner(signer);
* const wallet = await ethers6Adapter.signer.fromEthersSigner({ signer });
* ```
*/
fromEthers: (signer: ethers6.Signer) => {
fromEthers: (options: { signer: ethers6.Signer }) => {
assertEthers6(ethers);
return fromEthersSigner(signer);
return fromEthersSigner(options.signer);
},
/**
* Converts a Thirdweb wallet to an ethers.js signer.
* @param client - The thirdweb client.
* @param account - The account.
* @param chain - The chain.
* @param options - The options for converting the Thirdweb wallet to an ethers.js signer.
* @param options.client - The thirdweb client.
* @param options.account - The account.
* @param options.chain - The chain.
* @returns A promise that resolves to an ethers.js signer.
* @example
* ```ts
* import { ethers6Adapter } from "thirdweb/adapters/ethers6";
* const signer = await ethers6Adapter.signer.toEthers(client, chain, account);
* const signer = await ethers6Adapter.signer.toEthers({ client, chain, account });
* ```
*/
toEthers: (client: ThirdwebClient, account: Account, chain: Chain) => {
toEthers: (options: {
client: ThirdwebClient;
account: Account;
chain: Chain;
}) => {
assertEthers6(ethers);
return toEthersSigner(ethers, client, account, chain);
return toEthersSigner(
ethers,
options.client,
options.account,
options.chain,
);
},
},
};
@@ -265,7 +280,7 @@ async function fromEthersSigner(signer: ethers6.Signer): Promise<Account> {
* @returns A promise that resolves to an ethers.js signer.
* @internal
*/
export async function toEthersSigner(
async function toEthersSigner(
ethers: Ethers6,
client: ThirdwebClient,
account: Account,
@@ -292,25 +307,30 @@ export async function toEthersSigner(
}
// eslint-disable-next-line jsdoc/require-jsdoc
override async sendTransaction(
tx: ethers6.ethers.TransactionRequest & { chainId: number },
tx: ethers6.ethers.TransactionRequest,
): Promise<ethers6.ethers.TransactionResponse> {
const alignedTx = await alignTxFromEthers(tx);
if (!account) {
throw new Error("Account not found");
}
const result = await account.sendTransaction({
...alignedTx,
chainId: tx.chainId,
const ethersTx = await alignTxFromEthers({
chain,
client,
tx,
});
const serializableTx = await toSerializableTransaction({
transaction: ethersTx,
from: account.address,
});
const result = await account.sendTransaction(serializableTx);
const txResponseParams: ethers6.TransactionResponseParams = {
...alignedTx,
...serializableTx,
blockHash: null,
from: this.address,
hash: result.transactionHash as string,
blockNumber: null,
index: 0,
gasLimit: alignedTx.gas as bigint,
gasLimit: serializableTx.gas as bigint,
// @ts-expect-error - we don't have this reliably so we'll just not include it
signature: null,
};
@@ -327,9 +347,16 @@ export async function toEthersSigner(
if (!account.signTransaction) {
throw new Error("Account does not support signing transactions");
}
const viemTx = await alignTxFromEthers(tx);
return account.signTransaction(viemTx);
const ethersTx = await alignTxFromEthers({
chain,
client,
tx,
});
const serializableTx = await toSerializableTransaction({
transaction: ethersTx,
from: account.address,
});
return account.signTransaction(serializableTx);
}
// eslint-disable-next-line jsdoc/require-jsdoc
override signMessage(message: string | Uint8Array): Promise<string> {
@@ -410,9 +437,12 @@ function alignTxToEthers(
return { ...rest, type };
}
async function alignTxFromEthers(
tx: ethers6.TransactionRequest,
): Promise<TransactionSerializable> {
async function alignTxFromEthers(options: {
client: ThirdwebClient;
chain: Chain;
tx: ethers6.TransactionRequest;
}): Promise<PreparedTransaction> {
const { client, chain, tx } = options;
const {
type: ethersType,
accessList,
@@ -440,11 +470,10 @@ async function alignTxFromEthers(
throw new Error("ChainId is required for EIP-2930 transactions");
}
return {
type: "eip2930",
chainId,
client,
chain,
accessList: accessList as AccessList,
to,
to: (to ?? undefined) as string | undefined,
data: (data ?? undefined) as Hex | undefined,
gasPrice: gasPrice ? bigNumberIshToBigint(gasPrice) : undefined,
gas: gasLimit ? bigNumberIshToBigint(gasLimit) : undefined,
@@ -457,10 +486,10 @@ async function alignTxFromEthers(
throw new Error("ChainId is required for EIP-1559 transactions");
}
return {
type: "eip1559",
chainId,
client,
chain,
accessList: accessList as AccessList,
to,
to: (to ?? undefined) as string | undefined,
data: (data ?? undefined) as Hex | undefined,
gas: gasLimit ? bigNumberIshToBigint(gasLimit) : undefined,
nonce: nonce ?? undefined,
@@ -477,9 +506,9 @@ async function alignTxFromEthers(
default: {
// fall back to legacy
return {
type: "legacy",
chainId,
to,
client,
chain,
to: (to ?? undefined) as string | undefined,
data: (data ?? undefined) as Hex | undefined,
nonce: nonce ?? undefined,
value: value ? bigNumberIshToBigint(value) : undefined,
@@ -7,6 +7,7 @@ import { zeroAddress } from "viem";
import { typedData } from "~test/typed-data.js";
import { ANVIL_PKEY_A } from "~test/test-wallets.js";
import { ANVIL_CHAIN } from "../../test/src/chains.js";
import { mainnet } from "../chains/chain-definitions/ethereum.js";
const account = privateKeyAccount({
privateKey: ANVIL_PKEY_A,
@@ -62,4 +63,16 @@ describe("walletClient.toViem", () => {
expect(txHash).toBeDefined();
expect(txHash.slice(0, 2)).toBe("0x");
});
test("should get address on live chain", async () => {
walletClient = viemAdapter.walletClient.toViem({
client: TEST_CLIENT,
account,
chain: mainnet,
});
const address = await walletClient.getAddresses();
expect(address[0]).toBeDefined();
expect(address[0]).toBe(account.address);
});
});
+9 -6
View File
@@ -46,7 +46,7 @@ export const viemAdapter = {
* @example
* ```ts
* import { viemAdapter } from "thirdweb/adapters";
* const viemContract = await viemAdapter.contract.toViem(contract);
* const viemContract = await viemAdapter.contract.toViem({ thirdwebContract });
* ```
*/
toViem: toViemContract,
@@ -121,12 +121,12 @@ function fromViemContract<const TAbi extends Abi>(
});
}
async function toViemContract<const TAbi extends Abi>(
contract: ThirdwebContract<TAbi>,
): Promise<GetContractReturnType<TAbi>> {
async function toViemContract<const TAbi extends Abi>(options: {
thirdwebContract: ThirdwebContract<TAbi>;
}): Promise<GetContractReturnType<TAbi>> {
return {
address: contract.address,
abi: await resolveContractAbi(contract),
address: options.thirdwebContract.address,
abi: await resolveContractAbi(options.thirdwebContract),
};
}
@@ -225,6 +225,9 @@ function toViemWalletClient(options: ToViemWalletClientOptions) {
const data = JSON.parse(request.params[1]);
return account.signTypedData(data);
}
if (request.method === "eth_accounts") {
return [account.address];
}
return rpcClient(request);
},
});
@@ -57,9 +57,7 @@ describe.runIf(process.env.TW_SECRET_KEY)("deployFromMetadata", () => {
transaction,
account: TEST_ACCOUNT_A,
});
expect(hash.transactionHash).toBe(
"0xca716193f5448ec52dafef9451ee5afabc8770a5303195a3977a94705d8101d1",
);
expect(hash.transactionHash).toBeDefined();
});
it("should deploy published contract with no existing infra", async () => {
@@ -117,8 +115,6 @@ describe.runIf(process.env.TW_SECRET_KEY)("deployFromMetadata", () => {
transaction,
account: TEST_ACCOUNT_A,
});
expect(hash.transactionHash).toBe(
"0x531b94f7554b7c7ac5d72db3583e6997559ffa2acdc0d9afea1002c15db0632b",
);
expect(hash.transactionHash).toBeDefined();
});
});
@@ -16,8 +16,8 @@ export {
} from "../react/core/hooks/wallets/wallet-hooks.js";
// contract related
export { useReadContract } from "../react/core/hooks/contract/useRead.js";
export { useSendTransaction } from "../react/core/hooks/contract/useSend.js";
export { useReadContract } from "../react/core/hooks/contract/useReadContract.js";
export { useSendTransaction } from "../react/core/hooks/contract/useSendTransaction.js";
export { useEstimateGas } from "../react/core/hooks/contract/useEstimateGas.js";
export { useWaitForReceipt } from "../react/core/hooks/contract/useWaitForReceipt.js";
export { useContractEvents } from "../react/core/hooks/contract/useContractEvents.js";
+3 -2
View File
@@ -51,8 +51,9 @@ export {
} from "../react/core/hooks/wallets/wallet-hooks.js";
// contract related
export { useReadContract } from "../react/core/hooks/contract/useRead.js";
export { useSendTransaction } from "../react/core/hooks/contract/useSend.js";
export { useReadContract } from "../react/core/hooks/contract/useReadContract.js";
export { useSendTransaction } from "../react/core/hooks/contract/useSendTransaction.js";
export { useSendAndConfirmTransaction } from "../react/core/hooks/contract/useSendAndConfirmTransaction.js";
export { useEstimateGas } from "../react/core/hooks/contract/useEstimateGas.js";
export { useEstimateGasCost } from "../react/core/hooks/contract/useEstimateGasCost.js";
export { useWaitForReceipt } from "../react/core/hooks/contract/useWaitForReceipt.js";
@@ -20,7 +20,7 @@ describe.runIf(process.env.TW_SECRET_KEY)("deployERC1155", () => {
symbol: "NFTD",
},
});
expect(address).toBe("0xd91A47278829a0128D7212225FE74BC153A7FAF8");
expect(address).toBeDefined();
const deployedName = await name({
contract: getContract({
client: TEST_CLIENT,
@@ -41,7 +41,7 @@ describe.runIf(process.env.TW_SECRET_KEY)("deployERC1155", () => {
name: "Edition",
},
});
expect(address).toBe("0x7dD915A335Af52698bFFFE14D1D3F0DCfdC0a8E6");
expect(address).toBeDefined();
const deployedName = await name({
contract: getContract({
client: TEST_CLIENT,
@@ -20,7 +20,7 @@ describe.runIf(process.env.TW_SECRET_KEY)("deployERC20", () => {
symbol: "NFTD",
},
});
expect(address).toBe("0x61Ae22E7240C7e5853749AF49f2552CB8D7C3e35");
expect(address).toBeDefined();
const deployedName = await name({
contract: getContract({
client: TEST_CLIENT,
@@ -41,7 +41,7 @@ describe.runIf(process.env.TW_SECRET_KEY)("deployERC20", () => {
name: "Token",
},
});
expect(address).toBe("0x3E8437C96275E9873b0379c1e5d5F0998A9546e9");
expect(address).toBeDefined();
const deployedName = await name({
contract: getContract({
client: TEST_CLIENT,
@@ -19,7 +19,7 @@ describe.runIf(process.env.TW_SECRET_KEY)("deployERC721", () => {
name: "NFTDrop",
},
});
expect(address).toBe("0x6AA2E0148a57EcDdb025C856c4e68682CFfcac78");
expect(address).toBeDefined();
const deployedName = await name({
contract: getContract({
client: TEST_CLIENT,
@@ -40,7 +40,7 @@ describe.runIf(process.env.TW_SECRET_KEY)("deployERC721", () => {
name: "NFTCollection",
},
});
expect(address).toBe("0x349D9e8751C40Be121a862FaC1Dc7c357281846E");
expect(address).toBeDefined();
const deployedName = await name({
contract: getContract({
client: TEST_CLIENT,
@@ -61,7 +61,7 @@ describe.runIf(process.env.TW_SECRET_KEY)("deployERC721", () => {
name: "OE",
},
});
expect(address).toBe("0x5804ebCE1834B8F57D31f0078B8f7Dd1F1Da4985");
expect(address).toBeDefined();
const deployedName = await name({
contract: getContract({
client: TEST_CLIENT,
@@ -0,0 +1,38 @@
import { useMutation, type UseMutationResult } from "@tanstack/react-query";
import { useActiveAccount } from "../wallets/wallet-hooks.js";
import type { PreparedTransaction } from "../../../../transaction/prepare-transaction.js";
import type { TransactionReceipt } from "../../../../transaction/types.js";
import { sendAndConfirmTransaction } from "../../../../transaction/actions/send-and-confirm-transaction.js";
/**
* A hook to send a transaction.
* @returns A mutation object to send a transaction.
* @example
* ```jsx
* import { useSendAndConfirmTransaction } from "thirdweb/react";
* const { mutate: sendAndConfirmTx, data: transactionReceipt } = useSendAndConfirmTransaction();
*
* // later
* sendAndConfirmTx(tx);
* ```
* @transaction
*/
export function useSendAndConfirmTransaction(): UseMutationResult<
TransactionReceipt,
Error,
PreparedTransaction
> {
const account = useActiveAccount();
return useMutation({
mutationFn: async (transaction) => {
if (!account) {
throw new Error("No active account");
}
return await sendAndConfirmTransaction({
transaction,
account,
});
},
});
}
@@ -10,10 +10,10 @@ import type { PreparedTransaction } from "../../../../transaction/prepare-transa
* @example
* ```jsx
* import { useSendTransaction } from "thirdweb/react";
* const { mutate: sendTx, data: transactionHash } = useSendTransaction();
* const { mutate: sendTx, data: transactionResult } = useSendTransaction();
*
* // later
* const transactionHash = await sendTx(tx);
* sendTx(tx);
* ```
* @transaction
*/
@@ -70,13 +70,13 @@ export function useActiveWalletChain() {
}
/**
* A hook that returns all connected accounts
* @returns An array of all connected accounts
* A hook that returns all connected wallets
* @returns An array of all connected wallets
* @example
* ```jsx
* import { useConnectedAccounts } from "thirdweb/react";
* import { useConnectedWallets } from "thirdweb/react";
*
* const accounts = useConnectedAccounts();
* const wallets = useConnectedWallets();
* ```
* @walletConnection
*/
@@ -31,6 +31,7 @@ export function ThirdwebProvider(props: React.PropsWithChildren) {
defaultOptions: {
mutations: {
onSettled: (data, error, variables) => {
console.log("Mutation settled", data, error, variables);
if (error) {
// TODO: remove - but useful for debug now
console.error("[Mutation Error]", error);
@@ -50,14 +51,14 @@ export function ThirdwebProvider(props: React.PropsWithChildren) {
// invalidate any readContract queries for this chainId:contractAddress
[
"readContract",
variables.contract.chain.id,
variables.contract.address,
variables.__contract?.chain.id,
variables.__contract?.address,
] as const,
// invalidate any walletBalance queries for this chainId
// TODO: add wallet address in here if we can get it somehow
[
"walletBalance",
variables.contract.chain.id,
variables.__contract?.chain.id,
] as const,
],
});
@@ -7,7 +7,7 @@ import { useState } from "react";
import type { Chain } from "../../../../../../../chains/types.js";
import type { BuyWithCryptoQuote } from "../../../../../../../pay/buyWithCrypto/actions/getQuote.js";
import type { Account } from "../../../../../../../wallets/interfaces/wallet.js";
import { useSendTransaction } from "../../../../../../core/hooks/contract/useSend.js";
import { useSendTransaction } from "../../../../../../core/hooks/contract/useSendTransaction.js";
import { useChainQuery } from "../../../../../../core/hooks/others/useChainQuery.js";
import {
useBuyWithCryptoStatus,
@@ -8,7 +8,7 @@ import {
useActiveAccount,
useActiveWallet,
} from "../../../core/hooks/wallets/wallet-hooks.js";
import { useSendTransaction } from "../../../core/hooks/contract/useSend.js";
import { useSendTransaction } from "../../../core/hooks/contract/useSendTransaction.js";
import type { PreparedTransaction } from "../../../../transaction/prepare-transaction.js";
import type { TransactionReceipt } from "../../../../transaction/types.js";
import { useState } from "react";
@@ -1,5 +1,5 @@
import { useMutation } from "@tanstack/react-query";
import { useSendTransaction } from "../../../core/hooks/contract/useSend.js";
import { useSendTransaction } from "../../../core/hooks/contract/useSendTransaction.js";
import { useActiveWalletChain } from "../../../core/hooks/wallets/wallet-hooks.js";
import { toWei } from "../../../../utils/units.js";
import { getContract } from "../../../../contract/contract.js";
+3 -1
View File
@@ -73,7 +73,9 @@ export async function fetchRpc(
if (!response.ok) {
response.body?.cancel();
throw new Error(`RPC request failed with status ${response.status}`);
throw new Error(
`RPC request failed with status ${response.status} - ${response.statusText}`,
);
}
let result;
+5 -4
View File
@@ -10,6 +10,7 @@ import type { ThirdwebContract } from "../contract/contract.js";
import { isObjectWithKeys } from "../utils/type-guards.js";
import type { Hex } from "../utils/encoding/hex.js";
import type { TransactionReceipt as ViemTransactionReceipt } from "viem";
import type { PreparedTransaction } from "./prepare-transaction.js";
export type SendTransactionResult = {
readonly transactionHash: Hex;
@@ -44,11 +45,11 @@ export type BaseTransactionOptions<
*/
export function isBaseTransactionOptions(
value: unknown,
): value is BaseTransactionOptions {
): value is PreparedTransaction {
return (
isObjectWithKeys(value, ["contract"]) &&
isObjectWithKeys(value.contract, ["address", "chain"]) &&
typeof value.contract.address === "string"
isObjectWithKeys(value, ["__contract"]) &&
isObjectWithKeys(value.__contract, ["address", "chain"]) &&
typeof value.__contract.address === "string"
);
}
@@ -212,15 +212,12 @@ function onConnect(
},
};
function disconnect() {
if (!provider) {
return;
}
provider.disconnect();
provider.close();
async function disconnect() {
provider.removeListener("accountsChanged", onAccountsChanged);
provider.removeListener("chainChanged", onChainChanged);
provider.removeListener("disconnect", onDisconnect);
provider.disconnect();
await provider.close();
}
function onDisconnect() {
@@ -235,6 +232,7 @@ function onConnect(
address: getAddress(accounts[0]),
};
emitter.emit("accountChanged", newAccount);
emitter.emit("accountsChanged", accounts);
} else {
onDisconnect();
}
+22 -24
View File
@@ -76,10 +76,15 @@ export function createWallet<const ID extends WalletId>(
chain = newChain;
});
const unsubscribeDisconnect = emitter.subscribe("disconnect", () => {
function reset() {
account = undefined;
chain = undefined;
// unsubscribe
}
let handleDisconnect = async () => {};
const unsubscribeDisconnect = emitter.subscribe("disconnect", () => {
reset();
unsubscribeChain();
unsubscribeDisconnect();
});
@@ -91,10 +96,6 @@ export function createWallet<const ID extends WalletId>(
let handleSwitchChain: (chain: Chain) => Promise<void> = async () => {
throw new Error("Not implemented yet");
};
let handleDisconnect: () => void = () => {
account = undefined;
chain = undefined;
};
const wallet: Wallet<ID> = {
id,
@@ -177,11 +178,7 @@ export function createWallet<const ID extends WalletId>(
// set the states
account = connectedAccount;
chain = connectedChain;
handleDisconnect = () => {
doDisconnect();
account = undefined;
chain = undefined;
};
handleDisconnect = doDisconnect;
handleSwitchChain = doSwitchChain;
trackConnect({
client: wcOptions.client,
@@ -226,11 +223,7 @@ export function createWallet<const ID extends WalletId>(
// set the states
account = connectedAccount;
chain = connectedChain;
handleDisconnect = () => {
doDisconnect();
account = undefined;
chain = undefined;
};
handleDisconnect = doDisconnect;
handleSwitchChain = doSwitchChain;
trackConnect({
client: options.client,
@@ -243,7 +236,10 @@ export function createWallet<const ID extends WalletId>(
throw new Error("Failed to connect");
},
// these get overridden in connect and autoConnect
disconnect: async () => handleDisconnect(),
disconnect: async () => {
reset();
await handleDisconnect();
},
switchChain: (c) => handleSwitchChain(c),
};
return wallet;
@@ -341,11 +337,11 @@ export function smartWallet(
return account;
},
disconnect: async () => {
const { disconnectSmartWallet } = await import("./smart/index.js");
await disconnectSmartWallet(_smartWallet);
account = undefined;
chain = undefined;
emitter.emit("disconnect", undefined);
const { disconnectSmartWallet } = await import("./smart/index.js");
await disconnectSmartWallet(_smartWallet);
},
switchChain: async () => {
throw new Error("Not implemented yet");
@@ -444,10 +440,12 @@ function coinbaseWalletSDK(): Wallet<"com.coinbase.wallet"> {
let account: Account | undefined = undefined;
let chain: Chain | undefined = undefined;
let handleDisconnect: () => void = () => {
function reset() {
account = undefined;
chain = undefined;
};
}
let handleDisconnect = async () => {};
let handleSwitchChain = async (newChain: Chain) => {
chain = newChain;
@@ -461,8 +459,7 @@ function coinbaseWalletSDK(): Wallet<"com.coinbase.wallet"> {
);
const unsubscribeDisconnect = emitter.subscribe("disconnect", () => {
handleDisconnect();
// unsubscribe
reset();
unsubscribeChainChanged();
unsubscribeDisconnect();
});
@@ -517,7 +514,8 @@ function coinbaseWalletSDK(): Wallet<"com.coinbase.wallet"> {
return account;
},
disconnect: async () => {
handleDisconnect();
reset();
await handleDisconnect();
},
switchChain: async (newChain) => {
await handleSwitchChain(newChain);
@@ -185,10 +185,7 @@ async function onConnect(
},
};
function disconnect() {
if (!provider || !provider.removeListener) {
return;
}
async function disconnect() {
provider.removeListener("accountsChanged", onAccountsChanged);
provider.removeListener("chainChanged", onChainChanged);
provider.removeListener("disconnect", onDisconnect);
@@ -207,6 +204,7 @@ async function onConnect(
};
emitter.emit("accountChanged", newAccount);
emitter.emit("accountsChanged", accounts);
} else {
onDisconnect();
}
+1 -1
View File
@@ -19,5 +19,5 @@ export type AppMetadata = {
logoUrl?: string;
};
export type DisconnectFn = () => void;
export type DisconnectFn = () => Promise<void>;
export type SwitchChainFn = (chain: Chain) => Promise<void>;
@@ -52,7 +52,6 @@ const defaultWCProjectId = "08c4b07e3ad25f1a27c14a4e8cecb6f0";
const NAMESPACE = "eip155";
const ADD_ETH_CHAIN_METHOD = "wallet_addEthereumChain";
const isNewChainsStale = true;
const defaultShowQrModal = true;
const storageKeys = {
@@ -69,12 +68,6 @@ export async function connectWC(
walletId: WCSupportedWalletIds | "walletConnect",
): Promise<ReturnType<typeof onConnect>> {
const provider = await initProvider(options, walletId);
const _isChainsState = await isChainsStale(provider, [
provider.chainId,
...(options?.walletConnect?.optionalChains || []).map((c) => c.id),
]);
const wcOptions = options.walletConnect;
const { onDisplayUri } = wcOptions || {};
@@ -91,8 +84,7 @@ export async function connectWC(
optionalChains: options.walletConnect?.optionalChains,
});
// If there no active session, or the chain is stale, force connect.
if (!provider.session || _isChainsState) {
if (provider.session) {
await provider.connect({
...(wcOptions?.pairingTopic
? { pairingTopic: wcOptions?.pairingTopic }
@@ -100,10 +92,9 @@ export async function connectWC(
optionalChains: chainsToRequest,
rpcMap: rpcMap,
});
setRequestedChainsIds(chainsToRequest);
}
setRequestedChainsIds(chainsToRequest);
// If session exists and chains are authorized, enable provider for required chain
const addresses = await provider.enable();
const address = addresses[0];
@@ -174,23 +165,6 @@ export async function autoConnectWC(
return onConnect(address, chain, provider, emitter);
}
// /**
// * @internal
// */
// export async function disconnectWC(wallet: Wallet<WCSupportedWalletIds>) {
// const provider = walletToProviderMap.get(wallet);
// // const storage = getWalletData(wallet)?.storage;
// onDisconnect(wallet);
// // if (storage) {
// // deleteConnectParamsFromStorage(storage, wallet.id);
// // }
// if (provider) {
// provider.disconnect();
// }
// }
// Connection utils -----------------------------------------------------------------------------------------------
async function initProvider(
@@ -238,9 +212,9 @@ async function initProvider(
// disconnect the provider if chains are stale when (if not auto connecting)
if (!isAutoConnect) {
const isStale = await isChainsStale(provider, chainsToRequest);
// const isStale = await isChainsStale(provider, chainsToRequest);
if (isStale && provider.session) {
if (provider.session) {
await provider.disconnect();
}
}
@@ -341,14 +315,11 @@ function onConnect(
},
};
function disconnect() {
if (!provider) {
return;
}
provider.disconnect();
async function disconnect() {
provider.removeListener("accountsChanged", onAccountsChanged);
provider.removeListener("chainChanged", onChainChanged);
provider.removeListener("disconnect", onDisconnect);
await provider.disconnect();
}
function onDisconnect() {
@@ -365,6 +336,7 @@ function onConnect(
address: getAddress(accounts[0]),
};
emitter.emit("accountChanged", newAccount);
emitter.emit("accountsChanged", accounts);
} else {
onDisconnect();
}
@@ -396,9 +368,6 @@ function getNamespaceMethods(provider: WCProvider) {
}
function getNamespaceChainsIds(provider: WCProvider): number[] {
if (!provider) {
return [];
}
const chainIds = provider.session?.namespaces[NAMESPACE]?.chains?.map(
(chain) => parseInt(chain.split(":")[1] || ""),
);
@@ -450,39 +419,6 @@ async function switchChainWC(provider: WCProvider, chain: Chain) {
}
}
/**
* if every chain requested were already requested earlier - then they are not stale
* @param connectToChainId
* @internal
*/
async function isChainsStale(provider: WCProvider, chains: number[]) {
const namespaceMethods = getNamespaceMethods(provider);
// if chain adding method is available, then chains are not stale
if (namespaceMethods.includes(ADD_ETH_CHAIN_METHOD)) {
return false;
}
// if new chains are considered stale, then return true
if (!isNewChainsStale) {
return false;
}
const requestedChains = await getRequestedChainsIds();
const namespaceChains = getNamespaceChainsIds(provider);
// if any of the requested chains are not in the namespace chains, then they are stale
if (
namespaceChains.length &&
!namespaceChains.some((id) => chains.includes(id))
) {
return false;
}
// if chain was requested earlier, then they are not stale
return !chains.every((id) => requestedChains.includes(id));
}
/**
* Set the requested chains to the storage.
* @internal
@@ -5,6 +5,7 @@ import type { WalletAutoConnectionOption, WalletId } from "./wallet-types.js";
export type WalletEmitterEvents<TWalletId extends WalletId> = {
accountChanged: Account;
accountsChanged: string[];
disconnect?: never;
chainChanged: Chain;
onConnect: WalletAutoConnectionOption<TWalletId>;
Binary file not shown.
+10
View File
@@ -1,5 +1,15 @@
# @thirdweb-dev/unity-js-bridge
## 0.6.6
### Patch Changes
- Updated dependencies [[`b3fca95`](https://github.com/thirdweb-dev/js/commit/b3fca9509feb0ac6e0ded816f08570b2954f6521)]:
- @thirdweb-dev/chains@0.1.88
- @thirdweb-dev/sdk@4.0.57
- @thirdweb-dev/wallets@2.4.33
- @thirdweb-dev/auth@4.1.55
## 0.6.5
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/unity-js-bridge",
"version": "0.6.5",
"version": "0.6.6",
"main": "dist/thirdweb-unity-bridge.js",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/unity-js-bridge",
"license": "Apache-2.0",