Compare commits

..
Author SHA1 Message Date
Jonas DanielsGitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>GitHub Action
c1e155d04f Version Packages (#3172)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: GitHub Action <[email protected]>
2024-06-01 07:14:56 +12:00
gregandGitHub 91e658035d Add forked chains explainer to contributing guide (#3189) 2024-05-31 07:51:51 +00:00
gregandGitHub 8491675e2e Fix AutoConnect on MIPD wallets (#3190) 2024-05-31 19:50:38 +12:00
Joaquim VergesandGitHub 1b2edb4c09 show connect button if disconnected in pay playground (#3188) 2024-05-31 16:12:10 +12:00
Joaquim VergesandGitHub 874747b3e0 chore: update cb SDK (#3187) 2024-05-31 14:30:07 +12:00
FirekeeperandGitHub 01f883f637 Unity 4.14.1 (#3185) 2024-05-31 00:06:09 +00:00
gregandGitHub 123275bbe2 Catch any rogue poller errors in watchBlockNumber (#3186) 2024-05-30 17:05:52 -07:00
Manan TankandGitHub 7bb241f7db Improved OTP input in v4 SDK using input-otp lib (#3183) 2024-05-30 15:34:20 +00:00
Jonas DanielsandGitHub a1f53a2b9e refactor: Improve CI workflow configuration and setup (#3182) 2024-05-30 08:46:42 +00:00
gregandGitHub 46e9072576 Adds predefined hardhat chain (#3176) 2024-05-30 02:48:31 +00:00
501ef9339d fix: peerDependency version of react-native-quick-crypto (#3174)
Signed-off-by: Kacper <[email protected]>
Co-authored-by: Joaquim Verges <[email protected]>
2024-05-30 13:52:26 +12:00
Joaquim VergesandGitHub 3dca028a7e fix: transaction button gas estimation for pay (#3178) 2024-05-30 00:31:40 +00:00
Edward SunandGitHub fd777c71c2 Upgrade dependencies for legacy_packages/wallets, add new AuthProviders (#3175) 2024-05-29 21:42:53 +00:00
Joaquim VergesandGitHub fbec24e260 chore: add tsdoc tags (#3177) 2024-05-30 09:22:45 +12:00
bbf65acc80 Add some basic tests for React (#3165)
Co-authored-by: greg <[email protected]>
2024-05-29 20:46:08 +00:00
gregandGitHub b569eb48ad Adds EIP-5792 hooks and waitForBundle fn (#3161) 2024-05-29 00:00:29 +00:00
gregandGitHub b6b0eb9120 Improve connect wallet copy (#3171) 2024-05-28 23:37:51 +00:00
FirekeeperandGitHub 7cfe6745e8 Unity 4.14.0 (#3170) 2024-05-28 23:18:20 +00:00
84 changed files with 1194 additions and 326 deletions
+4
View File
@@ -73,6 +73,10 @@ pnpm test:dev <YOUR TEST FILE PATH>
> Specifying your test file path is optional, but will save time by only running specific tests each time. Before opening your PR, run `pnpm test` from the monorepo root (without specifying your test file) to ensure your changes didn't break any existing tests.
Many of the tests use forked versions of live chains like mainnet. We fork these chains at a specific arbitrary block number so results are consistent across test runs. If you're interacting with on-chain data, you can write tests that interact with real contracts at the same block number by using `FORKED_ETHEREUM_CHAIN`. However, if you don't need to interact with existing contracts, we recommend running your tests against `ANVIL_CHAIN`.
If you need to use accounts in your tests, use the predefined accounts in `test/src/test-wallets.ts`. These are the default anvil accounts that are pre-funded on the local test forks.
#### Linting
We use a linter to maintain best practices across projects. Once your changes are complete (or periodically while making changes), run the linter with the following command from the repo root:
+56 -1
View File
@@ -90,6 +90,10 @@ jobs:
timeout-minutes: 15
name: E2E Tests
runs-on: ubuntu-latest
strategy:
matrix:
package_manager: [npm, yarn, pnpm, bun]
bundler: [vite, webpack, esbuild]
steps:
- name: Check out the code
uses: actions/checkout@v4
@@ -97,7 +101,58 @@ jobs:
- name: Setup & Install
uses: ./.github/composite-actions/install
# TODO actually run e2e tests
- name: Build Packages
run: pnpm build:packages
- name: Install Yarn (if needed)
if: matrix.package_manager == 'yarn'
run: npm install -g yarn
- name: Create test project
run: |
mkdir test-project
cd test-project
npm init -y
${{ matrix.package_manager }} add react react-dom ../packages/thirdweb
- name: Create test file
run: |
cd test-project
echo "import { createThirdwebClient } from 'thirdweb'; console.log(createThirdwebClient({clientId: "foo_bar_baz"}));" > index.js
- name: Bundle with vite
if: matrix.bundler == 'vite'
run: |
cd test-project
${{matrix.package_manager}} add vite
echo 'import { defineConfig } from "vite"; import {resolve} from "path"; export default defineConfig({ build: { lib: { entry: resolve(__dirname, "index.js"), name: "e2e_test" }, outDir: "dist" }});' > vite.config.js
npx vite build
- name: Bundle with webpack
if: matrix.bundler == 'webpack'
run: |
cd test-project
${{matrix.package_manager}} add webpack webpack-cli
echo 'const path = require("path"); module.exports = { mode: "production", entry: "./index.js", output: { path: path.resolve(__dirname, "dist"), filename: "bundle.js" }};' > webpack.config.js
npx webpack
- name: Bundle with esbuild
if: matrix.bundler == 'esbuild'
run: |
cd test-project
${{matrix.package_manager}} add esbuild
npx esbuild index.js --bundle --outdir=dist
- name: Verify bundle
run: |
cd test-project/dist
file_count=$(find . -type f | wc -l)
if [ "$file_count" -gt 0 ]; then
echo "Bundling successful"
else
echo "Bundling failed"
exit 1
fi
benchmark:
# cannot run benchmarks on merge group
@@ -3,6 +3,8 @@ import { Button } from "@/components/ui/button";
import { metadataBase } from "@/lib/constants";
import type { Metadata } from "next";
import Link from "next/link";
import { CodeExample } from "../../../components/code/code-example";
import { StyledPayTransaction } from "../../../components/styled-pay-transaction";
export const metadata: Metadata = {
metadataBase,
@@ -55,6 +57,46 @@ export default function Page() {
</div>
</div>
</section>
<section className="container px-4 md:px-6 space-y-8">
<div className="space-y-2">
<h2 className="text-4xl font-semibold tracking-tight">
Transaction Button
</h2>
<p className="max-w-[600px]">
Transaction Button is a handy component that handles transactions.
<br />
If your user doesn&apos;t have enough funds for that transaction, a
pre-filled pay modal will appear with the exact amount needed.
</p>
</div>
<CodeExample
preview={<StyledPayTransaction />}
code={`import { TransactionButton } from "thirdweb/react";
function App() {
const account = useActiveAccount();
return (
<TransactionButton
transaction={() => {
// any transaction works
return claimTo({
contract,
quantity: 1n,
tokenId: 0n,
to: account?.address,
});
}}
>
Buy for 10 MATIC
</TransactionButton>
);
};`}
lang="tsx"
/>
</section>
</main>
);
}
@@ -0,0 +1,41 @@
"use client";
import { THIRDWEB_CLIENT } from "@/lib/client";
import { useTheme } from "next-themes";
import { getContract } from "thirdweb";
import { polygon } from "thirdweb/chains";
import { claimTo } from "thirdweb/extensions/erc1155";
import { TransactionButton, useActiveAccount } from "thirdweb/react";
import { StyledConnectButton } from "./styled-connect-button";
const contract = getContract({
address: "0x96B30d36f783c7BC68535De23147e2ce65788e93",
chain: polygon,
client: THIRDWEB_CLIENT,
});
export function StyledPayTransaction() {
const account = useActiveAccount();
const { theme } = useTheme();
return account ? (
<TransactionButton
transaction={() => {
if (!account) throw new Error("No active account");
return claimTo({
contract,
quantity: 1n,
tokenId: 0n,
to: account?.address,
});
}}
payModal={{
theme: theme === "light" ? "light" : "dark",
}}
>
Buy for 10 MATIC
</TransactionButton>
) : (
<StyledConnectButton />
);
}
+5 -18
View File
@@ -1,10 +1,6 @@
{
"compilerOptions": {
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
@@ -22,19 +18,10 @@
}
],
"paths": {
"@/*": [
"./src/*"
]
"@/*": ["./src/*"]
},
"target": "ES2017"
"target": "ES2020"
},
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts"
],
"exclude": [
"node_modules"
]
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}
+7
View File
@@ -1,5 +1,12 @@
# @thirdweb-dev/auth
## 4.1.88
### Patch Changes
- Updated dependencies []:
- @thirdweb-dev/wallets@2.5.30
## 4.1.87
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/auth",
"version": "4.1.87",
"version": "4.1.88",
"main": "dist/thirdweb-dev-auth.cjs.js",
"module": "dist/thirdweb-dev-auth.esm.js",
"browser": {
+9
View File
@@ -1,5 +1,14 @@
# thirdweb
## 0.14.3
### Patch Changes
- Updated dependencies []:
- @thirdweb-dev/sdk@4.0.90
- @thirdweb-dev/wallets@2.5.30
- @thirdweb-dev/auth@4.1.88
## 0.14.2
### Patch Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@thirdweb-dev/cli",
"main": "dist/cli/index.js",
"version": "0.14.2",
"version": "0.14.3",
"repository": "https://github.com/thirdweb-dev/js/tree/main/legacy_packages/cli",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
+9
View File
@@ -1,5 +1,14 @@
# @thirdweb-dev/react-core
## 4.6.29
### Patch Changes
- Updated dependencies []:
- @thirdweb-dev/sdk@4.0.90
- @thirdweb-dev/wallets@2.5.30
- @thirdweb-dev/auth@4.1.88
## 4.6.28
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/react-core",
"version": "4.6.28",
"version": "4.6.29",
"repository": "https://github.com/thirdweb-dev/js/tree/main/legacy_packages/react-core",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
+11
View File
@@ -1,5 +1,16 @@
# @thirdweb-dev/react
## 4.6.29
### Patch Changes
- [#3183](https://github.com/thirdweb-dev/js/pull/3183) [`7bb241f`](https://github.com/thirdweb-dev/js/commit/7bb241f7db12e97b7eff7583548638b7ab2e5b77) Thanks [@MananTank](https://github.com/MananTank)! - Improved OTP input using input-otp library
- Updated dependencies []:
- @thirdweb-dev/sdk@4.0.90
- @thirdweb-dev/react-core@4.6.29
- @thirdweb-dev/wallets@2.5.30
## 4.6.28
### Patch Changes
+2 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/react",
"version": "4.6.28",
"version": "4.6.29",
"repository": "https://github.com/thirdweb-dev/js/tree/main/legacy_packages/react",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
@@ -122,6 +122,7 @@
"copy-to-clipboard": "^3.3.3",
"detect-browser": "^5.3.0",
"fuse.js": "^7.0.0",
"input-otp": "^1.2.4",
"qrcode": "^1.5.3",
"tiny-invariant": "^1.3.3"
},
+86 -117
View File
@@ -1,140 +1,109 @@
import { useEffect, useRef } from "react";
import { Input } from "./formElements";
import { Container } from "./basic";
import { media, fontSize, spacing } from "../design-system";
import styled from "@emotion/styled";
"use client";
import { keyframes } from "@emotion/react";
import { OTPInput as InputOTP, type SlotProps } from "input-otp";
import { fontSize, spacing, radius } from "../design-system";
import { useCustomTheme } from "../design-system/CustomThemeProvider";
import { StyledDiv } from "../design-system/elements";
import { Container } from "./basic";
/**
* @internal
*/
export function OTPInput(props: {
digits: number;
isInvalid?: boolean;
value: string;
setValue: (value: string) => void;
onEnter?: () => void;
onEnter: () => void;
}) {
const otp = props.value.split("").map(Number);
const setOTP = (newOTP: number[]) => {
props.setValue(newOTP.join(""));
};
const inputToFocusIndex = otp.length;
const boxEls = useRef<(HTMLInputElement | null)[]>([]);
useEffect(() => {
if (boxEls.current[inputToFocusIndex]) {
requestAnimationFrame(() => {
boxEls.current[inputToFocusIndex]?.focus();
});
}
}, [inputToFocusIndex]);
return (
<Container center="x" gap="sm" flex="row">
{new Array(props.digits).fill(null).map((_, i) => {
return (
<OTPInputBox
data-error={props.isInvalid}
ref={(e) => (boxEls.current[i] = e)}
key={i}
value={otp[i] ?? ""}
type="number"
pattern="[0-9]*"
variant="outline"
inputMode="numeric"
onPaste={(e) => {
const pastedData = e.clipboardData.getData("text/plain");
const newOTP = pastedData
.slice(0, props.digits)
.split("")
.filter((n) => /\d/.test(n))
.map(Number);
setOTP(newOTP);
e.preventDefault();
}}
onKeyDown={(e) => {
if (e.key === "Enter") {
if (props.onEnter) {
props.onEnter();
return;
}
}
if (e.key === "ArrowLeft") {
if (i === 0) {
return;
}
boxEls.current[i - 1]?.focus();
return;
}
if (e.key === "ArrowRight") {
if (i === props.digits - 1) {
return;
}
boxEls.current[i + 1]?.focus();
return;
}
if (e.key === "e" || e.key === ".") {
e.preventDefault();
return;
}
if (e.key === "Backspace") {
if (i === 0) {
return;
}
const newOTP = otp.slice(0, -1);
setOTP(newOTP);
}
}}
onChange={(e) => {
const value = e.target.value;
if (value.length > 1) {
setOTP(value.split("").filter((n) => /\d/.test(n)).map(Number));
return;
}
if (!/\d/.test(value) && value !== "") {
e.preventDefault();
return;
}
const newOTP = [...otp];
const index = i > inputToFocusIndex - 1 ? inputToFocusIndex : i;
newOTP[index] = Number(value);
setOTP(newOTP);
}}
/>
);
})}
</Container>
<OTPInputContainer>
<InputOTP
onComplete={() => {
props.onEnter();
}}
maxLength={6}
value={props.value}
render={({ slots }) => (
<Container flex="row" gap="xs" center="both">
{slots.map((slot, idx) => (
<Slot key={idx} {...slot} isInvalid={props.isInvalid} />
))}
</Container>
)}
onChange={(newValue) => {
props.setValue(newValue);
}}
/>
</OTPInputContainer>
);
}
const OTPInputBox = /* @__PURE__ */ styled(Input)(() => {
const OTPInputContainer = /* @__PURE__ */ StyledDiv({
"& input": {
maxWidth: "100%",
},
});
function Slot(props: SlotProps & { isInvalid?: boolean }) {
return (
<OTPInputBox data-active={props.isActive} data-error={props.isInvalid}>
{props.char !== null && <div>{props.char}</div>}
{props.hasFakeCaret && <FakeCaret />}
</OTPInputBox>
);
}
const caretBlink = keyframes`
0%, 100% {
opacity: 0;
},
50% {
opacity: 1;
}
`;
const FakeCaret = /* @__PURE__ */StyledDiv(() => {
const theme = useCustomTheme();
return {
appearance: "none",
WebkitAppearance: "none",
position: "absolute",
pointerEvents: "none",
inset: 0,
display: "flex",
alignItems: "center",
justifyContent: "center",
animation: `${caretBlink} 1s infinite`,
"&::before": {
content: "''",
display: "block",
width: "1.5px",
height: "1em",
backgroundColor: theme.colors.primaryText,
},
};
});
const OTPInputBox = /* @__PURE__ */ StyledDiv(() => {
const theme = useCustomTheme();
return {
position: "relative",
width: "40px",
height: "40px",
textAlign: "center",
display: "flex",
alignItems: "center",
justifyContent: "center",
fontSize: fontSize.md,
padding: spacing.xs,
[media.mobile]: {
width: "35px",
height: "35px",
boxSizing: "border-box",
transition: "color 200ms ease",
border: `2px solid ${theme.colors.borderColor}`,
"&[data-active='true']": {
borderColor: theme.colors.accentText,
},
"&[data-verify-status='invalid']": {
color: theme.colors.danger,
color: theme.colors.primaryText,
borderRadius: radius.lg,
"&[data-error='true']": {
borderColor: theme.colors.danger,
},
};
@@ -313,7 +313,6 @@ export const EmbeddedWalletOTPLoginUI: React.FC<
setValue={(value) => {
setOtpInput(value);
setVerifyStatus("idle"); // reset error
verify(value);
}}
onEnter={() => {
verify(otpInput);
Binary file not shown.
+7
View File
@@ -1,5 +1,12 @@
# @thirdweb-dev/sdk
## 4.0.90
### Patch Changes
- Updated dependencies [[`3dca028`](https://github.com/thirdweb-dev/js/commit/3dca028a7eff926ae406eb29cc82016ae6c994b3), [`874747b`](https://github.com/thirdweb-dev/js/commit/874747b3e00714e9a7336dcfda34e7b92b82e7e1), [`123275b`](https://github.com/thirdweb-dev/js/commit/123275bbe275457b0be5205812ba0ef75b1f0e5b), [`b569eb4`](https://github.com/thirdweb-dev/js/commit/b569eb48ad018619e4589b9efb5aa774c7b77642), [`b569eb4`](https://github.com/thirdweb-dev/js/commit/b569eb48ad018619e4589b9efb5aa774c7b77642)]:
- thirdweb@5.26.0
## 4.0.89
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/sdk",
"version": "4.0.89",
"version": "4.0.90",
"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.
@@ -1,5 +1,14 @@
# @thirdweb-dev/unity-js-bridge
## 0.6.39
### Patch Changes
- Updated dependencies []:
- @thirdweb-dev/sdk@4.0.90
- @thirdweb-dev/wallets@2.5.30
- @thirdweb-dev/auth@4.1.88
## 0.6.38
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/unity-js-bridge",
"version": "0.6.38",
"version": "0.6.39",
"main": "dist/thirdweb-unity-bridge.js",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/unity-js-bridge",
"license": "Apache-2.0",
@@ -171,7 +171,7 @@ class ThirdwebBridge implements TWBridge {
// biome-ignore lint/suspicious/noExplicitAny: TODO: fix use of any
(globalThis as any).X_SDK_PLATFORM = "unity";
// biome-ignore lint/suspicious/noExplicitAny: TODO: fix use of any
(globalThis as any).X_SDK_VERSION = "4.13.3";
(globalThis as any).X_SDK_VERSION = "4.14.1";
// biome-ignore lint/suspicious/noExplicitAny: TODO: fix use of any
(globalThis as any).X_SDK_OS = browser?.os ?? "unknown";
}
+7
View File
@@ -1,5 +1,12 @@
# @thirdweb-dev/wallets
## 2.5.30
### Patch Changes
- Updated dependencies []:
- @thirdweb-dev/sdk@4.0.90
## 2.5.29
### Patch Changes
+5 -5
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/wallets",
"version": "2.5.29",
"version": "2.5.30",
"main": "dist/thirdweb-dev-wallets.cjs.js",
"module": "dist/thirdweb-dev-wallets.esm.js",
"browser": {
@@ -520,9 +520,9 @@
"sideEffects": false,
"dependencies": {
"@account-abstraction/contracts": "^0.5.0",
"@blocto/sdk": "0.5.5",
"@coinbase/wallet-sdk": "^3.7.2",
"@google-cloud/kms": "4.2.0",
"@blocto/sdk": "0.10.2",
"@coinbase/wallet-sdk": "^3.9.0",
"@google-cloud/kms": "^4.4.0",
"@magic-ext/connect": "^6.7.2",
"@magic-ext/oauth": "^7.6.2",
"@magic-sdk/provider": "^13.6.2",
@@ -530,7 +530,7 @@
"@paperxyz/embedded-wallet-service-sdk": "^1.2.5",
"@paperxyz/sdk-common-utilities": "^0.1.1",
"@safe-global/safe-core-sdk": "^3.3.5",
"@safe-global/safe-ethers-adapters": "0.1.0-alpha.17",
"@safe-global/safe-ethers-adapters": "0.1.0-alpha.19",
"@safe-global/safe-ethers-lib": "^1.9.4",
"@thirdweb-dev/chains": "workspace:*",
"@thirdweb-dev/contracts-js": "workspace:*",
@@ -114,7 +114,7 @@ export class BloctoConnector extends WagmiConnector<
getProvider({ chainId }: { chainId?: number } = {}): Promise<BloctoProvider> {
if (!this._provider) {
const _chainId =
chainId ?? this.options.chainId ?? this.chains[0]?.chainId ?? 1;
chainId ?? this.chains[0]?.chainId ?? 1;
const _rpc = this.chains.find((x) => x.chainId === _chainId)?.rpc[0];
this._provider = new BloctoSDK({
@@ -145,7 +145,7 @@ export class BloctoConnector extends WagmiConnector<
}
async isAuthorized(): Promise<boolean> {
return !!this._provider?._blocto?.sessionKey ?? false;
return !!this._provider?._blocto?.sessionKeyEnv ?? false;
}
async switchChain(chainId: number): Promise<Chain> {
@@ -157,8 +157,8 @@ export class BloctoConnector extends WagmiConnector<
throw new SwitchChainError(new Error("chain not found on connector."));
}
const isBloctoSupportChain =
provider._blocto.supportNetworkList[`${chainId}`];
const blocktoSupportedChainList = await provider.supportChainList();
const isBloctoSupportChain = blocktoSupportedChainList[`${chainId}`];
if (!isBloctoSupportChain) {
throw new SwitchChainError(new Error(`Blocto unsupported chain: ${id}`));
}
@@ -17,6 +17,9 @@ export enum AuthProvider {
CUSTOM_AUTH_ENDPOINT = "CustomAuthEndpoint",
FACEBOOK = "Facebook",
APPLE = "Apple",
PASSKEY = "Passkey",
EXTERNAL_WALLET = "ExternalWallet",
DISCORD = "Discord",
}
/**
-1
View File
@@ -37,7 +37,6 @@
"hotlink-init": "node ./scripts/hotlink/hotlink-init.mjs",
"hotlink-revert": "node ./scripts/hotlink/hotlink-revert.mjs"
},
"packageManager": "[email protected]",
"dependencies": {
"@changesets/changelog-github": "0.5.0",
"@changesets/cli": "2.27.1",
+2 -5
View File
@@ -23,10 +23,7 @@
},
"./package.json": "./package.json"
},
"files": [
"dist/*",
"src/*"
],
"files": ["dist/*", "src/*"],
"dependencies": {
"@aws-sdk/client-lambda": "3.577.0",
"@aws-sdk/credential-providers": "3.577.0",
@@ -43,7 +40,7 @@
"expo-application": "^5",
"expo-web-browser": "^13",
"react-native-aes-gcm-crypto": "^0.2",
"react-native-quick-crypto": ">=0.6.1",
"react-native-quick-crypto": ">=0.7.0-rc.6 || >=0.7",
"shamir-secret-sharing": "^0.0.3",
"react-native": ">=0.70",
"react-native-get-random-values": "^1"
+96
View File
@@ -1,5 +1,101 @@
# thirdweb
## 5.26.0
### Minor Changes
- [#3161](https://github.com/thirdweb-dev/js/pull/3161) [`b569eb4`](https://github.com/thirdweb-dev/js/commit/b569eb48ad018619e4589b9efb5aa774c7b77642) Thanks [@gregfromstl](https://github.com/gregfromstl)! - Adds waitForBundle function to await a sendCalls bundle's complete confirmation.
### Usage
```ts
import { waitForBundle } from "thirdweb/wallets/eip5792";
const result = await waitForBundle({
client,
chain,
wallet,
bundleId: "0x123...",
});
```
- [#3161](https://github.com/thirdweb-dev/js/pull/3161) [`b569eb4`](https://github.com/thirdweb-dev/js/commit/b569eb48ad018619e4589b9efb5aa774c7b77642) Thanks [@gregfromstl](https://github.com/gregfromstl)! - Adds EIP-5792 react hooks
## `useSendCalls`
`useSendCalls` will automatically revalidate all reads from contracts that are interacted with.
```tsx
import { useSendCalls } from "thirdweb/react";
const sendTx1 = approve({
contract: USDT_CONTRACT,
amount: 100,
spender: "0x33d9B8BEfE81027E2C859EDc84F5636cbb202Ed6",
});
const sendTx2 = approve({
contract: USDT_CONTRACT,
amount: 100,
spender: "0x2a4f24F935Eb178e3e7BA9B53A5Ee6d8407C0709",
});
const { mutate: sendCalls, data: bundleId } = useSendCalls({ client });
await sendCalls({
wallet,
client,
calls: [sendTx1, sendTx2],
});
```
Await the bundle's full confirmation:
```tsx
const { mutate: sendCalls, data: bundleId } = useSendCalls({
client,
waitForResult: true,
});
await sendCalls({
wallet,
client,
calls: [sendTx1, sendTx2],
});
```
Sponsor transactions with a paymaster:
```ts
const { mutate: sendCalls, data: bundleId } = useSendCalls();
await sendCalls({
client,
calls: [sendTx1, sendTx2],
capabilities: {
paymasterService: {
url: `https://${CHAIN.id}.bundler.thirdweb.com/${client.clientId}`,
},
},
});
```
## `useCapabilities`
```tsx
import { useCapabilities } from "thirdweb/react";
const { data: capabilities, isLoading } = useCapabilities();
```
## `useCallsStatus`
```tsx
import { useCallsStatus } from "thirdweb/react";
const { data: status, isLoading } = useCallsStatus({ bundleId, client });
```
### Patch Changes
- [#3178](https://github.com/thirdweb-dev/js/pull/3178) [`3dca028`](https://github.com/thirdweb-dev/js/commit/3dca028a7eff926ae406eb29cc82016ae6c994b3) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Fix gas estimation in transaction button
- [#3187](https://github.com/thirdweb-dev/js/pull/3187) [`874747b`](https://github.com/thirdweb-dev/js/commit/874747b3e00714e9a7336dcfda34e7b92b82e7e1) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Upgrade to latest coinbase wallet sdk
- [#3186](https://github.com/thirdweb-dev/js/pull/3186) [`123275b`](https://github.com/thirdweb-dev/js/commit/123275bbe275457b0be5205812ba0ef75b1f0e5b) Thanks [@gregfromstl](https://github.com/gregfromstl)! - Catch any errors thrown while polling block numbers
## 5.25.1
### Patch Changes
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "thirdweb",
"version": "5.25.1",
"version": "5.26.0",
"repository": {
"type": "git",
"url": "git+https://github.com/thirdweb-dev/js.git#main"
@@ -176,7 +176,7 @@
"!tsconfig.build.json"
],
"dependencies": {
"@coinbase/wallet-sdk": "4.0.0-rc.2",
"@coinbase/wallet-sdk": "4.0.3",
"@emotion/react": "11.11.4",
"@emotion/styled": "11.11.0",
"@google/model-viewer": "2.1.1",
@@ -210,7 +210,7 @@
"react": ">=18",
"react-native": ">=0.70",
"react-native-aes-gcm-crypto": "^0.2",
"react-native-quick-crypto": ">=0.6.1",
"react-native-quick-crypto": ">=0.7.0-rc.6 || >=0.7",
"shamir-secret-sharing": "^0.0.3",
"typescript": ">=5.0.4"
},
@@ -11,6 +11,29 @@ export type AdapterWalletOptions = {
switchChain: (chain: Chain) => Promise<void> | void;
};
/**
* Creates a wallet from the given adapted account. Use this to convert a third party library wallet into a thirdweb wallet.
* @param options - The options for the adapter wallet.
* @returns a wallet instance.
*
* @example
* ```ts
* import { createWalletAdapter } from "thirdweb";
*
* const wallet = createWalletAdapter({
* client,
* adaptedAccount,
* chain,
* onDisconnect: () => {
* // disconnect logic
* },
* switchChain: async (chain) => {
* // switch chain logic
* },
* });
* ```
* @wallet
*/
export function createWalletAdapter(
options: AdapterWalletOptions,
): Wallet<"adapter"> {
@@ -0,0 +1,13 @@
import { defineChain } from "../utils.js";
export const hardhat = /* @__PURE__ */ defineChain({
id: 31337,
name: "Hardhat",
rpc: "http://127.0.0.1:8545",
testnet: true,
nativeCurrency: {
name: "Hardhat Ether",
symbol: "ETH",
decimals: 18,
},
});
+1
View File
@@ -11,6 +11,7 @@ export {
* PRE_DEFINED CHAINS
*/
export { anvil } from "../chains/chain-definitions/anvil.js";
export { hardhat } from "../chains/chain-definitions/hardhat.js";
export { arbitrumNova } from "../chains/chain-definitions/arbitrum-nova.js";
export { arbitrumSepolia } from "../chains/chain-definitions/arbitrum-sepolia.js";
export { arbitrum } from "../chains/chain-definitions/arbitrum.js";
@@ -10,8 +10,14 @@ export type {
PreparedSendCall,
PrepareCallOptions,
} from "../../wallets/eip5792/send-calls.js";
export { getCallsStatus } from "../../wallets/eip5792/get-calls-status.js";
export type { GetCallsStatusOptions } from "../../wallets/eip5792/get-calls-status.js";
export {
type GetCallsStatusOptions,
getCallsStatus,
} from "../../wallets/eip5792/get-calls-status.js";
export {
waitForBundle,
type WaitForBundleOptions,
} from "../../wallets/eip5792/wait-for-bundle.js";
export type {
WalletCapabilities,
WalletCapabilitiesRecord,
@@ -20,3 +26,6 @@ export type {
GetCallsStatusResponse,
WalletCallReceipt,
} from "../../wallets/eip5792/types.js";
export { useSendCalls } from "../../react/core/hooks/wallets/useSendCalls.js";
export { useCallsStatus } from "../../react/core/hooks/wallets/useCallsStatus.js";
export { useCapabilities } from "../../react/core/hooks/wallets/useCapabilities.js";
@@ -6,6 +6,12 @@ export type SetSharedMetadataParams = {
nft: NFTInput;
};
/**
* Sets the shared metadata for a OpenEdition contract.
* @param options - The options for the transaction.
* @returns The prepared transaction.
* @extension ERC721
*/
export function setSharedMetadata(
options: BaseTransactionOptions<SetSharedMetadataParams>,
) {
@@ -33,7 +33,7 @@ export type BuyWithFiatHistoryParams = {
/**
* The results for [`getBuyWithFiatHistory`](https://portal.thirdweb.com/references/typescript/v5/getBuyWithFiatHistory) function
* @buyFiat
* @buyCrypto
*/
export type BuyWithFiatHistoryData = {
page: BuyWithFiatStatus[];
@@ -60,7 +60,7 @@ export type BuyWithFiatHistoryData = {
* })
* ```
* @returns Object of type [`BuyWithFiatHistoryData`](https://portal.thirdweb.com/references/typescript/v5/BuyWithFiatHistoryData)
* @buyFiat
* @buyCrypto
*/
export async function getBuyWithFiatHistory(
params: BuyWithFiatHistoryParams,
@@ -54,7 +54,7 @@ export type GetPostOnRampQuoteParams = {
* });
* }
* ```
* @buyFiat
* @buyCrypto
*/
export async function getPostOnRampQuote({
client,
@@ -232,7 +232,7 @@ export type BuyWithFiatQuote = {
*
* window.open(quote.onRampLink, "_blank");
* ```
* @buyFiat
* @buyCrypto
*/
export async function getBuyWithFiatQuote(
params: GetBuyWithFiatQuoteParams,
@@ -158,7 +158,7 @@ export type BuyWithFiatStatus =
* // when the fiatStatus.status is "ON_RAMP_TRANSFER_COMPLETED" - the process is complete
* // when the fiatStatus.status is "CRYPTO_SWAP_REQUIRED" - start the swap process
* ```
* @buyFiat
* @buyCrypto
*/
export async function getBuyWithFiatStatus(
params: GetBuyWithFiatStatusParams,
@@ -11,7 +11,7 @@ import type { BuyWithFiatQuote } from "./getQuote.js";
*
* @param buyWithFiatQuote - The quote of type [`BuyWithFiatQuote`](https://portal.thirdweb.com/references/typescript/v5/BuyWithFiatQuote) returned
* by the [`getBuyWithFiatQuote`](https://portal.thirdweb.com/references/typescript/v5/getBuyWithFiatQuote) function.
* @buyFiat
* @buyCrypto
*/
export function isSwapRequiredPostOnramp(
buyWithFiatQuote: Pick<BuyWithFiatQuote, "toToken" | "onRampToken">,
@@ -1,4 +1,6 @@
import { useQuery } from "@tanstack/react-query";
import { createWallet } from "../../../../wallets/create-wallet.js";
import { getInstalledWalletProviders } from "../../../../wallets/injected/mipdStore.js";
import type { Wallet } from "../../../../wallets/interfaces/wallet.js";
import {
getLastConnectedChain,
@@ -68,8 +70,13 @@ export function useAutoConnect(props: AutoConnectProps) {
});
}
const availableWallets = [
...wallets,
...getInstalledWalletProviders().map((p) => createWallet(p.info.rdns)),
];
const activeWallet =
lastActiveWalletId && wallets.find((w) => w.id === lastActiveWalletId);
lastActiveWalletId &&
availableWallets.find((w) => w.id === lastActiveWalletId);
if (activeWallet) {
try {
@@ -5,7 +5,6 @@ import { sendTransaction } from "../../../../transaction/actions/send-transactio
import type { WaitForReceiptOptions } from "../../../../transaction/actions/wait-for-tx-receipt.js";
import type { PreparedTransaction } from "../../../../transaction/prepare-transaction.js";
import { resolvePromisedValue } from "../../../../utils/promise/resolve-promised-value.js";
import type { Account } from "../../../../wallets/interfaces/wallet.js";
import {
type GetWalletBalanceResult,
getWalletBalance,
@@ -98,15 +97,14 @@ export function useSendTransactionCore(
return;
}
// buy supported, check if there is enouch balance - if not show modal to buy tokens
// buy supported, check if there is enough balance - if not show modal to buy tokens
const [walletBalance, totalCostWei] = await Promise.all([
getWalletBalance({
address: account.address,
chain: tx.chain,
client: tx.client,
}),
getTotalTxCostForBuy(tx, account),
getTotalTxCostForBuy(tx, account?.address),
]);
const walletBalanceWei = walletBalance.value;
@@ -140,18 +138,31 @@ export function useSendTransactionCore(
export async function getTotalTxCostForBuy(
tx: PreparedTransaction,
account?: Account,
from?: string,
) {
const gasCost = await estimateGasCost({
transaction: tx,
account,
});
try {
const gasCost = await estimateGasCost({
transaction: tx,
from,
});
const bufferCost = gasCost.wei / 10n;
const bufferCost = gasCost.wei / 10n;
// Note: get tx.value AFTER estimateGasCost
const txValue = await resolvePromisedValue(tx.value);
// Note: get tx.value AFTER estimateGasCost
const txValue = await resolvePromisedValue(tx.value);
// add 10% extra gas cost to the estimate to ensure user buys enough to cover the tx cost
return gasCost.wei + bufferCost + (txValue || 0n);
// add 10% extra gas cost to the estimate to ensure user buys enough to cover the tx cost
return gasCost.wei + bufferCost + (txValue || 0n);
} catch (e) {
if (from) {
// try again without passing from
return await getTotalTxCostForBuy(tx);
}
// fallback if both fail, use the tx value + 1% buffer
const value = await resolvePromisedValue(tx.value);
if (!value) {
return 0n;
}
return value + value / 100n;
}
}
@@ -22,6 +22,7 @@ import {
*
* const { data, isLoading, isError } = useWalletBalance({ chain, address, client, tokenAddress });
* ```
* @wallet
*/
export function useWalletBalance(options: Partial<GetWalletBalanceOptions>) {
const { chain, address, tokenAddress, client } = options;
@@ -35,6 +35,7 @@ export type BuyHistoryQueryOptions = Omit<
* return <div> ... </div>
* }
* ```
* @buyCrypto
*/
export function useBuyHistory(
params?: BuyHistoryParams,
@@ -34,7 +34,7 @@ export type BuyWithFiatHistoryQueryOptions = Omit<
* return <div> ... </div>
* }
* ```
* @buyFiat
* @buyCrypto
*/
export function useBuyWithFiatHistory(
params?: BuyWithFiatHistoryParams,
@@ -60,7 +60,7 @@ export type BuyWithFiatQuoteQueryOptions = Omit<
* );
* }
* ```
* @buyFiat
* @buyCrypto
*/
export function useBuyWithFiatQuote(
params?: GetBuyWithFiatQuoteParams,
@@ -31,7 +31,7 @@ import {
* return <div>...</div>;
* }
* ```
* @buyFiat
* @buyCrypto
*/
export function useBuyWithFiatStatus(
params?: GetBuyWithFiatStatusParams,
@@ -32,7 +32,7 @@ export type PostOnRampQuoteQueryOptions = Omit<
*
* @param params - object of type [`GetPostOnRampQuoteParams`](https://portal.thirdweb.com/references/typescript/v5/GetPostOnRampQuoteParams)
* @returns Object of type [`BuyWithCryptoQuote`](https://portal.thirdweb.com/references/typescript/v5/BuyWithCryptoQuote) which contains the information about the quote such as processing fees, estimated time, converted token amounts, etc.
* @buyFiat
* @buyCrypto
*/
export function usePostOnRampQuote(
params?: GetPostOnRampQuoteParams,
@@ -0,0 +1,49 @@
import {
type UseQueryOptions,
type UseQueryResult,
useQuery,
} from "@tanstack/react-query";
import type { ThirdwebClient } from "../../../../client/client.js";
import { getCallsStatus } from "../../../../wallets/eip5792/get-calls-status.js";
import type { GetCallsStatusResponse } from "../../../../wallets/eip5792/types.js";
import { useActiveWallet } from "./wallet-hooks.js";
/**
* A hook to get a call bundle's current status according to [EIP-5792](https://eips.ethereum.org/EIPS/eip-5792).
*
* @note This function is dependent on the wallet's support for EIP-5792 and could throw an error if it's not supported.
*
* @returns a React Query object.
* @beta
* @example
* ```tsx
* import { useCallsStatus } from "thirdweb/react";
* const { data: status, isLoading } = useCallsStatus({ bundleId, client });
* ```
* @extension EIP5792
*/
export function useCallsStatus(options: {
bundleId: string;
client: ThirdwebClient;
queryOptions?: Pick<UseQueryOptions, "enabled" | "retry">;
}): UseQueryResult<GetCallsStatusResponse> {
const { client, bundleId } = options;
const wallet = useActiveWallet();
return useQuery({
queryKey: [
"getCapabilities",
wallet?.getChain()?.id || -1,
wallet?.id,
] as const,
queryFn: async () => {
if (!wallet) {
throw new Error("Failed to get calls status, no wallet connected");
}
return getCallsStatus({ wallet, client, bundleId });
},
retry: false,
enabled: !!bundleId && wallet !== undefined,
...options.queryOptions,
});
}
@@ -0,0 +1,49 @@
import {
type UseQueryOptions,
type UseQueryResult,
useQuery,
} from "@tanstack/react-query";
import {
type GetCapabilitiesResult,
getCapabilities,
} from "../../../../wallets/eip5792/get-capabilities.js";
import { useActiveWallet } from "./wallet-hooks.js";
/**
* A hook to get the current wallet's capabilities according to [EIP-5792](https://eips.ethereum.org/EIPS/eip-5792).
*
* @note This function is dependent on the wallet's support for EIP-5792, but will not throw.
* **The returned object contains a `message` field detailing any issues with the wallet's support for EIP-5792.**
*
* @returns a React Query object.
* @beta
* @example
* ```tsx
* import { useCapabilities } from "thirdweb/react";
* const { data: capabilities, isLoading } = useCapabilities();
* ```
* @extension EIP5792
*/
export function useCapabilities(options?: {
queryOptions?: Pick<UseQueryOptions, "enabled" | "retry">;
}): UseQueryResult<GetCapabilitiesResult> {
const wallet = useActiveWallet();
return useQuery({
queryKey: [
"getCapabilities",
wallet?.getChain()?.id || -1,
wallet?.id,
] as const,
queryFn: async () => {
if (!wallet) {
return {
message: "Can't get capabilities, no wallet connected",
} as const;
}
return getCapabilities({ wallet });
},
retry: false,
...options?.queryOptions,
});
}
@@ -0,0 +1,150 @@
import {
type UseMutationResult,
useMutation,
useQueryClient,
} from "@tanstack/react-query";
import type { ThirdwebClient } from "../../../../client/client.js";
import {
type SendCallsOptions,
sendCalls,
} from "../../../../wallets/eip5792/send-calls.js";
import type {
GetCallsStatusResponse,
WalletSendCallsId,
} from "../../../../wallets/eip5792/types.js";
import { waitForBundle } from "../../../../wallets/eip5792/wait-for-bundle.js";
import type { Wallet } from "../../../../wallets/interfaces/wallet.js";
import { invalidateWalletBalance } from "../../providers/invalidateWalletBalance.js";
import { useActiveWallet } from "../wallets/wallet-hooks.js";
/**
* A hook to send [EIP-5792](https://eips.ethereum.org/EIPS/eip-5792) calls to a wallet.
* This hook works with all Thirdweb wallets (in-app and smart) and certain injected wallets that already support EIP-5792.
* Transactions will be bundled and sponsored when those capabilities are supported, otherwise they will be sent as individual transactions.
*
* When calls are sent, all contracts that are interacted with will have their corresponding reads revalidated via React Query.
*
* @note This hook is dependent on the wallet's support for EIP-5792 and could fail.
* @note The mutatuon function will use your currently connected wallet by default, but you can pass it a specific wallet to use if you'd like.
*
* @returns A React Query mutatuon object to interact with {@link sendCalls}
* @throws an error if the wallet does not support EIP-5792.
* @returns The ID of the bundle of the calls.
*
* @beta
* @example
* ```tsx
* import { useSendCalls } from "thirdweb/react";
*
* const sendTx1 = approve({
contract: USDT_CONTRACT,
amount: 100,
spender: "0x33d9B8BEfE81027E2C859EDc84F5636cbb202Ed6",
});
* const sendTx2 = approve({
contract: USDT_CONTRACT,
amount: 100,
spender: "0x2a4f24F935Eb178e3e7BA9B53A5Ee6d8407C0709",
});
* const { mutate: sendCalls, data: bundleId } = useSendCalls({ client });
* await sendCalls({
* wallet,
* client,
* calls: [sendTx1, sendTx2],
* });
* ```
* Await the bundle's full confirmation:
* ```tsx
* const { mutate: sendCalls, data: bundleId } = useSendCalls({ client, waitForResult: true });
* await sendCalls({
* wallet,
* client,
* calls: [sendTx1, sendTx2],
* });
* ```
* Sponsor transactions with a paymaster:
* ```ts
* const { mutate: sendCalls, data: bundleId } = useSendCalls();
* await sendCalls({
* client,
* calls: [sendTx1, sendTx2],
* capabilities: {
* paymasterService: {
* url: `https://${CHAIN.id}.bundler.thirdweb.com/${client.clientId}`
* }
* }
* });
* @note We recommend proxying any paymaster calls via an API route you setup and control.
* ```
* @extension EIP5792
*/
export function useSendCalls({
client,
waitForResult = true,
}: { client: ThirdwebClient; waitForResult?: boolean }): UseMutationResult<
GetCallsStatusResponse | WalletSendCallsId,
Error,
Omit<SendCallsOptions, "chain" | "wallet"> & { wallet?: Wallet } // Optional wallet override
> {
const connectedWallet = useActiveWallet();
const queryClient = useQueryClient();
return useMutation({
mutationFn: async (options) => {
const { wallet = connectedWallet } = options;
const chain = wallet?.getChain();
if (!wallet || !chain) {
throw new Error(
"Failed to send transactions, no connected wallet found.",
);
}
const callsPromise = sendCalls({ ...options, wallet });
if (!waitForResult) {
return callsPromise;
}
const result = await waitForBundle({
bundleId: await callsPromise,
wallet,
client,
chain,
});
return result;
},
onSettled: async (_result, _error, variables) => {
// Attempt to invalidate any reads related to the sent transactions
const chain = connectedWallet?.getChain();
if (!_result || !connectedWallet || !chain) {
return;
}
if (typeof _result === "string") {
await waitForBundle({
bundleId: _result,
wallet: connectedWallet,
client,
chain,
}).catch((error) => {
console.error(
"Failed to confirm sent bundle and invalidate queries",
_result,
error,
);
return undefined;
});
}
for (const call of variables.calls) {
queryClient.invalidateQueries({
queryKey: [
"readContract",
call.__contract?.chain.id,
call.__contract?.address,
],
});
}
invalidateWalletBalance(queryClient, chain.id);
},
});
}
@@ -0,0 +1,14 @@
import { describe, expect, it } from "vitest";
import { shortenString } from "./addresses.js";
const testAddress = "0x0000000000000000000000000000000000000000";
describe("react: addresses test", () => {
it("should shorten string <extraShort === true>", () => {
expect(shortenString(testAddress, true)).toBe("0x00...000");
});
it("should shorten string <extraShort === false>", () => {
expect(shortenString(testAddress, false)).toBe("0x0000...0000");
});
});
@@ -0,0 +1,65 @@
import { describe, expect, it, vi } from "vitest";
import { timeoutPromise } from "./timeoutPromise.js";
const options = {
ms: 100,
message: "Timeout",
};
describe("timeoutPromise", () => {
it("should resolve if the promise resolves before the timeout", async () => {
const mockPromise = new Promise((resolve) => {
setTimeout(() => resolve("success"), 50);
});
const result = await timeoutPromise(mockPromise, options);
expect(result).toBe("success");
});
it("should reject if the promise rejects before the timeout", async () => {
const mockPromise = new Promise((_, reject) => {
setTimeout(() => reject(new Error("failure")), 50);
});
try {
await timeoutPromise(mockPromise, options);
} catch (error) {
expect(error).toBeInstanceOf(Error);
expect((error as Error).message).toBe("failure");
}
});
it("rejects with the timeout message if the promise took longer than the allowed time", async () => {
const mockPromise = new Promise((resolve) => {
setTimeout(() => resolve("success"), 1000);
});
try {
await timeoutPromise(mockPromise, options);
} catch (error) {
expect(error).toBeInstanceOf(Error);
expect((error as Error).message).toBe("Timeout");
}
});
it("cleans up the timeout when the promise resolves", async () => {
const clearTimeoutSpy = vi.spyOn(global, "clearTimeout");
const mockPromise = new Promise((resolve) => {
setTimeout(() => resolve("success"), 50);
});
await timeoutPromise(mockPromise, options);
expect(clearTimeoutSpy).toHaveBeenCalled();
clearTimeoutSpy.mockRestore();
});
it("cleans up the timeout when the promise rejects", async () => {
const clearTimeoutSpy = vi.spyOn(global, "clearTimeout");
const mockPromise = new Promise((_, reject) => {
setTimeout(() => reject(new Error("failure")), 50);
});
try {
await timeoutPromise(mockPromise, options);
} catch (error) {}
expect(clearTimeoutSpy).toHaveBeenCalled();
clearTimeoutSpy.mockRestore();
});
});
@@ -38,7 +38,10 @@ export function useBuyTxStates(options: {
}
try {
const totalCost = await getTotalTxCostForBuy(buyForTx.tx, account);
const totalCost = await getTotalTxCostForBuy(
buyForTx.tx,
account?.address,
);
if (!mounted) {
return;
@@ -42,7 +42,7 @@ import type { WelcomeScreen } from "./screens/types.js";
* The returned `connect` method takes an object of type [UseConnectModalOptions](https://portal.thirdweb.com/references/typescript/v5/ConnectButtonProps)
* as an argument to customize the Connect Modal UI. Refer to [UseConnectModalOptions](https://portal.thirdweb.com/references/typescript/v5/ConnectButtonProps) to see the available options.
*
* @connectWallet
* @walletConnection
*/
export function useConnectModal() {
const setRootEl = useContext(SetRootElementContext);
@@ -5,6 +5,7 @@ import type { WalletId } from "../../../../wallets/wallet-types.js";
/**
* Returns the wallet info for the provided wallet id.
* @wallet
*/
export function useWalletInfo(id: WalletId) {
return useQuery<WalletInfo>({
@@ -18,6 +19,7 @@ export function useWalletInfo(id: WalletId) {
/**
* Returns the wallet image for the provided wallet id.
* @wallet
*/
export function useWalletImage(id: WalletId) {
return useQuery({
@@ -0,0 +1,34 @@
import { describe, expect, it } from "vitest";
import { wideModalScreenThreshold } from "../ui/ConnectWallet/constants.js";
import { canFitWideModal } from "./canFitWideModal.js";
describe("canFitWideModal", () => {
it("should return true if window width is >= wideModalScreenThreshold", () => {
// Mock the window object and set innerWidth
Object.defineProperty(window, "innerWidth", {
writable: true,
value: wideModalScreenThreshold,
});
expect(canFitWideModal()).toBe(true);
window.innerWidth = wideModalScreenThreshold + 1;
expect(canFitWideModal()).toBe(true);
});
it("returns false if window width is < wideModalScreenThreshold", () => {
// Mock the window object and set innerWidth
Object.defineProperty(window, "innerWidth", {
writable: true,
value: wideModalScreenThreshold - 1,
});
expect(canFitWideModal()).toBe(false);
});
it("returns false if window is undefined", () => {
// Mock the window object to be undefined
const originalWindow = global.window;
// @ts-ignore - Not sure if this is the best way to mock the undefined `window` object
global.window = undefined;
expect(canFitWideModal()).toBe(false);
global.window = originalWindow;
});
});
@@ -16,7 +16,7 @@ const injectedWalletLocaleEn = (wallet: string): InjectedWalletLocale => ({
scanScreen: {
instruction: `Scan the QR code with the ${wallet} app to connect`,
},
getStartedLink: `Don't have a ${wallet} wallet?`,
getStartedLink: `Don't have ${wallet}?`,
download: {
chrome: "Download Chrome Extension",
android: "Download on Google Play",
+53 -29
View File
@@ -32,6 +32,7 @@ function createBlockNumberPoller(
client: ThirdwebClient,
chain: Chain,
overPollRatio?: number,
onError?: (error: Error) => void,
) {
let subscribers: Array<(blockNumber: bigint) => void> = [];
let blockTimesWindow: number[] = [];
@@ -51,35 +52,48 @@ function createBlockNumberPoller(
if (!isActive) {
return;
}
const blockNumber = await eth_blockNumber(rpcRequest);
if (!lastBlockNumber || blockNumber > lastBlockNumber) {
let newBlockNumbers = [];
if (lastBlockNumber) {
for (let i = lastBlockNumber + 1n; i <= blockNumber; i++) {
newBlockNumbers.push(BigInt(i));
try {
const blockNumber = await eth_blockNumber(rpcRequest);
if (!lastBlockNumber || blockNumber > lastBlockNumber) {
let newBlockNumbers = [];
if (lastBlockNumber) {
for (let i = lastBlockNumber + 1n; i <= blockNumber; i++) {
newBlockNumbers.push(BigInt(i));
}
} else {
newBlockNumbers = [blockNumber];
}
lastBlockNumber = blockNumber;
const currentTime = new Date().getTime();
if (lastBlockAt) {
// if we skipped a block we need to adjust the block time down to that level
const blockTime =
(currentTime - lastBlockAt) / newBlockNumbers.length;
blockTimesWindow.push(blockTime);
blockTimesWindow = blockTimesWindow.slice(-SLIDING_WINDOW_SIZE);
}
lastBlockAt = currentTime;
// for all new blockNumbers...
for (const b of newBlockNumbers) {
// ... call all current subscribers
for (const subscriberCallback of subscribers) {
subscriberCallback(b);
}
}
}
} catch (err: unknown) {
if (onError) {
onError(err as Error);
} else {
newBlockNumbers = [blockNumber];
}
lastBlockNumber = blockNumber;
const currentTime = new Date().getTime();
if (lastBlockAt) {
// if we skipped a block we need to adjust the block time down to that level
const blockTime = (currentTime - lastBlockAt) / newBlockNumbers.length;
blockTimesWindow.push(blockTime);
blockTimesWindow = blockTimesWindow.slice(-SLIDING_WINDOW_SIZE);
}
lastBlockAt = currentTime;
// for all new blockNumbers...
for (const b of newBlockNumbers) {
// ... call all current subscribers
for (const subscriberCallback of subscribers) {
subscriberCallback(b);
}
console.error(
`[watchBlockNumber]: Failed to poll for latest block number: ${err}`,
);
}
}
const currentApproximateBlockTime = getAverageBlockTime(blockTimesWindow);
// make sure we never poll faster than our minimum poll delay or slower than our maximum poll delay
@@ -141,6 +155,7 @@ export type WatchBlockNumberOptions = {
client: ThirdwebClient;
chain: Chain;
onNewBlockNumber: (blockNumber: bigint) => void;
onError?: (error: Error) => void;
overPollRatio?: number;
latestBlockNumber?: bigint;
};
@@ -157,7 +172,10 @@ export type WatchBlockNumberOptions = {
* chainId,
* onNewBlockNumber: (blockNumber) => {
* // do something with the block number
* },
* },
* onError: (err) => {
* // do something if getting the block number fails
* },
* });
*
* // later stop watching
@@ -166,14 +184,20 @@ export type WatchBlockNumberOptions = {
* @rpc
*/
export function watchBlockNumber(opts: WatchBlockNumberOptions) {
const { client, chain, onNewBlockNumber, overPollRatio, latestBlockNumber } =
opts;
const {
client,
chain,
onNewBlockNumber,
overPollRatio,
latestBlockNumber,
onError,
} = opts;
const chainId = chain.id;
// if we already have a poller for this chainId -> use it
// if we already have a poller for this chainId -> use it.
let poller = existingPollers.get(chainId);
// otherwise create a new poller
if (!poller) {
poller = createBlockNumberPoller(client, chain, overPollRatio);
poller = createBlockNumberPoller(client, chain, overPollRatio, onError);
// and store it for later use
existingPollers.set(chainId, poller);
}
@@ -23,7 +23,10 @@ export type EstimateGasOptions = Prettify<
export type EstimateGasResult = bigint;
const cache = new WeakMap<PreparedTransaction, Promise<EstimateGasResult>>();
const cache = new WeakMap<
PreparedTransaction & { from: string | undefined },
Promise<EstimateGasResult>
>();
/**
* Estimates the gas required to execute a transaction. The gas is returned as a `bigint` and in gwei units.
@@ -41,9 +44,15 @@ const cache = new WeakMap<PreparedTransaction, Promise<EstimateGasResult>>();
export async function estimateGas(
options: EstimateGasOptions,
): Promise<EstimateGasResult> {
if (cache.has(options.transaction)) {
// from is:
// 1. the user specified from address
// 2. the passed in account address
// 3. the passed in wallet's account address
const from = options.from ?? options.account?.address ?? undefined;
const txWithFrom = { ...options.transaction, from };
if (cache.has(txWithFrom)) {
// biome-ignore lint/style/noNonNullAssertion: the `has` above ensures that this will always be set
return cache.get(options.transaction)!;
return cache.get(txWithFrom)!;
}
const { account } = options;
const promise = (async () => {
@@ -84,11 +93,6 @@ export async function estimateGas(
]);
const rpcRequest = getRpcClient(options.transaction);
// from is:
// 1. the user specified from address
// 2. the passed in account address
// 3. the passed in wallet's account address
const from = options.from ?? options.account?.address ?? undefined;
try {
let gas = await eth_estimateGas(
rpcRequest,
@@ -110,6 +114,6 @@ export async function estimateGas(
});
}
})();
cache.set(options.transaction, promise);
cache.set(txWithFrom, promise);
return promise;
}
@@ -26,6 +26,7 @@ export type SignTransactionOptions = {
* privateKey: "0x...",
* });
* ```
* @transaction
*/
export function signTransaction({
transaction,
@@ -32,6 +32,7 @@ import type { FetchDeployMetadataResult } from "./deploy-metadata.js";
* });
* ```
* @returns A promise that resolves to the predicted address of the contract.
* @extension DEPLOY
*/
export async function computePublishedContractAddress(args: {
client: ThirdwebClient;
+1
View File
@@ -15,6 +15,7 @@ export type ResolveArweaveSchemeOptions = {
* import { resolveArweaveScheme } from "thirdweb/storage";
* const url = resolveArweaveScheme({ uri: "ar://<fileId>" });
* ```
* @storage
*/
export function resolveArweaveScheme(options: ResolveArweaveSchemeOptions) {
if (options.uri.startsWith("ar://")) {
@@ -5,6 +5,7 @@ import type { Hex } from "./is-hex.js";
*
* @param values - An array of hexadecimal values to concatenate.
* @returns The concatenated hexadecimal value.
* @utils
*/
export function concatHex(values: readonly Hex[]): Hex {
return `0x${(values as Hex[]).reduce(
+1
View File
@@ -6,6 +6,7 @@
* const obj = { tokenId: 0n };
* const str = stringify(obj); // "{"tokenId":"0"}"
* ```
* @utils
*/
export const stringify: typeof JSON.stringify = (value, replacer, space) => {
const res = JSON.stringify(
@@ -28,6 +28,7 @@ export type SignMessageOptions = {
* privateKey: "0x...",
* });
* ```
* @utils
*/
export function signMessage({ message, privateKey }: SignMessageOptions): Hex {
const signature = sign({ hash: hashMessage(message), privateKey });
@@ -25,6 +25,7 @@ export type SignTypedDataOptions<
* ...typedData
* });
* ```
* @utils
*/
export function signTypedData<
const typedData extends TypedData | Record<string, unknown>,
@@ -26,6 +26,7 @@ export type SignOptions = {
* privateKey: "0x",
* });
* ```
* @utils
*/
export function sign({ hash, privateKey }: SignOptions): Signature {
const { r, s, recovery } = secp256k1.sign(hash.slice(2), privateKey.slice(2));
@@ -22,6 +22,8 @@ import { type Hex, hexToBigInt } from "../encoding/hex.js";
*
* console.log(hex);
* // "0x6e100a352ec6ad1b70802290e18aeed190704973570f3b8ed42cb9808e2ea6bf4a90a229a244495b41890987806fcbd2d5d23fc0dbe5f5256c2613c039d76db81c"
* ```
* @utils
*/
export function signatureToHex(signature: Signature): Hex {
const { r, s, v } = signature;
@@ -295,7 +295,6 @@ export function walletConnect() {
* import { smartWallet } from "thirdweb/wallets";
*
* const wallet = smartWallet({
* factoryAddress: "0x1234...",
* chain: sepolia,
* gasless: true,
* });
@@ -415,6 +414,7 @@ export function smartWallet(
* strategy: "google",
* });
* ```
*
* Enable smart accounts and sponsor gas for your users:
* ```ts
* import { inAppWallet } from "thirdweb/wallets";
@@ -439,6 +439,7 @@ export function smartWallet(
* },
* },
* });
* ```
*
* Hide the ability to export the private key within the Connect Modal
* ```ts
@@ -16,7 +16,7 @@ export type GetCallsStatusOptions = {
/**
* Get the status of an [EIP-5792](https://eips.ethereum.org/EIPS/eip-5792) bundle.
*
* Note: This function is dependent on the wallet's support for EIP-5792 and could fail.
* @note This function is dependent on the wallet's support for EIP-5792 and could fail.
*
* @param {GetCallsStatusOptions} options
* @param {Wallet} options.wallet - The wallet that send the original calls.
@@ -39,7 +39,8 @@ export type GetCallsStatusOptions = {
* result = await getCallsStatus({ wallet, client, bundleId });
* }
* ```
* @wallets
* @extension EIP5792
* @extension EIP5792
*/
export async function getCallsStatus({
wallet,
@@ -19,7 +19,7 @@ export type GetCapabilitiesResult = Prettify<
/**
* Get the capabilities of a wallet based on the [EIP-5792](https://eips.ethereum.org/EIPS/eip-5792) specification.
*
* Note: This function is dependent on the wallet's support for EIP-5792, but will not throw.
* @note This function is dependent on the wallet's support for EIP-5792, but will not throw.
* **The returned object contains a `message` field detailing any issues with the wallet's support for EIP-5792.**
*
* @param {GetCapabilitiesOptions} options
@@ -34,7 +34,7 @@ export type GetCapabilitiesResult = Prettify<
* const capabilities = await getCapabilities({ wallet });
* ```
*
* @wallets
* @extension EIP5792
*/
export async function getCapabilities<const ID extends WalletId = WalletId>({
wallet,
@@ -56,7 +56,7 @@ export type SendCallsResult = WalletSendCallsId;
* This function works with all Thirdweb wallets (in-app and smart) and certain injected wallets that already support EIP-5792.
* Transactions will be bundled and sponsored when those capabilities are supported, otherwise they will be sent as individual transactions.
*
* Note: This function is dependent on the wallet's support for EIP-5792 and could fail.
* @note This function is dependent on the wallet's support for EIP-5792 and could fail.
*
* @param {SendCallsOptions} options
* @param {Wallet} options.wallet - The wallet to send the calls to.
@@ -106,8 +106,9 @@ export type SendCallsResult = WalletSendCallsId;
* }
* }
* });
* @note We recommend proxying any paymaster calls via an API route you setup and control.
* ```
* @wallets
* @extension EIP5792
*/
export async function sendCalls<const ID extends WalletId>(
options: SendCallsOptions<ID>,
@@ -32,7 +32,7 @@ export type ShowCallsStatusOptions = {
* const bundleId = await sendCalls({ wallet, client, calls });
* await showCallsStatus({ wallet, bundleId });
* ```
* @wallets
* @extension EIP5792
* @internal
*/
export async function showCallsStatus({
@@ -0,0 +1,98 @@
import { afterAll, beforeEach, describe, expect, it, vi } from "vitest";
import { ANVIL_CHAIN } from "../../../test/src/chains.js";
import { TEST_CLIENT } from "../../../test/src/test-clients.js";
import { TEST_ACCOUNT_A } from "../../../test/src/test-wallets.js";
import * as watchBlockNumberExports from "../../rpc/watchBlockNumber.js";
import * as getCallsStatusExports from "../../wallets/eip5792/get-calls-status.js";
import { METAMASK } from "../constants.js";
import { createWallet } from "../create-wallet.js";
import type { GetCallsStatusResponse } from "./types.js";
import {
DEFAULT_MAX_BLOCKS_WAIT_TIME,
waitForBundle,
} from "./wait-for-bundle.js";
const MOCK_BUNDLE_ID = "0x1234567890abcdef";
const MOCK_SUCCESS_RECEIPT: GetCallsStatusResponse = {
status: "CONFIRMED",
receipts: [
{
logs: [],
status: "success",
blockHash:
"0xf19bbafd9fd0124ec110b848e8de4ab4f62bf60c189524e54213285e7f540d4a",
blockNumber: 12345n,
transactionHash:
"0x9b7bb827c2e5e3c1a0a44dc53e573aa0b3af3bd1f9f5ed03071b100bb039eaff",
gasUsed: 12345n,
},
],
};
const MOCK_PENDING_RECEIPT: GetCallsStatusResponse = {
status: "PENDING",
receipts: [],
};
const mockGetCallsStatus = vi.spyOn(getCallsStatusExports, "getCallsStatus");
const wallet = createWallet(METAMASK);
wallet.getAccount = () => TEST_ACCOUNT_A;
let emitBlockNumber: (blockNumber: bigint) => void;
vi.spyOn(watchBlockNumberExports, "watchBlockNumber").mockImplementation(
({ onNewBlockNumber }) => {
emitBlockNumber = (blockNumber: bigint) => {
onNewBlockNumber(blockNumber);
};
return () => {};
},
);
describe("waitForBundle", () => {
afterAll(() => {
vi.restoreAllMocks();
});
beforeEach(() => {
vi.clearAllMocks();
});
it("should resolve with transaction receipt when transactionHash is provided", async () => {
mockGetCallsStatus.mockResolvedValueOnce(MOCK_SUCCESS_RECEIPT);
// can't `await` here because we still need to be able to increment the block number below
const res = waitForBundle({
chain: ANVIL_CHAIN,
client: TEST_CLIENT,
bundleId: MOCK_BUNDLE_ID,
wallet,
});
emitBlockNumber(1n);
await expect(res).resolves.toMatchObject(MOCK_SUCCESS_RECEIPT);
});
it("should reject with an error when bundle is not complete after waiting 10 blocks", async () => {
mockGetCallsStatus.mockRejectedValue(MOCK_PENDING_RECEIPT);
const result = waitForBundle({
chain: ANVIL_CHAIN,
client: TEST_CLIENT,
bundleId: MOCK_BUNDLE_ID,
wallet,
});
for (let i = 1; i <= DEFAULT_MAX_BLOCKS_WAIT_TIME + 1; i++) {
emitBlockNumber(BigInt(i));
}
await expect(result).rejects.toThrow(
`Bundle not confirmed after ${DEFAULT_MAX_BLOCKS_WAIT_TIME} blocks`,
);
expect(mockGetCallsStatus).toHaveBeenCalledTimes(30);
});
});
@@ -0,0 +1,98 @@
import type { Chain } from "../../chains/types.js";
import type { ThirdwebClient } from "../../client/client.js";
import { watchBlockNumber } from "../../rpc/watchBlockNumber.js";
import type { Prettify } from "../../utils/type-utils.js";
import type { Wallet } from "../interfaces/wallet.js";
import { getCallsStatus } from "./get-calls-status.js";
import type { GetCallsStatusResponse, WalletSendCallsId } from "./types.js";
export const DEFAULT_MAX_BLOCKS_WAIT_TIME = 30;
const map = new Map<string, Promise<GetCallsStatusResponse>>();
export type WaitForBundleOptions = Prettify<{
bundleId: WalletSendCallsId;
wallet: Wallet;
client: ThirdwebClient;
chain: Chain;
maxBlocksWaitTime?: number;
}>;
/**
* Waits for the [EIP-5792](https://eips.ethereum.org/EIPS/eip-5792) bundle to be confirmed.
*
* @note This function is dependent on the wallet's support for EIP-5792 and could fail.
*
* @param options - The options for waiting for the bundle.
* By default, the max wait time is 30 blocks.
* @returns A promise that resolves with the final {@link getCallsStatus} result.
* @throws an error if the wallet does not support EIP-5792.
* @beta
* @example
* ```ts
* import { waitForBundle } from "thirdweb/wallets/eip5792";
* const result = await waitForBundle({
* client,
* chain,
* wallet,
* bundleId: "0x123...",
* });
* ```
* @extension EIP5792
*/
export function waitForBundle(
options: WaitForBundleOptions,
): Promise<GetCallsStatusResponse> {
const { bundleId, chain, wallet, client } = options;
const chainId = chain.id;
const key = `${chainId}:calls_${bundleId}`;
const maxBlocksWaitTime =
options.maxBlocksWaitTime ?? DEFAULT_MAX_BLOCKS_WAIT_TIME;
if (map.has(key)) {
// biome-ignore lint/style/noNonNullAssertion: the `has` above ensures that this will always be set
return map.get(key)!;
}
const promise = new Promise<GetCallsStatusResponse>((resolve, reject) => {
// start at -1 because the first block doesn't count
let blocksWaited = -1;
const unwatch = watchBlockNumber({
client: client,
chain: chain,
onNewBlockNumber: async () => {
blocksWaited++;
if (blocksWaited >= maxBlocksWaitTime) {
unwatch();
reject(
new Error(`Bundle not confirmed after ${maxBlocksWaitTime} blocks`),
);
return;
}
try {
const result = await getCallsStatus({
wallet,
client,
bundleId,
});
if (result.status === "CONFIRMED") {
// stop the polling
unwatch();
// resolve the top level promise with the result
resolve(result);
}
} catch {
// noop, we'll try again on the next blocks
}
},
});
// remove the promise from the map when it's done (one way or the other)
}).finally(() => {
map.delete(key);
});
map.set(key, promise);
return promise;
}
@@ -69,6 +69,7 @@ export async function logoutAuthenticatedUser(
* console.log(user.walletAddress);
* }
* ```
* @wallet
*/
export async function getAuthenticatedUser(
options: GetAuthenticatedUserParams,
@@ -95,6 +96,7 @@ export async function getAuthenticatedUser(
* const email = await getUserEmail({ client });
* console.log(email);
* ```
* @wallet
*/
export async function getUserEmail(options: GetAuthenticatedUserParams) {
const user = await getAuthenticatedUser(options);
@@ -115,6 +117,7 @@ export async function getUserEmail(options: GetAuthenticatedUserParams) {
* const phoneNumber = await getUserPhoneNumber({ client });
* console.log(phoneNumber);
* ```
* @wallet
*/
export async function getUserPhoneNumber(options: GetAuthenticatedUserParams) {
const user = await getAuthenticatedUser(options);
@@ -139,6 +142,7 @@ export async function getUserPhoneNumber(options: GetAuthenticatedUserParams) {
* email: "[email protected]",
* });
* ```
* @wallet
*/
export async function preAuthenticate(args: PreAuthArgsType) {
const ewSDK = await getInAppWalletConnector(args.client);
@@ -160,6 +164,7 @@ export async function preAuthenticate(args: PreAuthArgsType) {
* verificationCode: "123456",
* });
* ```
* @wallet
*/
export async function authenticate(
args: AuthArgsType,
@@ -132,6 +132,7 @@ export async function loginWithPasskey(options: {
* Returns whether this device has a stored passkey ready to be used for sign-in
* @param client - the thirdweb client
* @returns whether the device has a stored passkey
* @wallet
*/
export async function hasStoredPasskey(client: ThirdwebClient) {
const storage = new LocalStorage({ clientId: client.clientId });
Binary file not shown.
+23 -45
View File
@@ -906,6 +906,9 @@ importers:
fuse.js:
specifier: ^7.0.0
version: 7.0.0
input-otp:
specifier: ^1.2.4
version: 1.2.4([email protected])([email protected])
qrcode:
specifier: ^1.5.3
version: 1.5.3
@@ -1353,14 +1356,14 @@ importers:
specifier: ^0.5.0
version: 0.5.0
'@blocto/sdk':
specifier: 0.5.5
version: 0.5.5
specifier: 0.10.2
version: 0.10.2
'@coinbase/wallet-sdk':
specifier: ^3.7.2
specifier: ^3.9.0
version: 3.9.3
'@google-cloud/kms':
specifier: 4.2.0
version: 4.2.0
specifier: ^4.4.0
version: 4.4.0
'@magic-ext/connect':
specifier: ^6.7.2
version: 6.7.2
@@ -1383,8 +1386,8 @@ importers:
specifier: ^3.3.5
version: 3.3.5([email protected])
'@safe-global/safe-ethers-adapters':
specifier: 0.1.0-alpha.17
version: 0.1.0-alpha.17(@ethersproject/[email protected])(@ethersproject/[email protected])(@ethersproject/[email protected])(@ethersproject/[email protected])([email protected])
specifier: 0.1.0-alpha.19
version: 0.1.0-alpha.19(@ethersproject/[email protected])(@ethersproject/[email protected])(@ethersproject/[email protected])(@ethersproject/[email protected])([email protected])
'@safe-global/safe-ethers-lib':
specifier: ^1.9.4
version: 1.9.4
@@ -1564,8 +1567,8 @@ importers:
specifier: ^1
version: 1.11.0([email protected])
react-native-quick-crypto:
specifier: '>=0.6.1'
version: 0.6.1([email protected])([email protected])
specifier: '>=0.7.0-rc.6 || >=0.7'
version: 0.7.0-rc.6([email protected])([email protected])
shamir-secret-sharing:
specifier: 0.0.3
version: 0.0.3
@@ -1601,8 +1604,8 @@ importers:
packages/thirdweb:
dependencies:
'@coinbase/wallet-sdk':
specifier: 4.0.0-rc.2
version: 4.0.0-rc.2
specifier: 4.0.3
version: 4.0.3
'@emotion/react':
specifier: 11.11.4
version: 11.11.4(@types/[email protected])([email protected])
@@ -5539,18 +5542,14 @@ packages:
dev: true
optional: true
/@blocto/sdk@0.5.5:
resolution: {integrity: sha512-u7bbAYmYDCf0QWvXleVOTeGFRbo8evT3uacsLJ6dv01HspmLDKZWjFyu7i3ARebJTpenHvwM78XHV7KTvBqTRg==}
/@blocto/sdk@0.10.2:
resolution: {integrity: sha512-9gCIUKA7/7/hMHaa5n94+OYU/3tHd6vmBgTgv4o2h3z9SFueQXAJMO4aBggH9+EldgHQDI6wHsnvytEt9AWb6g==}
peerDependencies:
'@solana/web3.js': ^1.30.2
aptos: ^1.3.14
peerDependenciesMeta:
'@solana/web3.js':
optional: true
aptos:
optional: true
dependencies:
bs58: 5.0.0
buffer: 6.0.3
eip1193-provider: 1.0.1
js-sha3: 0.8.0
@@ -5833,8 +5832,8 @@ packages:
- supports-color
dev: false
/@coinbase/[email protected].0-rc.2:
resolution: {integrity: sha512-1wrzKtgEhB5cr5z2xPUWw8BUs2+w6ddzWEkafYUh0+fKvXPWl8y5bgBvMiWpjnDa/n9rIliGW7Bs2QlLaRvmtA==}
/@coinbase/[email protected].3:
resolution: {integrity: sha512-y/OGEjlvosikjfB+wk+4CVb9OxD1ob9cidEBLI5h8Hxaf/Qoob2XoVT1uvhtAzBx34KpGYSd+alKvh/GCRre4Q==}
dependencies:
buffer: 6.0.3
clsx: 1.2.1
@@ -7271,8 +7270,8 @@ packages:
keycode: 2.2.1
dev: true
/@google-cloud/kms@4.2.0:
resolution: {integrity: sha512-EIFxBL2XbpRkW6TmmYNU3xmpbaDw49uD57q6/rRQMkWPENvPTrlonQeTBeXV1I18GMToVliQOwKs001Mzo7Dwg==}
/@google-cloud/kms@4.4.0:
resolution: {integrity: sha512-ZS2IOouhNThDYdHQjH7JO9DfqLlfhxsXs/z1Pwzb9vsw+In0RbsyxtVZc/s7n+Qp09MZ+e4kfrR9YiRn6TyT9w==}
engines: {node: '>=14.0.0'}
dependencies:
google-gax: 4.3.3
@@ -10961,8 +10960,8 @@ packages:
semver: 7.6.2
dev: false
/@safe-global/[email protected]7(@ethersproject/[email protected])(@ethersproject/[email protected])(@ethersproject/[email protected])(@ethersproject/[email protected])([email protected]):
resolution: {integrity: sha512-02+emAnnXZAOwld1Ucen6idnMCAD76TXrhmuteYsdYoPjl5Eyq1ySb9tzIjCWklgfjMHQtrHSHDJqwdlHFM4GQ==}
/@safe-global/[email protected]9(@ethersproject/[email protected])(@ethersproject/[email protected])(@ethersproject/[email protected])(@ethersproject/[email protected])([email protected]):
resolution: {integrity: sha512-FKd1XySR/FGfEY/HDGfQPByTnOPWE4m6HuH/Q4PgizsGdgYa6kjUy0/UWTb42bOdkqeVm2XffPxErHK/BaUhaQ==}
peerDependencies:
'@ethersproject/abstract-provider': ^5.7.0
'@ethersproject/abstract-signer': ^5.7.0
@@ -12391,10 +12390,6 @@ packages:
resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==}
dev: false
/@types/[email protected]:
resolution: {integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==}
dev: false
/@types/[email protected]:
resolution: {integrity: sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q==}
dev: true
@@ -23036,23 +23031,6 @@ packages:
react: 18.2.0
react-native: 0.74.1(@babel/[email protected])(@babel/[email protected])(@types/[email protected])([email protected])
/[email protected]([email protected])([email protected]):
resolution: {integrity: sha512-s6uFo7tcI3syo8/y5j+t6Rf+KVSuRKDp6tH04A0vjaHptJC6Iu7DVgkNYO7aqtfrYn8ZUgQ/Kqaq+m4i9TxgIQ==}
peerDependencies:
react: '*'
react-native: '>=0.71.0'
dependencies:
'@craftzdog/react-native-buffer': 6.0.5([email protected])([email protected])
'@types/node': 17.0.45
crypto-browserify: 3.12.0
events: 3.3.0
react: 18.2.0
react-native: 0.74.1(@babel/[email protected])(@babel/[email protected])(@types/[email protected])([email protected])
react-native-quick-base64: 2.1.2([email protected])([email protected])
stream-browserify: 3.0.0
string_decoder: 1.3.0
dev: false
/[email protected]([email protected])([email protected]):
resolution: {integrity: sha512-l3L96k7Bpdu6Mh3uuZfdAuyfPz5mlpnXpBQIxGuwpY64V+K8U62lN+8jukfJiCu/huCXog5iikUQjtcPmlGkOw==}
dependencies:
@@ -23064,7 +23042,6 @@ packages:
transitivePeerDependencies:
- react
- react-native
dev: true
/[email protected]([email protected]):
resolution: {integrity: sha512-w9JfSkvpqqlix9UjDvJjm1EjSt652zVQ6iwCIj1cVVkwXf4jQhQgTNXY6EVTwuAmUjg6BC6k9RHCBynoLFo3IQ==}
@@ -24449,6 +24426,7 @@ packages:
dependencies:
inherits: 2.0.4
readable-stream: 3.6.2
dev: true
/[email protected]:
resolution: {integrity: sha512-uyQK/mx5QjHun80FLJTfaWE7JtwfRMKBLkMne6udYOmvH0CawotVa7TfgYHzAnpphn4+TweIx1QKMnRIbipmUg==}
-43
View File
@@ -1,43 +0,0 @@
#!/usr/bin/env bash
set -e
echo "Setting up environment..."
# check if pnpm is installed
if ! command -v pnpm &> /dev/null
then
echo "⌛️ \"pnpm\" seems to not be installed, installing it now..."
# if not, install it using corepack if that is available
if command -v corepack &> /dev/null
then
corepack enable
corepack prepare [email protected] --activate
else
# if not, install it using npm
npm install -g pnpm
fi
else
# if it is, just confirm that to the user
echo "✅ \"pnpm\" is already installed"
fi
# check if there is still a leftover yarn.lock file
if [ -f "yarn.lock" ]
then
echo "⌛️ \"yarn.lock\" file found, removing it..."
rm yarn.lock
echo "✅ \"yarn.lock\" file removed"
# if we had a yarn lock we likely also have to remove all node_modules folders
echo "⌛️ Removing all \"node_modules\" folders in project..."
find ./ -name "node_modules" -type d -exec rm -rf {} \;
echo "✅ Removed all \"node_modules\" folders in project"
fi
# after all of that we'll want to re-install dependencies using pnpm
echo "⌛️ Installing dependencies using \"pnpm\"..."
pnpm install
echo "✅ Installed dependencies using \"pnpm\""
# we're finished
echo "✅ Environment setup complete"