Compare commits
70
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e17e41f4d1 | ||
|
|
712b11a43e | ||
|
|
306debb029 | ||
|
|
86f0ceff46 | ||
|
|
7f0d1ec947 | ||
|
|
b1218cbd7d | ||
|
|
97ef35ce0f | ||
|
|
1f46f270cd | ||
|
|
e8c25ed0f2 | ||
|
|
78d6d3c159 | ||
|
|
c72d92956a | ||
|
|
cf88795376 | ||
|
|
47287fb189 | ||
|
|
3763326c25 | ||
|
|
894eb27dfa | ||
|
|
8b3b97c8f7 | ||
|
|
89d87a5eb3 | ||
|
|
492a818079 | ||
|
|
86f608390a | ||
|
|
8096c78b46 | ||
|
|
521a49c6ec | ||
|
|
25a4773bba | ||
|
|
18381fac73 | ||
|
|
89b5c6fe07 | ||
|
|
4dccccc6fa | ||
|
|
de15e4212f | ||
|
|
1f41adbd2c | ||
|
|
1918495f2e | ||
|
|
24514a6e9f | ||
|
|
ad06c5b289 | ||
|
|
9de3f8c8e9 | ||
|
|
b1fa17158d | ||
|
|
2bdf1984cb | ||
|
|
df048af605 | ||
|
|
41507d32a7 | ||
|
|
b2cadf164c | ||
|
|
57b9c671aa | ||
|
|
3b7d10ed93 | ||
|
|
d6bb61b7fa | ||
|
|
8e591383fc | ||
|
|
6f95a520e6 | ||
|
|
f669d3ef4a | ||
|
|
83575058db | ||
|
|
028cb78125 | ||
|
|
c8261b74b5 | ||
|
|
a36c788415 | ||
|
|
ac232b5aff | ||
|
|
ba6f45027a | ||
|
|
d677e9d634 | ||
|
|
9b92697fb7 | ||
|
|
c19e471f65 | ||
|
|
b6fc298d0c | ||
|
|
ea41231b3e | ||
|
|
2ea3f00c41 | ||
|
|
20745f8cd6 | ||
|
|
caf979537b | ||
|
|
e4b10bc5bd | ||
|
|
ef0bac7f44 | ||
|
|
23de9eac4f | ||
|
|
1972f3ec0d | ||
|
|
ffd0fc42ae | ||
|
|
93531a5d47 | ||
|
|
b16aaebc4c | ||
|
|
1136d959ba | ||
|
|
db23f0588d | ||
|
|
e662408e19 | ||
|
|
afe4ba6471 | ||
|
|
6647f707bd | ||
|
|
cac373b010 | ||
|
|
9412d41683 |
@@ -2,7 +2,7 @@
|
||||
"$schema": "https://unpkg.com/@changesets/[email protected]/schema.json",
|
||||
"changelog": ["@changesets/changelog-github", { "repo": "thirdweb-dev/js" }],
|
||||
"commit": false,
|
||||
"fixed": [],
|
||||
"fixed": [["@thirdweb-dev/sdk", "@thirdweb-dev/react"]],
|
||||
"linked": [],
|
||||
"access": "public",
|
||||
"baseBranch": "main",
|
||||
|
||||
@@ -30,8 +30,6 @@ jobs:
|
||||
- name: Install
|
||||
uses: ./.github/composite-actions/install
|
||||
|
||||
- name: Build
|
||||
run: yarn build
|
||||
|
||||
- name: Test
|
||||
# this already builds anything that changed...
|
||||
- name: Build & Test
|
||||
run: yarn test
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
name: Compressed Size
|
||||
|
||||
on: [pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
# try out buildjet to speed up build and test
|
||||
runs-on: buildjet-32vcpu-ubuntu-2204
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 1
|
||||
- uses: preactjs/compressed-size-action@v2
|
||||
with:
|
||||
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
strip-hash: "\\-(\\w{8})(?:\\.esm|\\.cjs)"
|
||||
minimum-change-threshold: 100
|
||||
@@ -27,7 +27,7 @@
|
||||
| [/auth](./packages/auth) | Best in class wallet authentication for Node backends | <a href="https://www.npmjs.com/package/@thirdweb-dev/auth"><img src="https://img.shields.io/npm/v/@thirdweb-dev/auth?color=red&label=npm&logo=npm" alt="npm version"/></a> |
|
||||
| [/storage](./packages/storage) | Best in class decentralized storage SDK for Browser and Node | <a href="https://www.npmjs.com/package/@thirdweb-dev/storage"><img src="https://img.shields.io/npm/v/@thirdweb-dev/storage?color=red&label=npm&logo=npm" alt="npm version"/></a> |
|
||||
| [/cli](./packages/cli) | Publish and deploy smart contracts without dealing with private keys | <a href="https://www.npmjs.com/package/thirdweb"><img src="https://img.shields.io/npm/v/thirdweb?color=red&label=npm&logo=npm" alt="npm version"/></a> |
|
||||
| [/solana](./packages/solana) | Solana SDK for Browser, Node and React Native | <a href="https://www.npmjs.com/package/@thirdweb-dev/solana"><img src="https://img.shields.io/npm/v/@thirdweb-dev/solana?color=red&label=npm&logo=npm" alt="npm version"/></a> |
|
||||
|
||||
|
||||
## Documentation
|
||||
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@
|
||||
]
|
||||
},
|
||||
"scripts": {
|
||||
"test": "turbo run test && turbo run test:evm && turbo run test:solana",
|
||||
"test": "turbo run test test:evm test:solana",
|
||||
"e2e": "turbo run e2e",
|
||||
"build": "turbo run build",
|
||||
"build:release": "turbo run build --force",
|
||||
|
||||
@@ -1,5 +1,21 @@
|
||||
# @thirdweb-dev/auth
|
||||
|
||||
## 2.0.17
|
||||
|
||||
## 2.0.16
|
||||
|
||||
## 2.0.15
|
||||
|
||||
## 2.0.14
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#274](https://github.com/thirdweb-dev/js/pull/274) [`ad06c5b`](https://github.com/thirdweb-dev/js/commit/ad06c5b28902422f9b416d65255c64c937a5e046) Thanks [@adam-maj](https://github.com/adam-maj)! - Add solana auth support and plugins for react and auth package
|
||||
|
||||
## 2.0.13
|
||||
|
||||
## 2.0.12
|
||||
|
||||
## 2.0.11
|
||||
|
||||
## 2.0.10
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"main": "dist/thirdweb-dev-auth-next-evm.cjs.js",
|
||||
"module": "dist/thirdweb-dev-auth-next-evm.esm.js"
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"main": "dist/thirdweb-dev-auth-next-solana.cjs.js",
|
||||
"module": "dist/thirdweb-dev-auth-next-solana.esm.js"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/auth",
|
||||
"version": "2.0.11",
|
||||
"version": "2.0.17",
|
||||
"exports": {
|
||||
"./next": {
|
||||
"module": "./next/dist/thirdweb-dev-auth-next.esm.js",
|
||||
@@ -10,10 +10,18 @@
|
||||
"module": "./express/dist/thirdweb-dev-auth-express.esm.js",
|
||||
"default": "./express/dist/thirdweb-dev-auth-express.cjs.js"
|
||||
},
|
||||
"./next/evm": {
|
||||
"module": "./next/evm/dist/thirdweb-dev-auth-next-evm.esm.js",
|
||||
"default": "./next/evm/dist/thirdweb-dev-auth-next-evm.cjs.js"
|
||||
},
|
||||
"./next-auth": {
|
||||
"module": "./next-auth/dist/thirdweb-dev-auth-next-auth.esm.js",
|
||||
"default": "./next-auth/dist/thirdweb-dev-auth-next-auth.cjs.js"
|
||||
},
|
||||
"./next/solana": {
|
||||
"module": "./next/solana/dist/thirdweb-dev-auth-next-solana.esm.js",
|
||||
"default": "./next/solana/dist/thirdweb-dev-auth-next-solana.cjs.js"
|
||||
},
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/auth",
|
||||
@@ -35,6 +43,8 @@
|
||||
"preconstruct": {
|
||||
"entrypoints": [
|
||||
"next/index.ts",
|
||||
"next/evm/index.ts",
|
||||
"next/solana/index.ts",
|
||||
"express/index.ts",
|
||||
"next-auth/index.ts"
|
||||
],
|
||||
@@ -44,6 +54,7 @@
|
||||
"exports": true
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.19.3",
|
||||
"@babel/preset-env": "^7.18.10",
|
||||
"@babel/preset-typescript": "^7.18.6",
|
||||
"@microsoft/api-documenter": "^7.19.4",
|
||||
@@ -62,11 +73,13 @@
|
||||
"eslint-plugin-inclusive-language": "^2.2.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"eslint-plugin-tsdoc": "^0.2.16",
|
||||
"ethers": "^5.7.0",
|
||||
"ethers": "^5.7.1",
|
||||
"express": "^4.18.1",
|
||||
"next": "^12.2.0",
|
||||
"next-auth": "^4.10.3",
|
||||
"prettier": "^2.7.1",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"typescript": "^4.7.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
import loginHandler from "./routes/login";
|
||||
import logoutHandler from "./routes/logout";
|
||||
import userHandler from "./routes/user";
|
||||
import {
|
||||
ThirdwebAuthConfig,
|
||||
ThirdwebAuthRoute,
|
||||
ThirdwebAuthUser,
|
||||
} from "./types";
|
||||
import { ThirdwebSDK } from "@thirdweb-dev/sdk";
|
||||
import cookieParser from "cookie-parser";
|
||||
import { Express, NextFunction, Request, Response } from "express";
|
||||
|
||||
export * from "./types";
|
||||
|
||||
export function getUser(req: Request): ThirdwebAuthUser | null {
|
||||
return req.user;
|
||||
}
|
||||
|
||||
export function ThirdwebAuth(app: Express, cfg: ThirdwebAuthConfig) {
|
||||
const ctx = {
|
||||
...cfg,
|
||||
sdk: ThirdwebSDK.fromPrivateKey(cfg.privateKey, "mainnet"),
|
||||
};
|
||||
|
||||
const authUrl = cfg.authUrl?.replace(/\/$/, "") || "/auth";
|
||||
|
||||
app.use(cookieParser());
|
||||
|
||||
app.use(async (req: Request, _: Response, next: NextFunction) => {
|
||||
const { sdk, domain } = ctx;
|
||||
let user = null;
|
||||
const token = req.cookies.thirdweb_auth_token;
|
||||
|
||||
if (token) {
|
||||
try {
|
||||
const address = await sdk.auth.authenticate(domain, token);
|
||||
|
||||
if (ctx.callbacks?.user) {
|
||||
user = await ctx.callbacks.user(address);
|
||||
}
|
||||
|
||||
user = { ...user, address };
|
||||
} catch {
|
||||
// No-op
|
||||
}
|
||||
}
|
||||
|
||||
req.user = user as ThirdwebAuthUser | null;
|
||||
next();
|
||||
});
|
||||
|
||||
app.get(`${authUrl}/:route`, (req: Request, res: Response) => {
|
||||
const action = req.params.route as ThirdwebAuthRoute;
|
||||
|
||||
switch (action) {
|
||||
case "login":
|
||||
return loginHandler(req, res, ctx);
|
||||
case "user":
|
||||
return userHandler(req, res);
|
||||
case "logout":
|
||||
return logoutHandler(req, res);
|
||||
default:
|
||||
return res.status(400).json({
|
||||
message: "Invalid route for authentication.",
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1,68 +1 @@
|
||||
import loginHandler from "./routes/login";
|
||||
import logoutHandler from "./routes/logout";
|
||||
import userHandler from "./routes/user";
|
||||
import {
|
||||
ThirdwebAuthConfig,
|
||||
ThirdwebAuthRoute,
|
||||
ThirdwebAuthUser,
|
||||
} from "./types";
|
||||
import { ThirdwebSDK } from "@thirdweb-dev/sdk";
|
||||
import cookieParser from "cookie-parser";
|
||||
import { Express, NextFunction, Request, Response } from "express";
|
||||
|
||||
export * from "./types";
|
||||
|
||||
export function getUser(req: Request): ThirdwebAuthUser | null {
|
||||
return req.user;
|
||||
}
|
||||
|
||||
export function ThirdwebAuth(app: Express, cfg: ThirdwebAuthConfig) {
|
||||
const ctx = {
|
||||
...cfg,
|
||||
sdk: ThirdwebSDK.fromPrivateKey(cfg.privateKey, "mainnet"),
|
||||
};
|
||||
|
||||
const authUrl = cfg.authUrl?.replace(/\/$/, "") || "/auth";
|
||||
|
||||
app.use(cookieParser());
|
||||
|
||||
app.use(async (req: Request, _: Response, next: NextFunction) => {
|
||||
const { sdk, domain } = ctx;
|
||||
let user = null;
|
||||
const token = req.cookies.thirdweb_auth_token;
|
||||
|
||||
if (token) {
|
||||
try {
|
||||
const address = await sdk.auth.authenticate(domain, token);
|
||||
|
||||
if (ctx.callbacks?.user) {
|
||||
user = await ctx.callbacks.user(address);
|
||||
}
|
||||
|
||||
user = { ...user, address };
|
||||
} catch {
|
||||
// No-op
|
||||
}
|
||||
}
|
||||
|
||||
req.user = user as ThirdwebAuthUser | null;
|
||||
next();
|
||||
});
|
||||
|
||||
app.get(`${authUrl}/:route`, (req: Request, res: Response) => {
|
||||
const action = req.params.route as ThirdwebAuthRoute;
|
||||
|
||||
switch (action) {
|
||||
case "login":
|
||||
return loginHandler(req, res, ctx);
|
||||
case "user":
|
||||
return userHandler(req, res);
|
||||
case "logout":
|
||||
return logoutHandler(req, res);
|
||||
default:
|
||||
return res.status(400).json({
|
||||
message: "Invalid route for authentication.",
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
export * from "./evm";
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
import { ThirdwebNextAuthConfig } from "./types";
|
||||
import { ThirdwebSDK } from "@thirdweb-dev/sdk";
|
||||
import { serialize } from "cookie";
|
||||
import {
|
||||
GetServerSidePropsContext,
|
||||
NextApiRequest,
|
||||
NextApiResponse,
|
||||
} from "next";
|
||||
import NextAuth, {
|
||||
NextAuthOptions,
|
||||
Session,
|
||||
unstable_getServerSession,
|
||||
} from "next-auth";
|
||||
import CredentialsProvider from "next-auth/providers/credentials";
|
||||
|
||||
export function ThirdwebNextAuth(cfg: ThirdwebNextAuthConfig) {
|
||||
const sdk = ThirdwebSDK.fromPrivateKey(cfg.privateKey, "mainnet");
|
||||
|
||||
function ThirdwebProvider(res: GetServerSidePropsContext["res"]) {
|
||||
return CredentialsProvider({
|
||||
name: "ThirdwebAuth",
|
||||
credentials: {
|
||||
payload: {
|
||||
label: "Payload",
|
||||
type: "text",
|
||||
placeholder: "",
|
||||
},
|
||||
},
|
||||
async authorize({ payload }: any) {
|
||||
try {
|
||||
const parsed = JSON.parse(payload);
|
||||
const token = await sdk.auth.generateAuthToken(cfg.domain, parsed);
|
||||
const address = await sdk.auth.authenticate(cfg.domain, token);
|
||||
|
||||
// Securely set httpOnly cookie on request to prevent XSS on frontend
|
||||
// And set path to / to enable thirdweb_auth_token usage on all endpoints
|
||||
res.setHeader(
|
||||
"Set-Cookie",
|
||||
serialize("thirdweb_auth_token", token, {
|
||||
path: "/",
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
sameSite: "strict",
|
||||
}),
|
||||
);
|
||||
|
||||
return { address };
|
||||
} catch (err) {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function nextOptions(
|
||||
req: GetServerSidePropsContext["req"],
|
||||
res: GetServerSidePropsContext["res"],
|
||||
): NextAuthOptions {
|
||||
async function session({
|
||||
session: _session,
|
||||
}: {
|
||||
session: Session;
|
||||
}): Promise<Session> {
|
||||
const token = req.cookies.thirdweb_auth_token || "";
|
||||
try {
|
||||
const address = await sdk.auth.authenticate(cfg.domain, token);
|
||||
_session.user = { ..._session.user, address } as Session["user"];
|
||||
return _session;
|
||||
} catch {
|
||||
return _session;
|
||||
}
|
||||
}
|
||||
|
||||
function signOut() {
|
||||
res.setHeader(
|
||||
"Set-Cookie",
|
||||
serialize("thirdweb_auth_token", "", {
|
||||
path: "/",
|
||||
expires: new Date(Date.now() + 5 * 1000),
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
const providers: NextAuthOptions["providers"] = [
|
||||
...cfg.nextOptions.providers,
|
||||
ThirdwebProvider(res),
|
||||
];
|
||||
|
||||
const configSession = cfg.nextOptions.callbacks?.session;
|
||||
const callbacks: NextAuthOptions["callbacks"] = {
|
||||
...cfg.nextOptions.callbacks,
|
||||
session: configSession
|
||||
? async (params) => {
|
||||
params.session = await session(params);
|
||||
return configSession(params);
|
||||
}
|
||||
: session,
|
||||
};
|
||||
|
||||
const configSignOut = cfg.nextOptions.events?.signOut;
|
||||
const events: NextAuthOptions["events"] = {
|
||||
...cfg.nextOptions.events,
|
||||
signOut: configSignOut
|
||||
? async (params) => {
|
||||
signOut();
|
||||
return configSignOut(params);
|
||||
}
|
||||
: signOut,
|
||||
};
|
||||
|
||||
return {
|
||||
...cfg.nextOptions,
|
||||
providers,
|
||||
callbacks,
|
||||
events,
|
||||
};
|
||||
}
|
||||
|
||||
async function getUser(
|
||||
...args:
|
||||
| [NextApiRequest, NextApiResponse]
|
||||
| [GetServerSidePropsContext["req"], GetServerSidePropsContext["res"]]
|
||||
) {
|
||||
return unstable_getServerSession(
|
||||
args[0],
|
||||
args[1],
|
||||
nextOptions(args[0], args[1]),
|
||||
);
|
||||
}
|
||||
|
||||
function NextAuthHandler(...args: [] | [NextApiRequest, NextApiResponse]) {
|
||||
if (args.length === 0) {
|
||||
return (req: NextApiRequest, res: NextApiResponse) => {
|
||||
return NextAuth(req, res, nextOptions(req, res));
|
||||
};
|
||||
}
|
||||
|
||||
return NextAuth(args[0], args[1], nextOptions(args[0], args[1]));
|
||||
}
|
||||
|
||||
return {
|
||||
NextAuthHandler,
|
||||
getUser,
|
||||
};
|
||||
}
|
||||
@@ -1,145 +1 @@
|
||||
import { ThirdwebNextAuthConfig } from "./types";
|
||||
import { ThirdwebSDK } from "@thirdweb-dev/sdk";
|
||||
import { serialize } from "cookie";
|
||||
import {
|
||||
GetServerSidePropsContext,
|
||||
NextApiRequest,
|
||||
NextApiResponse,
|
||||
} from "next";
|
||||
import NextAuth, {
|
||||
NextAuthOptions,
|
||||
Session,
|
||||
unstable_getServerSession,
|
||||
} from "next-auth";
|
||||
import CredentialsProvider from "next-auth/providers/credentials";
|
||||
|
||||
export function ThirdwebNextAuth(cfg: ThirdwebNextAuthConfig) {
|
||||
const sdk = ThirdwebSDK.fromPrivateKey(cfg.privateKey, "mainnet");
|
||||
|
||||
function ThirdwebProvider(res: GetServerSidePropsContext["res"]) {
|
||||
return CredentialsProvider({
|
||||
name: "ThirdwebAuth",
|
||||
credentials: {
|
||||
payload: {
|
||||
label: "Payload",
|
||||
type: "text",
|
||||
placeholder: "",
|
||||
},
|
||||
},
|
||||
async authorize({ payload }: any) {
|
||||
try {
|
||||
const parsed = JSON.parse(payload);
|
||||
const token = await sdk.auth.generateAuthToken(cfg.domain, parsed);
|
||||
const address = await sdk.auth.authenticate(cfg.domain, token);
|
||||
|
||||
// Securely set httpOnly cookie on request to prevent XSS on frontend
|
||||
// And set path to / to enable thirdweb_auth_token usage on all endpoints
|
||||
res.setHeader(
|
||||
"Set-Cookie",
|
||||
serialize("thirdweb_auth_token", token, {
|
||||
path: "/",
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
sameSite: "strict",
|
||||
}),
|
||||
);
|
||||
|
||||
return { address };
|
||||
} catch (err) {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function nextOptions(
|
||||
req: GetServerSidePropsContext["req"],
|
||||
res: GetServerSidePropsContext["res"],
|
||||
): NextAuthOptions {
|
||||
async function session({
|
||||
session: _session,
|
||||
}: {
|
||||
session: Session;
|
||||
}): Promise<Session> {
|
||||
const token = req.cookies.thirdweb_auth_token || "";
|
||||
try {
|
||||
const address = await sdk.auth.authenticate(cfg.domain, token);
|
||||
_session.user = { ..._session.user, address } as Session["user"];
|
||||
return _session;
|
||||
} catch {
|
||||
return _session;
|
||||
}
|
||||
}
|
||||
|
||||
function signOut() {
|
||||
res.setHeader(
|
||||
"Set-Cookie",
|
||||
serialize("thirdweb_auth_token", "", {
|
||||
path: "/",
|
||||
expires: new Date(Date.now() + 5 * 1000),
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
const providers: NextAuthOptions["providers"] = [
|
||||
...cfg.nextOptions.providers,
|
||||
ThirdwebProvider(res),
|
||||
];
|
||||
|
||||
const configSession = cfg.nextOptions.callbacks?.session;
|
||||
const callbacks: NextAuthOptions["callbacks"] = {
|
||||
...cfg.nextOptions.callbacks,
|
||||
session: configSession
|
||||
? async (params) => {
|
||||
params.session = await session(params);
|
||||
return configSession(params);
|
||||
}
|
||||
: session,
|
||||
};
|
||||
|
||||
const configSignOut = cfg.nextOptions.events?.signOut;
|
||||
const events: NextAuthOptions["events"] = {
|
||||
...cfg.nextOptions.events,
|
||||
signOut: configSignOut
|
||||
? async (params) => {
|
||||
signOut();
|
||||
return configSignOut(params);
|
||||
}
|
||||
: signOut,
|
||||
};
|
||||
|
||||
return {
|
||||
...cfg.nextOptions,
|
||||
providers,
|
||||
callbacks,
|
||||
events,
|
||||
};
|
||||
}
|
||||
|
||||
async function getUser(
|
||||
...args:
|
||||
| [NextApiRequest, NextApiResponse]
|
||||
| [GetServerSidePropsContext["req"], GetServerSidePropsContext["res"]]
|
||||
) {
|
||||
return unstable_getServerSession(
|
||||
args[0],
|
||||
args[1],
|
||||
nextOptions(args[0], args[1]),
|
||||
);
|
||||
}
|
||||
|
||||
function NextAuthHandler(...args: [] | [NextApiRequest, NextApiResponse]) {
|
||||
if (args.length === 0) {
|
||||
return (req: NextApiRequest, res: NextApiResponse) => {
|
||||
return NextAuth(req, res, nextOptions(req, res));
|
||||
};
|
||||
}
|
||||
|
||||
return NextAuth(args[0], args[1], nextOptions(args[0], args[1]));
|
||||
}
|
||||
|
||||
return {
|
||||
NextAuthHandler,
|
||||
getUser,
|
||||
};
|
||||
}
|
||||
export * from "./evm";
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
import loginHandler from "./routes/login";
|
||||
import logoutHandler from "./routes/logout";
|
||||
import userHandler from "./routes/user";
|
||||
import {
|
||||
ThirdwebAuthConfig,
|
||||
ThirdwebAuthContext,
|
||||
ThirdwebAuthRoute,
|
||||
ThirdwebAuthUser,
|
||||
} from "./types";
|
||||
import { ThirdwebSDK } from "@thirdweb-dev/sdk";
|
||||
import { NextRequest } from "next/server";
|
||||
import {
|
||||
GetServerSidePropsContext,
|
||||
NextApiRequest,
|
||||
NextApiResponse,
|
||||
} from "next/types";
|
||||
|
||||
export * from "./types";
|
||||
|
||||
async function ThirdwebAuthRouter(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse,
|
||||
ctx: ThirdwebAuthContext,
|
||||
) {
|
||||
// Catch-all route must be named with [...thirdweb]
|
||||
const { thirdweb } = req.query;
|
||||
const action = thirdweb?.[0] as ThirdwebAuthRoute;
|
||||
|
||||
switch (action) {
|
||||
case "login":
|
||||
return await loginHandler(req, res, ctx);
|
||||
case "user":
|
||||
return await userHandler(req, res, ctx);
|
||||
case "logout":
|
||||
return await logoutHandler(req, res);
|
||||
default:
|
||||
return res.status(400).json({
|
||||
message: "Invalid route for authentication.",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function ThirdwebAuth(cfg: ThirdwebAuthConfig) {
|
||||
const ctx = {
|
||||
...cfg,
|
||||
sdk: ThirdwebSDK.fromPrivateKey(cfg.privateKey, "mainnet"),
|
||||
};
|
||||
|
||||
function ThirdwebAuthHandler(
|
||||
...args: [] | [NextApiRequest, NextApiResponse]
|
||||
) {
|
||||
if (args.length === 0) {
|
||||
return async (req: NextApiRequest, res: NextApiResponse) =>
|
||||
await ThirdwebAuthRouter(req, res, ctx);
|
||||
}
|
||||
|
||||
return ThirdwebAuthRouter(args[0], args[1], ctx);
|
||||
}
|
||||
|
||||
async function getUser(
|
||||
req: GetServerSidePropsContext["req"] | NextRequest | NextApiRequest,
|
||||
) {
|
||||
const { sdk, domain } = ctx;
|
||||
let user: ThirdwebAuthUser | null = null;
|
||||
const token =
|
||||
typeof req.cookies.get === "function"
|
||||
? (req.cookies as any).get("thirdweb_auth_token")
|
||||
: (req.cookies as any).thirdweb_auth_token;
|
||||
|
||||
if (token) {
|
||||
try {
|
||||
const address = await sdk.auth.authenticate(domain, token);
|
||||
user = { address };
|
||||
} catch {
|
||||
// No-op
|
||||
}
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
return { ThirdwebAuthHandler, getUser };
|
||||
}
|
||||
@@ -1,83 +1 @@
|
||||
import loginHandler from "./routes/login";
|
||||
import logoutHandler from "./routes/logout";
|
||||
import userHandler from "./routes/user";
|
||||
import {
|
||||
ThirdwebAuthConfig,
|
||||
ThirdwebAuthContext,
|
||||
ThirdwebAuthRoute,
|
||||
ThirdwebAuthUser,
|
||||
} from "./types";
|
||||
import { ThirdwebSDK } from "@thirdweb-dev/sdk";
|
||||
import { NextRequest } from "next/server";
|
||||
import {
|
||||
GetServerSidePropsContext,
|
||||
NextApiRequest,
|
||||
NextApiResponse,
|
||||
} from "next/types";
|
||||
|
||||
export * from "./types";
|
||||
|
||||
async function ThirdwebAuthRouter(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse,
|
||||
ctx: ThirdwebAuthContext,
|
||||
) {
|
||||
// Catch-all route must be named with [...thirdweb]
|
||||
const { thirdweb } = req.query;
|
||||
const action = thirdweb?.[0] as ThirdwebAuthRoute;
|
||||
|
||||
switch (action) {
|
||||
case "login":
|
||||
return await loginHandler(req, res, ctx);
|
||||
case "user":
|
||||
return await userHandler(req, res, ctx);
|
||||
case "logout":
|
||||
return await logoutHandler(req, res);
|
||||
default:
|
||||
return res.status(400).json({
|
||||
message: "Invalid route for authentication.",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function ThirdwebAuth(cfg: ThirdwebAuthConfig) {
|
||||
const ctx = {
|
||||
...cfg,
|
||||
sdk: ThirdwebSDK.fromPrivateKey(cfg.privateKey, "mainnet"),
|
||||
};
|
||||
|
||||
function ThirdwebAuthHandler(
|
||||
...args: [] | [NextApiRequest, NextApiResponse]
|
||||
) {
|
||||
if (args.length === 0) {
|
||||
return async (req: NextApiRequest, res: NextApiResponse) =>
|
||||
await ThirdwebAuthRouter(req, res, ctx);
|
||||
}
|
||||
|
||||
return ThirdwebAuthRouter(args[0], args[1], ctx);
|
||||
}
|
||||
|
||||
async function getUser(
|
||||
req: GetServerSidePropsContext["req"] | NextRequest | NextApiRequest,
|
||||
) {
|
||||
const { sdk, domain } = ctx;
|
||||
let user: ThirdwebAuthUser | null = null;
|
||||
const token =
|
||||
typeof req.cookies.get === "function"
|
||||
? (req.cookies as any).get("thirdweb_auth_token")
|
||||
: (req.cookies as any).thirdweb_auth_token;
|
||||
|
||||
if (token) {
|
||||
try {
|
||||
const address = await sdk.auth.authenticate(domain, token);
|
||||
user = { address };
|
||||
} catch {
|
||||
// No-op
|
||||
}
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
return { ThirdwebAuthHandler, getUser };
|
||||
}
|
||||
export * from "./evm";
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
import loginHandler from "./routes/login";
|
||||
import logoutHandler from "./routes/logout";
|
||||
import userHandler from "./routes/user";
|
||||
import {
|
||||
ThirdwebAuthConfig,
|
||||
ThirdwebAuthContext,
|
||||
ThirdwebAuthRoute,
|
||||
ThirdwebAuthUser,
|
||||
} from "./types";
|
||||
import { ThirdwebSDK } from "@thirdweb-dev/sdk/solana";
|
||||
import { NextRequest } from "next/server";
|
||||
import {
|
||||
GetServerSidePropsContext,
|
||||
NextApiRequest,
|
||||
NextApiResponse,
|
||||
} from "next/types";
|
||||
|
||||
export * from "./types";
|
||||
|
||||
async function ThirdwebAuthRouter(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse,
|
||||
ctx: ThirdwebAuthContext,
|
||||
) {
|
||||
// Catch-all route must be named with [...thirdweb]
|
||||
const { thirdweb } = req.query;
|
||||
const action = thirdweb?.[0] as ThirdwebAuthRoute;
|
||||
|
||||
switch (action) {
|
||||
case "login":
|
||||
return await loginHandler(req, res, ctx);
|
||||
case "user":
|
||||
return await userHandler(req, res, ctx);
|
||||
case "logout":
|
||||
return await logoutHandler(req, res);
|
||||
default:
|
||||
return res.status(400).json({
|
||||
message: "Invalid route for authentication.",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function ThirdwebAuth(cfg: ThirdwebAuthConfig) {
|
||||
const ctx = {
|
||||
...cfg,
|
||||
sdk: ThirdwebSDK.fromPrivateKey("mainnet-beta", cfg.privateKey),
|
||||
};
|
||||
|
||||
function ThirdwebAuthHandler(
|
||||
...args: [] | [NextApiRequest, NextApiResponse]
|
||||
) {
|
||||
if (args.length === 0) {
|
||||
return async (req: NextApiRequest, res: NextApiResponse) =>
|
||||
await ThirdwebAuthRouter(req, res, ctx);
|
||||
}
|
||||
|
||||
return ThirdwebAuthRouter(args[0], args[1], ctx);
|
||||
}
|
||||
|
||||
async function getUser(
|
||||
req: GetServerSidePropsContext["req"] | NextRequest | NextApiRequest,
|
||||
) {
|
||||
const { sdk, domain } = ctx;
|
||||
let user: ThirdwebAuthUser | null = null;
|
||||
const token =
|
||||
typeof req.cookies.get === "function"
|
||||
? (req.cookies as any).get("thirdweb_auth_token")
|
||||
: (req.cookies as any).thirdweb_auth_token;
|
||||
|
||||
if (token) {
|
||||
try {
|
||||
const address = await sdk.auth.authenticate(domain, token);
|
||||
user = { address };
|
||||
} catch {
|
||||
// No-op
|
||||
}
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
return { ThirdwebAuthHandler, getUser };
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
import { ThirdwebAuthContext } from "../types";
|
||||
import { LoginPayload } from "@thirdweb-dev/sdk";
|
||||
import { serialize } from "cookie";
|
||||
import { NextApiRequest, NextApiResponse } from "next";
|
||||
|
||||
function redirectWithError(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse,
|
||||
error: string,
|
||||
) {
|
||||
const encodedError = encodeURIComponent(error);
|
||||
const url = new URL(req.headers.referer as string);
|
||||
url.searchParams.set("error", encodedError);
|
||||
return res.redirect(url.toString());
|
||||
}
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse,
|
||||
ctx: ThirdwebAuthContext,
|
||||
) {
|
||||
if (req.method !== "GET") {
|
||||
return redirectWithError(req, res, "INVALID_METHOD");
|
||||
}
|
||||
|
||||
const { sdk, domain } = ctx;
|
||||
|
||||
// Get signed login payload from the frontend
|
||||
const payload = JSON.parse(atob(req.query.payload as string)) as LoginPayload;
|
||||
if (!payload) {
|
||||
redirectWithError(req, res, "MISSING_LOGIN_PAYLOAD");
|
||||
}
|
||||
|
||||
let token;
|
||||
try {
|
||||
// Generate an access token with the SDK using the signed payload
|
||||
token = await sdk.auth.generateAuthToken(domain, payload);
|
||||
} catch {
|
||||
return redirectWithError(req, res, "INVALID_LOGIN_PAYLOAD");
|
||||
}
|
||||
|
||||
// Securely set httpOnly cookie on request to prevent XSS on frontend
|
||||
// And set path to / to enable thirdweb_auth_token usage on all endpoints
|
||||
res.setHeader(
|
||||
"Set-Cookie",
|
||||
serialize("thirdweb_auth_token", token, {
|
||||
path: "/",
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
sameSite: "strict",
|
||||
}),
|
||||
);
|
||||
|
||||
if (ctx.callbacks?.login) {
|
||||
const address = sdk.auth.verify(domain, payload);
|
||||
await ctx.callbacks.login(address);
|
||||
}
|
||||
|
||||
return res.status(301).redirect(req.query.redirect as string);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import { serialize } from "cookie";
|
||||
import { NextApiRequest, NextApiResponse } from "next";
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse,
|
||||
) {
|
||||
if (req.method !== "GET") {
|
||||
return res.status(400).json({
|
||||
error: "Invalid method. Only GET supported.",
|
||||
});
|
||||
}
|
||||
|
||||
// Set the access token to 'none' and expire in 5 seconds
|
||||
res.setHeader(
|
||||
"Set-Cookie",
|
||||
serialize("thirdweb_auth_token", "", {
|
||||
path: "/",
|
||||
expires: new Date(Date.now() + 5 * 1000),
|
||||
}),
|
||||
);
|
||||
|
||||
return res.status(301).redirect(req.headers.referer as string);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import { ThirdwebAuthContext, ThirdwebAuthUser } from "../types";
|
||||
import { NextApiRequest, NextApiResponse } from "next";
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse,
|
||||
ctx: ThirdwebAuthContext,
|
||||
) {
|
||||
if (req.method !== "GET") {
|
||||
return res.status(400).json({
|
||||
error: "Invalid method. Only GET supported.",
|
||||
});
|
||||
}
|
||||
|
||||
const { sdk, domain } = ctx;
|
||||
let user = null;
|
||||
const token = req.cookies.thirdweb_auth_token;
|
||||
|
||||
if (token) {
|
||||
try {
|
||||
const address = await sdk.auth.authenticate(domain, token);
|
||||
|
||||
if (ctx.callbacks?.user) {
|
||||
user = await ctx.callbacks.user(address);
|
||||
}
|
||||
|
||||
user = { ...user, address };
|
||||
} catch {
|
||||
// No-op
|
||||
}
|
||||
}
|
||||
|
||||
return res.status(200).json(user as ThirdwebAuthUser | null);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import { ThirdwebSDK } from "@thirdweb-dev/sdk/solana";
|
||||
|
||||
export type ThirdwebAuthRoute = "login" | "logout" | "user";
|
||||
|
||||
export type ThirdwebAuthConfig = {
|
||||
privateKey: string;
|
||||
domain: string;
|
||||
callbacks?: {
|
||||
login?: (address: string) => Promise<void> | void;
|
||||
user?: (
|
||||
address: string,
|
||||
) =>
|
||||
| Promise<Omit<ThirdwebAuthUser, "address">>
|
||||
| Omit<ThirdwebAuthUser, "address">;
|
||||
};
|
||||
};
|
||||
|
||||
export type ThirdwebAuthContext = {
|
||||
sdk: ThirdwebSDK;
|
||||
domain: string;
|
||||
callbacks?: {
|
||||
login?: (address: string) => Promise<void> | void;
|
||||
user?: (
|
||||
address: string,
|
||||
) =>
|
||||
| Promise<Omit<ThirdwebAuthUser, "address">>
|
||||
| Omit<ThirdwebAuthUser, "address">;
|
||||
};
|
||||
};
|
||||
|
||||
export type ThirdwebAuthUser = {
|
||||
address: string;
|
||||
[key: string]: any;
|
||||
};
|
||||
@@ -1,5 +1,61 @@
|
||||
# thirdweb
|
||||
|
||||
## 0.8.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`712b11a`](https://github.com/thirdweb-dev/js/commit/712b11a43e389ae10b7f09648779a69c05b2c913)]:
|
||||
- @thirdweb-dev/sdk@3.2.5
|
||||
|
||||
## 0.8.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @thirdweb-dev/sdk@3.2.4
|
||||
|
||||
## 0.8.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @thirdweb-dev/sdk@3.2.3
|
||||
|
||||
## 0.8.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#276](https://github.com/thirdweb-dev/js/pull/276) [`24514a6`](https://github.com/thirdweb-dev/js/commit/24514a6e9fc1316622c1494e5be225e53f88d26e) Thanks [@furqanrydhan](https://github.com/furqanrydhan)! - build is now default compile command, reorganized the help list
|
||||
|
||||
- [#279](https://github.com/thirdweb-dev/js/pull/279) [`1918495`](https://github.com/thirdweb-dev/js/commit/1918495f2ee7f50d94083d9577dab0bf1c828c94) Thanks [@furqanrydhan](https://github.com/furqanrydhan)! - Updating command list order, helper text and changed detect -> build
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#277](https://github.com/thirdweb-dev/js/pull/277) [`9de3f8c`](https://github.com/thirdweb-dev/js/commit/9de3f8c8e954733bfc3eb6e8e0e786ff5b296f0c) Thanks [@adam-maj](https://github.com/adam-maj)! - Add recursive folder upload support
|
||||
|
||||
- [#268](https://github.com/thirdweb-dev/js/pull/268) [`57b9c67`](https://github.com/thirdweb-dev/js/commit/57b9c671aaf7fce0076dd332c171ba6944752e7a) Thanks [@adam-maj](https://github.com/adam-maj)! - Update storage upload cLI
|
||||
|
||||
- Updated dependencies [[`521a49c`](https://github.com/thirdweb-dev/js/commit/521a49c6ec6a73068adcfbc1d94d2f3f17afae86), [`8b3b97c`](https://github.com/thirdweb-dev/js/commit/8b3b97c8f7b3710ce62ed86cfeb4f6de3c23d559), [`25a4773`](https://github.com/thirdweb-dev/js/commit/25a4773bba406f4e270ac86e68c5266d24c08330), [`b2cadf1`](https://github.com/thirdweb-dev/js/commit/b2cadf164cfe9fb27081df7530356baf70ec2b3a), [`d6bb61b`](https://github.com/thirdweb-dev/js/commit/d6bb61b7fac759fff7d6293edd46f693f5a7889c), [`78d6d3c`](https://github.com/thirdweb-dev/js/commit/78d6d3c15968a449924b3f24354e151a90e4b20d), [`89d87a5`](https://github.com/thirdweb-dev/js/commit/89d87a5eb31e78e68e097718e9ae6e4c4d101868), [`41507d3`](https://github.com/thirdweb-dev/js/commit/41507d32a78c556f50c88de81c4d6109b1783c78), [`8096c78`](https://github.com/thirdweb-dev/js/commit/8096c78b466a7f5f9c2aac6e2c56a06f9d3a25d6), [`b1fa171`](https://github.com/thirdweb-dev/js/commit/b1fa17158dcac00265bc8f4d64f1f9708482cdb5), [`18381fa`](https://github.com/thirdweb-dev/js/commit/18381fac73741826934212ac6441842ed42a64a0), [`df048af`](https://github.com/thirdweb-dev/js/commit/df048af605f449279b01d7352b604e7856ac223c), [`d6bb61b`](https://github.com/thirdweb-dev/js/commit/d6bb61b7fac759fff7d6293edd46f693f5a7889c), [`cf88795`](https://github.com/thirdweb-dev/js/commit/cf88795376d3110f9d3aa839928d22276904b15a), [`89b5c6f`](https://github.com/thirdweb-dev/js/commit/89b5c6fe079e4df2cf12cb557aa9784f88c5d159)]:
|
||||
- @thirdweb-dev/sdk@3.2.2
|
||||
|
||||
## 0.7.24
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#259](https://github.com/thirdweb-dev/js/pull/259) [`6f95a52`](https://github.com/thirdweb-dev/js/commit/6f95a520e6cc69e08f734705e8adc71431b091cc) Thanks [@adam-maj](https://github.com/adam-maj)! - Add npx thirdweb upload command
|
||||
|
||||
- Updated dependencies []:
|
||||
- @thirdweb-dev/sdk@3.2.1
|
||||
|
||||
## 0.7.23
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#246](https://github.com/thirdweb-dev/js/pull/246) [`ef0bac7`](https://github.com/thirdweb-dev/js/commit/ef0bac7f44b93939bfc9e2706b39edaa22992eec) Thanks [@simonlim94](https://github.com/simonlim94)! - Renamed initial commit message during thirdweb cli createApp
|
||||
|
||||
- Updated dependencies [[`ba6f450`](https://github.com/thirdweb-dev/js/commit/ba6f45027a6ec11aebb4a1918ab2ba4f88894ede), [`c8261b7`](https://github.com/thirdweb-dev/js/commit/c8261b74b5828ac66ea3a6d7636aa57e40ea1a14), [`20745f8`](https://github.com/thirdweb-dev/js/commit/20745f8cd603235eb5039e61a39c0959c5860bca), [`2ea3f00`](https://github.com/thirdweb-dev/js/commit/2ea3f00c41b5e70d9bb634cd86790890520fc4d6), [`9412d41`](https://github.com/thirdweb-dev/js/commit/9412d416832c87ab2c858cb120c6c5de03459c50), [`d677e9d`](https://github.com/thirdweb-dev/js/commit/d677e9d6341252013762882d25408ea8f93791e5), [`e662408`](https://github.com/thirdweb-dev/js/commit/e662408e1936983485936609552f80a56cbed082), [`e4b10bc`](https://github.com/thirdweb-dev/js/commit/e4b10bc5bd12178cba8856b60255732123cb7ae5), [`caf9795`](https://github.com/thirdweb-dev/js/commit/caf979537b5acb1610f182c94afa5d95c208ec3f), [`028cb78`](https://github.com/thirdweb-dev/js/commit/028cb781252b0050943b14cfdf38132c18753a4b), [`1972f3e`](https://github.com/thirdweb-dev/js/commit/1972f3ec0d511fbc17642b2a30852a177092a09e), [`6647f70`](https://github.com/thirdweb-dev/js/commit/6647f707bdd050725264a8a74220c11912f68e57), [`cac373b`](https://github.com/thirdweb-dev/js/commit/cac373b010ce3be3615a36671b66815a27785061)]:
|
||||
- @thirdweb-dev/sdk@3.2.0
|
||||
|
||||
## 0.7.22
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "thirdweb",
|
||||
"main": "dist/cli/index.js",
|
||||
"version": "0.7.22",
|
||||
"version": "0.8.3",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/cli",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
#!/usr/bin/env node
|
||||
import { installGithubAction } from "../common/ci-installer";
|
||||
import { detectExtensions } from "../common/feature-detector";
|
||||
import { processProject } from "../common/processor";
|
||||
import { cliVersion, pkg } from "../constants/urls";
|
||||
import { info, logger } from "../core/helpers/logger";
|
||||
import { twCreate } from "../create/command";
|
||||
import generateDashboardUrl from "../helpers/generate-dashboard-url";
|
||||
import { upload } from "../storage/command";
|
||||
import { ThirdwebStorage } from "@thirdweb-dev/storage";
|
||||
import chalk from "chalk";
|
||||
import { Command } from "commander";
|
||||
import open from "open";
|
||||
@@ -41,10 +42,10 @@ $$$$$$\\ $$$$$$$\\ $$\\ $$$$$$\\ $$$$$$$ |$$\\ $$\\ $$\\ $$$$$$\\ $$$$
|
||||
program
|
||||
.command("create")
|
||||
.description(
|
||||
"Create a thirdweb app from any of our official templates. Checkout some examples you can use here: https://github.com/thirdweb-example/",
|
||||
"Create a web3 app from any of our official templates: https://github.com/thirdweb-example/",
|
||||
)
|
||||
.option("--app", `Create a thirdweb app.`)
|
||||
.option("--contract", `Create a thirdweb contracts project.`)
|
||||
.option("--app", `Create a web3 app.`)
|
||||
.option("--contract", `Create a web3 contract project`)
|
||||
.option("--ts, --typescript", `Initialize as a TypeScript project.`)
|
||||
.option("--js, --javascript", `Initialize as a JavaScript project.`)
|
||||
.option("--forge", `Initialize as a Forge project.`)
|
||||
@@ -69,11 +70,19 @@ $$$$$$\\ $$$$$$$\\ $$\\ $$$$$$\\ $$$$$$$ |$$\\ $$\\ $$\\ $$$$$$\\ $$$$
|
||||
await twCreate(options);
|
||||
});
|
||||
|
||||
program
|
||||
.command("build")
|
||||
.description("Compile contract and detect thirdweb contract extensions")
|
||||
.option("-p, --path <project-path>", "path to project", ".")
|
||||
.option("-d, --debug", "show debug logs")
|
||||
.option("-a, --all", "run detection on all contracts")
|
||||
.action(async (options) => {
|
||||
await detectExtensions(options);
|
||||
});
|
||||
|
||||
program
|
||||
.command("deploy")
|
||||
.description(
|
||||
"Deploy contracts through your thirdweb dashboard, without dealing with private keys.",
|
||||
)
|
||||
.description("Deploy your (or team) contracts securely to blockchains")
|
||||
.option("-p, --path <project-path>", "path to project", ".")
|
||||
.option("--dry-run", "dry run (skip actually publishing)")
|
||||
.option("-d, --debug", "show debug logs")
|
||||
@@ -116,7 +125,7 @@ $$$$$$\\ $$$$$$$\\ $$\\ $$$$$$\\ $$$$$$$ |$$\\ $$\\ $$\\ $$$$$$\\ $$$$
|
||||
program
|
||||
.command("release")
|
||||
.description(
|
||||
"Release contracts, making them available for others to deploy and unlocking SDKs, Dashboards and Analytics.",
|
||||
"Release your protocol so other devs can deploy them and unlock SDKs, Dashboards and Analytics",
|
||||
)
|
||||
.option("-p, --path <project-path>", "path to project", ".")
|
||||
.option("--dry-run", "dry run (skip actually publishing)")
|
||||
@@ -129,10 +138,25 @@ $$$$$$\\ $$$$$$$\\ $$\\ $$$$$$\\ $$$$$$$ |$$\\ $$\\ $$\\ $$$$$$\\ $$$$
|
||||
open(url.toString());
|
||||
});
|
||||
|
||||
program
|
||||
.command("upload")
|
||||
.description("Upload any file or directory to decentralized storage (IPFS)")
|
||||
.argument("[upload]", "path to file or directory to upload")
|
||||
.action(async (path) => {
|
||||
const storage = new ThirdwebStorage();
|
||||
const uri = await upload(storage, path);
|
||||
info(`Files stored at the following IPFS URI:`);
|
||||
logger.info(chalk.blueBright(uri.toString()));
|
||||
|
||||
const url = storage.resolveScheme(uri);
|
||||
info(`Open this link to view your upload:`);
|
||||
logger.info(chalk.blueBright(url.toString()));
|
||||
});
|
||||
|
||||
program
|
||||
.command("detect")
|
||||
.description(
|
||||
"Compile contracts and detect implemented thirdweb contract extensions",
|
||||
"(deprecated) Compile contracts and detect implemented thirdweb contract extensions",
|
||||
)
|
||||
.option("-p, --path <project-path>", "path to project", ".")
|
||||
.option("-d, --debug", "show debug logs")
|
||||
@@ -141,15 +165,6 @@ $$$$$$\\ $$$$$$$\\ $$\\ $$$$$$\\ $$$$$$$ |$$\\ $$\\ $$\\ $$$$$$\\ $$$$
|
||||
await detectExtensions(options);
|
||||
});
|
||||
|
||||
program
|
||||
.command("install-ci")
|
||||
.description(
|
||||
"(alpha) Set up continuous integration for your contracts. This adds a github action to deploy the project on pull requests and pushes to branches. Publishes on push the the main branch.",
|
||||
)
|
||||
.action(async (options) => {
|
||||
await installGithubAction(options);
|
||||
});
|
||||
|
||||
await program.parseAsync();
|
||||
};
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ export function tryGitInit(root: string): boolean {
|
||||
execSync("git checkout -b main", { stdio: "ignore" });
|
||||
|
||||
execSync("git add -A", { stdio: "ignore" });
|
||||
execSync('git commit -m "Initial commit from Create thirdweb app"', {
|
||||
execSync('git commit -m "Initial commit from npx thirdweb create"', {
|
||||
stdio: "ignore",
|
||||
});
|
||||
return true;
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
import { logger } from "../core/helpers/logger";
|
||||
import { spinner } from "../core/helpers/logger";
|
||||
import { BufferOrStringWithName, ThirdwebStorage } from "@thirdweb-dev/storage";
|
||||
import chalk from "chalk";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
|
||||
function recurseFiles(
|
||||
uploadPath: string,
|
||||
basePath: string,
|
||||
): BufferOrStringWithName[] {
|
||||
const files = [];
|
||||
|
||||
const fileType = fs.lstatSync(uploadPath);
|
||||
if (fileType.isFile()) {
|
||||
const fileName = path.relative(basePath, uploadPath);
|
||||
const fileData = fs.readFileSync(uploadPath);
|
||||
files.push({ name: fileName, data: fileData });
|
||||
} else if (fileType.isDirectory()) {
|
||||
const paths = fs.readdirSync(uploadPath);
|
||||
paths.forEach((subPath) => {
|
||||
const fullSubPath = path.join(uploadPath, subPath);
|
||||
const subFiles = recurseFiles(fullSubPath, basePath);
|
||||
subFiles.forEach((file) => files.push(file));
|
||||
});
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
export async function upload(
|
||||
storage: ThirdwebStorage,
|
||||
uploadPath: string,
|
||||
): Promise<string> {
|
||||
if (!uploadPath) {
|
||||
logger.error(
|
||||
`Please pass a path to a file or directory to upload with the following format:\n ${chalk.blueBright(
|
||||
`npx thirdweb@latest upload path/to/file.jpg`,
|
||||
)}\n`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const pathExists = fs.existsSync(uploadPath);
|
||||
if (!pathExists) {
|
||||
logger.error(
|
||||
`Invalid path ${chalk.blueBright(
|
||||
uploadPath,
|
||||
)} provided. Please provide a valid path to a file or directory to upload."`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
let uri = "";
|
||||
const fileType = fs.lstatSync(uploadPath);
|
||||
if (fileType.isDirectory()) {
|
||||
const files = recurseFiles(uploadPath, uploadPath);
|
||||
|
||||
if (files.length === 0) {
|
||||
logger.error(
|
||||
`No files detected in specified directory ${chalk.blueBright(
|
||||
uploadPath,
|
||||
)} to upload.`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const spin = spinner(
|
||||
"Uploading directory to IPFS. This may take a while depending on file sizes.",
|
||||
);
|
||||
const uris = await storage.uploadBatch(files);
|
||||
spin.succeed("Successfully uploaded directory to IPFS");
|
||||
uri = uris[0].substring(0, uris[0].lastIndexOf("/"));
|
||||
} else if (fileType.isFile()) {
|
||||
const fileName = path.parse(uploadPath).base;
|
||||
const fileData = fs.readFileSync(uploadPath);
|
||||
const file = { name: fileName, data: fileData };
|
||||
|
||||
const spin = spinner(
|
||||
"Uploading file to IPFS. This may take a while depending on file sizes.",
|
||||
);
|
||||
uri = await storage.upload(file, { uploadWithoutDirectory: true });
|
||||
spin.succeed("Succesfully uploaded file to IPFS.");
|
||||
} else {
|
||||
logger.error(
|
||||
`Path ${chalk.blueBright(
|
||||
uploadPath,
|
||||
)} does not point to a valid file or directory. Please provide a valid path to a file or directory to upload`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
return uri;
|
||||
}
|
||||
@@ -12,6 +12,7 @@
|
||||
"@babel/preset-env": "^7.18.10",
|
||||
"@babel/preset-typescript": "^7.18.6",
|
||||
"@preconstruct/cli": "^2.2.1",
|
||||
"@typechain/ethers-v5": "10.0.0",
|
||||
"ethers": "^5.7.0",
|
||||
"typechain": "^8.1.0",
|
||||
"typescript": "^4.7.4"
|
||||
|
||||
@@ -5,3 +5,8 @@ node_modules/
|
||||
/test-results/
|
||||
/playwright-report/
|
||||
/playwright/.cache/
|
||||
etc/
|
||||
temp/
|
||||
temp-evm/
|
||||
temp-solana/
|
||||
docs/
|
||||
@@ -1,5 +1,74 @@
|
||||
# @thirdweb-dev/react
|
||||
|
||||
## 3.2.5
|
||||
|
||||
## 3.2.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#301](https://github.com/thirdweb-dev/js/pull/301) [`86f0cef`](https://github.com/thirdweb-dev/js/commit/86f0ceff46f72df8ebd81f843e3c66a245f23992) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Remove useAddress hook for now
|
||||
|
||||
## 3.2.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#299](https://github.com/thirdweb-dev/js/pull/299) [`b1218cb`](https://github.com/thirdweb-dev/js/commit/b1218cbd7d97ca7949d94a7e4ab93fef4ffbacd5) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Recreate SDK on wallet changes for hook propagation
|
||||
|
||||
## 3.2.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#289](https://github.com/thirdweb-dev/js/pull/289) [`521a49c`](https://github.com/thirdweb-dev/js/commit/521a49c6ec6a73068adcfbc1d94d2f3f17afae86) Thanks [@nachoiacovino](https://github.com/nachoiacovino)! - Standarize useClaimNFT to evm
|
||||
|
||||
- [#274](https://github.com/thirdweb-dev/js/pull/274) [`ad06c5b`](https://github.com/thirdweb-dev/js/commit/ad06c5b28902422f9b416d65255c64c937a5e046) Thanks [@adam-maj](https://github.com/adam-maj)! - Add solana auth support and plugins for react and auth package
|
||||
|
||||
- [#269](https://github.com/thirdweb-dev/js/pull/269) [`b2cadf1`](https://github.com/thirdweb-dev/js/commit/b2cadf164cfe9fb27081df7530356baf70ec2b3a) Thanks [@jnsdls](https://github.com/jnsdls)! - [EVM] - remove deprecated chains from support
|
||||
|
||||
- [#272](https://github.com/thirdweb-dev/js/pull/272) [`2bdf198`](https://github.com/thirdweb-dev/js/commit/2bdf1984cb97121c447cffd27aa6a5f4f92679b3) Thanks [@nachoiacovino](https://github.com/nachoiacovino)! - Add claim conditions hook for Solana
|
||||
|
||||
- [#291](https://github.com/thirdweb-dev/js/pull/291) [`86f6083`](https://github.com/thirdweb-dev/js/commit/86f608390a7848cda82c0f7e8913ca60f7d3901f) Thanks [@jnsdls](https://github.com/jnsdls)! - [SOL] - expose `.program` on `useProgram()` return type to mirror `.contract` on EVM
|
||||
|
||||
- [#292](https://github.com/thirdweb-dev/js/pull/292) [`492a818`](https://github.com/thirdweb-dev/js/commit/492a818079aff67c7f88bc43666c87c3714cc957) Thanks [@jnsdls](https://github.com/jnsdls)! - [SOL] expose `useAddress()` hook that returns the connected wallet address in base58
|
||||
|
||||
- [#290](https://github.com/thirdweb-dev/js/pull/290) [`8096c78`](https://github.com/thirdweb-dev/js/commit/8096c78b466a7f5f9c2aac6e2c56a06f9d3a25d6) Thanks [@jnsdls](https://github.com/jnsdls)! - [SOL] - `useClaimNFT()` allow claiming to connected wallet without passing address explicitly
|
||||
[EVM] - `useClaimNFT()` allow claiming to connected wallet without passing address explicitly
|
||||
|
||||
- [#298](https://github.com/thirdweb-dev/js/pull/298) [`e8c25ed`](https://github.com/thirdweb-dev/js/commit/e8c25ed0f28d566203d70bf59a8908e59216334a) Thanks [@jnsdls](https://github.com/jnsdls)! - [SOL] - fix useBalance
|
||||
|
||||
- [#263](https://github.com/thirdweb-dev/js/pull/263) [`d6bb61b`](https://github.com/thirdweb-dev/js/commit/d6bb61b7fac759fff7d6293edd46f693f5a7889c) Thanks [@jnsdls](https://github.com/jnsdls)! - [EVM] - add chainId getter on contracts
|
||||
|
||||
- [#266](https://github.com/thirdweb-dev/js/pull/266) [`3b7d10e`](https://github.com/thirdweb-dev/js/commit/3b7d10ed93d8e3b698e9f905c93ba79863b35325) Thanks [@adam-maj](https://github.com/adam-maj)! - Add storage hooks to react
|
||||
|
||||
- [#282](https://github.com/thirdweb-dev/js/pull/282) [`1f41adb`](https://github.com/thirdweb-dev/js/commit/1f41adbd2ccfbc367757620e0842ef32bc783a08) Thanks [@jarrodwatts](https://github.com/jarrodwatts)! - Fix useActiveClaimCondition invariant failing for token ID 0
|
||||
|
||||
- [#296](https://github.com/thirdweb-dev/js/pull/296) [`cf88795`](https://github.com/thirdweb-dev/js/commit/cf88795376d3110f9d3aa839928d22276904b15a) Thanks [@jnsdls](https://github.com/jnsdls)! - [SOL] - add `useBalance` hook
|
||||
|
||||
## 3.2.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#264](https://github.com/thirdweb-dev/js/pull/264) [`f669d3e`](https://github.com/thirdweb-dev/js/commit/f669d3ef4a84368c23f0359aec304f66a4063042) Thanks [@nachoiacovino](https://github.com/nachoiacovino)! - Standarize data between evm/solana for useLazyMint hook
|
||||
|
||||
## 3.2.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#261](https://github.com/thirdweb-dev/js/pull/261) [`c8261b7`](https://github.com/thirdweb-dev/js/commit/c8261b74b5828ac66ea3a6d7636aa57e40ea1a14) Thanks [@jnsdls](https://github.com/jnsdls)! - [EVM] - align behavior of `useContract()` and `getContract()` across react & sdk to both allow passing optional second params of contract types or ABIs
|
||||
|
||||
- [#236](https://github.com/thirdweb-dev/js/pull/236) [`cac373b`](https://github.com/thirdweb-dev/js/commit/cac373b010ce3be3615a36671b66815a27785061) Thanks [@jnsdls](https://github.com/jnsdls)! - [SOL] - do not require a connection, instead handle a network directly
|
||||
|
||||
- [#251](https://github.com/thirdweb-dev/js/pull/251) [`ea41231`](https://github.com/thirdweb-dev/js/commit/ea41231b3ec4a2aef6a203db195d0e450c45ef56) Thanks [@jnsdls](https://github.com/jnsdls)! - fix missing Buffer implementation for WalletConnect and CoinbaseWallet connectors
|
||||
|
||||
- [#253](https://github.com/thirdweb-dev/js/pull/253) [`b6fc298`](https://github.com/thirdweb-dev/js/commit/b6fc298d0cf63bc7129104f7779cc9d84e405093) Thanks [@jnsdls](https://github.com/jnsdls)! - [EVM] - allow passing contractType as second param to `useContract()`
|
||||
|
||||
- [#243](https://github.com/thirdweb-dev/js/pull/243) [`1136d95`](https://github.com/thirdweb-dev/js/commit/1136d959baf936c166e5f7c051d5173d68d9eb9b) Thanks [@jnsdls](https://github.com/jnsdls)! - fix persister logic
|
||||
|
||||
- [#258](https://github.com/thirdweb-dev/js/pull/258) [`ac232b5`](https://github.com/thirdweb-dev/js/commit/ac232b5affe31780ef1c10ec76edb21596850e7e) Thanks [@nachoiacovino](https://github.com/nachoiacovino)! - Accept SmartContract instead of erc20 instance
|
||||
|
||||
- [#245](https://github.com/thirdweb-dev/js/pull/245) [`1972f3e`](https://github.com/thirdweb-dev/js/commit/1972f3ec0d511fbc17642b2a30852a177092a09e) Thanks [@jnsdls](https://github.com/jnsdls)! - [SOL] - expose `useBurnNFT` hook
|
||||
|
||||
- [#255](https://github.com/thirdweb-dev/js/pull/255) [`9b92697`](https://github.com/thirdweb-dev/js/commit/9b92697fb77d3072e3e53b451f9b348595ae410e) Thanks [@jnsdls](https://github.com/jnsdls)! - [EVM] - `useContract()` and `<Web3Button />` can now accept an optional ABI directly and will return a `SmartContract` based on it
|
||||
|
||||
## 3.1.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -71,7 +71,7 @@ Below are examples of where to set this up in your application:
|
||||
|
||||
### Connect to a User's Wallet
|
||||
|
||||
Now the provider is set up, we can use all of the hooks and UI components available in the SDK, such as the [ConnectWallet](https://portal.thirdweb.com/sdk/ui-components/connectwalletbutton) component.
|
||||
Now the provider is set up, we can use all of the hooks and UI components available in the SDK, such as the [ConnectWallet](https://portal.thirdweb.com/ui-components/connectwalletbutton) component.
|
||||
|
||||
Once the user has connected their wallet, all the calls we make to interact with contracts using the SDK will be on behalf of the user.
|
||||
|
||||
@@ -143,7 +143,7 @@ Each [extension](https://portal.thirdweb.com/extensions) you implement in your s
|
||||
|
||||
These hooks make it easy to interact with your smart contracts by implementing the complex logic for you under the hood.
|
||||
|
||||
For example, if your smart contract implements [ERC721Supply](https://portal.thirdweb.com/extensions/erc721supply#unlocked-features), you unlock the ability to [view all NFTs](https://portal.thirdweb.com/sdk/interacting-with-contracts/erc721supply#get-all-minted-nfts) on that contract using the SDK; which fetches all of your NFT metadata and the current owner of each NFT in parallel. In the React SDK, that is available using `useNFTs`:
|
||||
For example, if your smart contract implements [ERC721Supply](https://portal.thirdweb.com/contractkit/interfaces/erc721supply#unlocked-features), you unlock the ability to [view all NFTs](https://portal.thirdweb.com/sdk/interacting-with-contracts/erc721supply#get-all-minted-nfts) on that contract using the SDK; which fetches all of your NFT metadata and the current owner of each NFT in parallel. In the React SDK, that is available using `useNFTs`:
|
||||
|
||||
```jsx
|
||||
import { useContract, useNFTs } from "@thirdweb-dev/react";
|
||||
@@ -154,7 +154,7 @@ export default function Home() {
|
||||
}
|
||||
```
|
||||
|
||||
If we want to mint an NFT and our contract implements [ERC721Mintable](https://portal.thirdweb.com/extensions/erc721mintable#unlocked-features), we can use the [`useMintNFT`](https://portal.thirdweb.com/sdk/interacting-with-contracts/erc721mintable) hook to mint an NFT from the connected wallet; handling all of the logic of uploading and pinning the metadata to IPFS for us behind the scenes.
|
||||
If we want to mint an NFT and our contract implements [ERC721Mintable](https://portal.thirdweb.com/contractkit/interfaces/erc721mintable#unlocked-features), we can use the [`useMintNFT`](https://portal.thirdweb.com/sdk/interacting-with-contracts/erc721mintable) hook to mint an NFT from the connected wallet; handling all of the logic of uploading and pinning the metadata to IPFS for us behind the scenes.
|
||||
|
||||
```jsx
|
||||
import { useContract, useNFTs, useMintNFT } from "@thirdweb-dev/react";
|
||||
@@ -172,7 +172,7 @@ export default function Home() {
|
||||
|
||||
The SDK provides many UI components to help you build your application.
|
||||
|
||||
For example, we can render each of the NFTs using the [`NFT Media Renderer`](https://portal.thirdweb.com/sdk/ui-components/nft-renderer)
|
||||
For example, we can render each of the NFTs using the [`NFT Media Renderer`](https://portal.thirdweb.com/ui-components/nft-renderer)
|
||||
component, making use of the loading state from `useNFTs`:
|
||||
|
||||
```jsx title="pages/index.jsx"
|
||||
@@ -203,7 +203,7 @@ export default function Home() {
|
||||
}
|
||||
```
|
||||
|
||||
The [`Web3Button`](https://portal.thirdweb.com/sdk/ui-components/web3button) component ensures the user has connected their wallet and is currently configured to the same network as your smart contract before calling the function. It also has access to the `contract` directly, allowing you to perform any action on your smart contract when the button is clicked.
|
||||
The [`Web3Button`](https://portal.thirdweb.com/ui-components/web3button) component ensures the user has connected their wallet and is currently configured to the same network as your smart contract before calling the function. It also has access to the `contract` directly, allowing you to perform any action on your smart contract when the button is clicked.
|
||||
|
||||
For example, we can mint an NFT like so:
|
||||
|
||||
|
||||
@@ -0,0 +1,342 @@
|
||||
/**
|
||||
* Config file for API Extractor. For more info, please visit: https://api-extractor.com
|
||||
*/
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
|
||||
/**
|
||||
* Optionally specifies another JSON config file that this file extends from. This provides a way for
|
||||
* standard settings to be shared across multiple projects.
|
||||
*
|
||||
* If the path starts with "./" or "../", the path is resolved relative to the folder of the file that contains
|
||||
* the "extends" field. Otherwise, the first path segment is interpreted as an NPM package name, and will be
|
||||
* resolved using NodeJS require().
|
||||
*
|
||||
* SUPPORTED TOKENS: none
|
||||
* DEFAULT VALUE: ""
|
||||
*/
|
||||
// "extends": "./shared/api-extractor-base.json"
|
||||
// "extends": "my-package/include/api-extractor-base.json"
|
||||
/**
|
||||
* Determines the "<projectFolder>" token that can be used with other config file settings. The project folder
|
||||
* typically contains the tsconfig.json and package.json config files, but the path is user-defined.
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting.
|
||||
*
|
||||
* The default value for "projectFolder" is the token "<lookup>", which means the folder is determined by traversing
|
||||
* parent folders, starting from the folder containing api-extractor.json, and stopping at the first folder
|
||||
* that contains a tsconfig.json file. If a tsconfig.json file cannot be found in this way, then an error
|
||||
* will be reported.
|
||||
*
|
||||
* SUPPORTED TOKENS: <lookup>
|
||||
* DEFAULT VALUE: "<lookup>"
|
||||
*/
|
||||
// "projectFolder": "..",
|
||||
/**
|
||||
* (REQUIRED) Specifies the .d.ts file to be used as the starting point for analysis. API Extractor
|
||||
* analyzes the symbols exported by this module.
|
||||
*
|
||||
* The file extension must be ".d.ts" and not ".ts".
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as "<projectFolder>".
|
||||
*
|
||||
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
|
||||
*/
|
||||
"mainEntryPointFilePath": "<projectFolder>/solana/dist/thirdweb-dev-react-solana.cjs.d.ts",
|
||||
/**
|
||||
* A list of NPM package names whose exports should be treated as part of this package.
|
||||
*
|
||||
* For example, suppose that Webpack is used to generate a distributed bundle for the project "library1",
|
||||
* and another NPM package "library2" is embedded in this bundle. Some types from library2 may become part
|
||||
* of the exported API for library1, but by default API Extractor would generate a .d.ts rollup that explicitly
|
||||
* imports library2. To avoid this, we can specify:
|
||||
*
|
||||
* "bundledPackages": [ "library2" ],
|
||||
*
|
||||
* This would direct API Extractor to embed those types directly in the .d.ts rollup, as if they had been
|
||||
* local files for library1.
|
||||
*/
|
||||
"bundledPackages": [
|
||||
"wagmi",
|
||||
"wagmi-core"
|
||||
],
|
||||
/**
|
||||
* Determines how the TypeScript compiler engine will be invoked by API Extractor.
|
||||
*/
|
||||
"compiler": {
|
||||
/**
|
||||
* Specifies the path to the tsconfig.json file to be used by API Extractor when analyzing the project.
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as "<projectFolder>".
|
||||
*
|
||||
* Note: This setting will be ignored if "overrideTsconfig" is used.
|
||||
*
|
||||
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
|
||||
* DEFAULT VALUE: "<projectFolder>/tsconfig.json"
|
||||
*/
|
||||
// "tsconfigFilePath": "<projectFolder>/tsconfig.json",
|
||||
/**
|
||||
* Provides a compiler configuration that will be used instead of reading the tsconfig.json file from disk.
|
||||
* The object must conform to the TypeScript tsconfig schema:
|
||||
*
|
||||
* http://json.schemastore.org/tsconfig
|
||||
*
|
||||
* If omitted, then the tsconfig.json file will be read from the "projectFolder".
|
||||
*
|
||||
* DEFAULT VALUE: no overrideTsconfig section
|
||||
*/
|
||||
"overrideTsconfig": {
|
||||
"skipLibCheck": true
|
||||
}
|
||||
/**
|
||||
* This option causes the compiler to be invoked with the --skipLibCheck option. This option is not recommended
|
||||
* and may cause API Extractor to produce incomplete or incorrect declarations, but it may be required when
|
||||
* dependencies contain declarations that are incompatible with the TypeScript engine that API Extractor uses
|
||||
* for its analysis. Where possible, the underlying issue should be fixed rather than relying on skipLibCheck.
|
||||
*
|
||||
* DEFAULT VALUE: false
|
||||
*/
|
||||
// "skipLibCheck": true,
|
||||
},
|
||||
/**
|
||||
* Configures how the API report file (*.api.md) will be generated.
|
||||
*/
|
||||
"apiReport": {
|
||||
/**
|
||||
* (REQUIRED) Whether to generate an API report.
|
||||
*/
|
||||
"enabled": true
|
||||
/**
|
||||
* The filename for the API report files. It will be combined with "reportFolder" or "reportTempFolder" to produce
|
||||
* a full file path.
|
||||
*
|
||||
* The file extension should be ".api.md", and the string should not contain a path separator such as "\" or "/".
|
||||
*
|
||||
* SUPPORTED TOKENS: <packageName>, <unscopedPackageName>
|
||||
* DEFAULT VALUE: "<unscopedPackageName>.api.md"
|
||||
*/
|
||||
// "reportFileName": "<unscopedPackageName>.api.md",
|
||||
/**
|
||||
* Specifies the folder where the API report file is written. The file name portion is determined by
|
||||
* the "reportFileName" setting.
|
||||
*
|
||||
* The API report file is normally tracked by Git. Changes to it can be used to trigger a branch policy,
|
||||
* e.g. for an API review.
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as "<projectFolder>".
|
||||
*
|
||||
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
|
||||
* DEFAULT VALUE: "<projectFolder>/etc/"
|
||||
*/
|
||||
// "reportFolder": "<projectFolder>/etc/",
|
||||
/**
|
||||
* Specifies the folder where the temporary report file is written. The file name portion is determined by
|
||||
* the "reportFileName" setting.
|
||||
*
|
||||
* After the temporary file is written to disk, it is compared with the file in the "reportFolder".
|
||||
* If they are different, a production build will fail.
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as "<projectFolder>".
|
||||
*
|
||||
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
|
||||
* DEFAULT VALUE: "<projectFolder>/temp/"
|
||||
*/
|
||||
// "reportTempFolder": "<projectFolder>/temp/"
|
||||
},
|
||||
/**
|
||||
* Configures how the doc model file (*.api.json) will be generated.
|
||||
*/
|
||||
"docModel": {
|
||||
/**
|
||||
* (REQUIRED) Whether to generate a doc model file.
|
||||
*/
|
||||
"enabled": true
|
||||
/**
|
||||
* The output path for the doc model file. The file extension should be ".api.json".
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as "<projectFolder>".
|
||||
*
|
||||
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
|
||||
* DEFAULT VALUE: "<projectFolder>/temp/<unscopedPackageName>.api.json"
|
||||
*/
|
||||
// "apiJsonFilePath": "<projectFolder>/temp/<unscopedPackageName>.api.json"
|
||||
},
|
||||
/**
|
||||
* Configures how the .d.ts rollup file will be generated.
|
||||
*/
|
||||
"dtsRollup": {
|
||||
/**
|
||||
* (REQUIRED) Whether to generate the .d.ts rollup file.
|
||||
*/
|
||||
"enabled": false,
|
||||
/**
|
||||
* Specifies the output path for a .d.ts rollup file to be generated without any trimming.
|
||||
* This file will include all declarations that are exported by the main entry point.
|
||||
*
|
||||
* If the path is an empty string, then this file will not be written.
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as "<projectFolder>".
|
||||
*
|
||||
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
|
||||
* DEFAULT VALUE: "<projectFolder>/dist/<unscopedPackageName>.d.ts"
|
||||
*/
|
||||
"untrimmedFilePath": "<projectFolder>/lib/<unscopedPackageName>.d.ts"
|
||||
/**
|
||||
* Specifies the output path for a .d.ts rollup file to be generated with trimming for a "beta" release.
|
||||
* This file will include only declarations that are marked as "@public" or "@beta".
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as "<projectFolder>".
|
||||
*
|
||||
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
|
||||
* DEFAULT VALUE: ""
|
||||
*/
|
||||
// "betaTrimmedFilePath": "<projectFolder>/dist/<unscopedPackageName>-beta.d.ts",
|
||||
/**
|
||||
* Specifies the output path for a .d.ts rollup file to be generated with trimming for a "public" release.
|
||||
* This file will include only declarations that are marked as "@public".
|
||||
*
|
||||
* If the path is an empty string, then this file will not be written.
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as "<projectFolder>".
|
||||
*
|
||||
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
|
||||
* DEFAULT VALUE: ""
|
||||
*/
|
||||
// "publicTrimmedFilePath": "<projectFolder>/dist/<unscopedPackageName>-public.d.ts",
|
||||
/**
|
||||
* When a declaration is trimmed, by default it will be replaced by a code comment such as
|
||||
* "Excluded from this release type: exampleMember". Set "omitTrimmingComments" to true to remove the
|
||||
* declaration completely.
|
||||
*
|
||||
* DEFAULT VALUE: false
|
||||
*/
|
||||
// "omitTrimmingComments": true
|
||||
},
|
||||
/**
|
||||
* Configures how the tsdoc-metadata.json file will be generated.
|
||||
*/
|
||||
"tsdocMetadata": {
|
||||
/**
|
||||
* Whether to generate the tsdoc-metadata.json file.
|
||||
*
|
||||
* DEFAULT VALUE: true
|
||||
*/
|
||||
// "enabled": true,
|
||||
/**
|
||||
* Specifies where the TSDoc metadata file should be written.
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as "<projectFolder>".
|
||||
*
|
||||
* The default value is "<lookup>", which causes the path to be automatically inferred from the "tsdocMetadata",
|
||||
* "typings" or "main" fields of the project's package.json. If none of these fields are set, the lookup
|
||||
* falls back to "tsdoc-metadata.json" in the package folder.
|
||||
*
|
||||
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
|
||||
* DEFAULT VALUE: "<lookup>"
|
||||
*/
|
||||
// "tsdocMetadataFilePath": "<projectFolder>/dist/tsdoc-metadata.json"
|
||||
},
|
||||
/**
|
||||
* Specifies what type of newlines API Extractor should use when writing output files. By default, the output files
|
||||
* will be written with Windows-style newlines. To use POSIX-style newlines, specify "lf" instead.
|
||||
* To use the OS's default newline kind, specify "os".
|
||||
*
|
||||
* DEFAULT VALUE: "crlf"
|
||||
*/
|
||||
// "newlineKind": "crlf",
|
||||
/**
|
||||
* Configures how API Extractor reports error and warning messages produced during analysis.
|
||||
*
|
||||
* There are three sources of messages: compiler messages, API Extractor messages, and TSDoc messages.
|
||||
*/
|
||||
"messages": {
|
||||
/**
|
||||
* Configures handling of diagnostic messages reported by the TypeScript compiler engine while analyzing
|
||||
* the input .d.ts files.
|
||||
*
|
||||
* TypeScript message identifiers start with "TS" followed by an integer. For example: "TS2551"
|
||||
*
|
||||
* DEFAULT VALUE: A single "default" entry with logLevel=warning.
|
||||
*/
|
||||
"compilerMessageReporting": {
|
||||
/**
|
||||
* Configures the default routing for messages that don't match an explicit rule in this table.
|
||||
*/
|
||||
"default": {
|
||||
/**
|
||||
* Specifies whether the message should be written to the the tool's output log. Note that
|
||||
* the "addToApiReportFile" property may supersede this option.
|
||||
*
|
||||
* Possible values: "error", "warning", "none"
|
||||
*
|
||||
* Errors cause the build to fail and return a nonzero exit code. Warnings cause a production build fail
|
||||
* and return a nonzero exit code. For a non-production build (e.g. when "api-extractor run" includes
|
||||
* the "--local" option), the warning is displayed but the build will not fail.
|
||||
*
|
||||
* DEFAULT VALUE: "warning"
|
||||
*/
|
||||
"logLevel": "warning"
|
||||
/**
|
||||
* When addToApiReportFile is true: If API Extractor is configured to write an API report file (.api.md),
|
||||
* then the message will be written inside that file; otherwise, the message is instead logged according to
|
||||
* the "logLevel" option.
|
||||
*
|
||||
* DEFAULT VALUE: false
|
||||
*/
|
||||
// "addToApiReportFile": false
|
||||
}
|
||||
// "TS2551": {
|
||||
// "logLevel": "warning",
|
||||
// "addToApiReportFile": true
|
||||
// },
|
||||
//
|
||||
// . . .
|
||||
},
|
||||
/**
|
||||
* Configures handling of messages reported by API Extractor during its analysis.
|
||||
*
|
||||
* API Extractor message identifiers start with "ae-". For example: "ae-extra-release-tag"
|
||||
*
|
||||
* DEFAULT VALUE: See api-extractor-defaults.json for the complete table of extractorMessageReporting mappings
|
||||
*/
|
||||
"extractorMessageReporting": {
|
||||
"default": {
|
||||
"logLevel": "warning"
|
||||
// "addToApiReportFile": false
|
||||
}
|
||||
// "ae-extra-release-tag": {
|
||||
// "logLevel": "warning",
|
||||
// "addToApiReportFile": true
|
||||
// },
|
||||
//
|
||||
// . . .
|
||||
},
|
||||
/**
|
||||
* Configures handling of messages reported by the TSDoc parser when analyzing code comments.
|
||||
*
|
||||
* TSDoc message identifiers start with "tsdoc-". For example: "tsdoc-link-tag-unescaped-text"
|
||||
*
|
||||
* DEFAULT VALUE: A single "default" entry with logLevel=warning.
|
||||
*/
|
||||
"tsdocMessageReporting": {
|
||||
"default": {
|
||||
"logLevel": "warning"
|
||||
// "addToApiReportFile": false
|
||||
}
|
||||
// "tsdoc-link-tag-unescaped-text": {
|
||||
// "logLevel": "warning",
|
||||
// "addToApiReportFile": true
|
||||
// },
|
||||
//
|
||||
// . . .
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/react",
|
||||
"version": "3.1.2",
|
||||
"version": "3.2.5",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"license": "Apache-2.0",
|
||||
@@ -44,9 +44,10 @@
|
||||
"lint": "eslint src/",
|
||||
"fix": "eslint src/ --fix",
|
||||
"clean": "rm -rf dist/",
|
||||
"generate-docs": "api-extractor run --local && yarn api-documenter markdown -i ./temp -o ./docs && yarn generate-snippets",
|
||||
"generate:md-docs": "yarn api-documenter markdown -i ./temp -o ./docs",
|
||||
"generate-snippets": "node ./scripts/generate-snippets.mjs && node ./scripts/generate-feature-snippets.mjs",
|
||||
"generate-docs": "yarn generate-docs:evm && yarn generate-docs:solana && yarn generate-snippets",
|
||||
"generate-docs:evm": "api-extractor run --local --config ./config/api-extractor-evm.json && api-documenter markdown -i ./temp -o ./docs/evm && rm -rf ./temp-evm && mv ./temp ./temp-evm",
|
||||
"generate-docs:solana": "api-extractor run --local --config ./config/api-extractor-solana.json && api-documenter markdown -i ./temp -o ./docs/solana && rm -rf ./temp-solana && mv ./temp ./temp-solana",
|
||||
"generate-snippets": "node ./scripts/generate-snippets-evm.mjs && node ./scripts/generate-snippets-solana.mjs && node ./scripts/generate-feature-snippets-evm.mjs",
|
||||
"build": "tsc && preconstruct build",
|
||||
"e2e": "yarn test-ct",
|
||||
"test-ct": "playwright test -c playwright-ct.config.ts",
|
||||
@@ -58,6 +59,7 @@
|
||||
"@babel/preset-env": "^7.18.10",
|
||||
"@babel/preset-react": "^7.18.6",
|
||||
"@babel/preset-typescript": "^7.18.6",
|
||||
"@babel/runtime": "^7.19.0",
|
||||
"@microsoft/api-documenter": "^7.19.4",
|
||||
"@microsoft/api-extractor": "^7.29.2",
|
||||
"@microsoft/tsdoc": "^0.14.1",
|
||||
@@ -82,7 +84,7 @@
|
||||
"eslint-plugin-inclusive-language": "^2.2.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"eslint-plugin-tsdoc": "^0.2.16",
|
||||
"ethers": "^5.7.0",
|
||||
"ethers": "^5.7.1",
|
||||
"prettier": "^2.7.1",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
@@ -98,6 +100,7 @@
|
||||
"@tanstack/react-query": "^4.0.10",
|
||||
"@zag-js/menu": "0.1.14",
|
||||
"@zag-js/react": "0.1.16",
|
||||
"buffer": "^6.0.3",
|
||||
"color": "^4.2.3",
|
||||
"copy-to-clipboard": "^3.3.2",
|
||||
"detect-browser": "^5.3.0",
|
||||
|
||||
+2
-2
@@ -44,7 +44,7 @@ config.setSupportForTag(tag, true);
|
||||
const tsdocParser = new TSDocParser(config);
|
||||
|
||||
const json = JSON.parse(
|
||||
fs.readFileSync(`${process.cwd()}/temp/react.api.json`, "utf8"),
|
||||
fs.readFileSync(`${process.cwd()}/temp-evm/react.api.json`, "utf8"),
|
||||
);
|
||||
|
||||
function languageNameToKey(languageName) {
|
||||
@@ -160,6 +160,6 @@ classes.forEach((m) => {
|
||||
});
|
||||
|
||||
fs.writeFileSync(
|
||||
`${process.cwd()}/docs/feature_snippets.json`,
|
||||
`${process.cwd()}/docs/evm/feature_snippets.json`,
|
||||
JSON.stringify(features, null, 2),
|
||||
);
|
||||
+25
-41
@@ -27,41 +27,6 @@ export class Formatter {
|
||||
}
|
||||
}
|
||||
|
||||
const tsdocParser = new TSDocParser();
|
||||
|
||||
const json = JSON.parse(
|
||||
fs.readFileSync(`${process.cwd()}/temp/react.api.json`, "utf8"),
|
||||
);
|
||||
|
||||
function languageNameToKey(languageName) {
|
||||
switch (languageName) {
|
||||
case "js":
|
||||
case "jsx":
|
||||
return "javascript";
|
||||
case "ts":
|
||||
case "tsx":
|
||||
return "typescript";
|
||||
default:
|
||||
return languageName;
|
||||
}
|
||||
}
|
||||
|
||||
const CONTRACT_HOOKS = [
|
||||
"useSignatureDrop",
|
||||
"useNFTDrop",
|
||||
"useEditionDrop",
|
||||
"useNFTCollection",
|
||||
"useEdition",
|
||||
"useTokenDrop",
|
||||
"useToken",
|
||||
"useMarketplace",
|
||||
"useSplit",
|
||||
"useVote",
|
||||
"usePack",
|
||||
"useMultiwrap",
|
||||
"useContract",
|
||||
];
|
||||
|
||||
const NFT_HOOKS = [
|
||||
"useNFT",
|
||||
"useNFTs",
|
||||
@@ -141,7 +106,7 @@ const CONTRACT_SETTINGS_HOOKS = [
|
||||
"useRevokeRole",
|
||||
];
|
||||
|
||||
const CONTRACT_SUBHOOKS = {
|
||||
const HOOKS_CONFIG = {
|
||||
useSignatureDrop: [...NFT_HOOKS, ...DROP_HOOKS, ...CLAIM_CONDITIONS_HOOKS],
|
||||
useNFTDrop: [...NFT_HOOKS, ...DROP_HOOKS, ...CLAIM_CONDITIONS_HOOKS],
|
||||
useEditionDrop: [...NFT_HOOKS, ...DROP_HOOKS, ...CLAIM_CONDITIONS_HOOKS],
|
||||
@@ -162,8 +127,27 @@ const CONTRACT_SUBHOOKS = {
|
||||
],
|
||||
};
|
||||
|
||||
const tsdocParser = new TSDocParser();
|
||||
|
||||
const json = JSON.parse(
|
||||
fs.readFileSync(`${process.cwd()}/temp-evm/react.api.json`, "utf8"),
|
||||
);
|
||||
|
||||
function languageNameToKey(languageName) {
|
||||
switch (languageName) {
|
||||
case "js":
|
||||
case "jsx":
|
||||
return "javascript";
|
||||
case "ts":
|
||||
case "tsx":
|
||||
return "typescript";
|
||||
default:
|
||||
return languageName;
|
||||
}
|
||||
}
|
||||
|
||||
const hooks = json.members[0].members.filter(
|
||||
(m) => m.kind === "Function" && CONTRACT_HOOKS.includes(m.name),
|
||||
(m) => m.kind === "Function" && Object.keys(HOOKS_CONFIG).includes(m.name),
|
||||
);
|
||||
|
||||
function parseExampleTag(docComment) {
|
||||
@@ -192,7 +176,7 @@ function parseExampleTag(docComment) {
|
||||
return examples;
|
||||
}
|
||||
|
||||
const baseDocUrl = "https://docs.thirdweb.com/typescript/react.";
|
||||
const baseDocUrl = "https://portal.thirdweb.com/react/react.";
|
||||
|
||||
const extractReferenceLink = (m, kind, contractName) => {
|
||||
if (kind === "Property") {
|
||||
@@ -212,7 +196,7 @@ const moduleMap = hooks.reduce((acc, m) => {
|
||||
const examples = parseExampleTag(docComment);
|
||||
|
||||
const contractSubhooks = json.members[0].members.filter(
|
||||
(f) => f.kind === "Function" && CONTRACT_SUBHOOKS[m.name].includes(f.name),
|
||||
(f) => f.kind === "Function" && HOOKS_CONFIG[m.name].includes(f.name),
|
||||
);
|
||||
|
||||
const contractHooks = contractSubhooks.map((subhookContent) => {
|
||||
@@ -223,7 +207,7 @@ const moduleMap = hooks.reduce((acc, m) => {
|
||||
return {
|
||||
name: subhookContent.name,
|
||||
example: subhookExamples?.javascript || "",
|
||||
reference: `https://portal.thirdweb.com/react/react.${subhookContent.name.toLowerCase()}`,
|
||||
reference: `${baseDocUrl}${subhookContent.name.toLowerCase()}`,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -241,6 +225,6 @@ const moduleMap = hooks.reduce((acc, m) => {
|
||||
}, {});
|
||||
|
||||
fs.writeFileSync(
|
||||
`${process.cwd()}/docs/snippets.json`,
|
||||
`${process.cwd()}/docs/evm/snippets.json`,
|
||||
JSON.stringify(moduleMap, null, 2),
|
||||
);
|
||||
@@ -0,0 +1,135 @@
|
||||
import { Formatter } from "./generate-snippets-evm.mjs";
|
||||
import { TSDocParser } from "@microsoft/tsdoc";
|
||||
import fs from "fs";
|
||||
|
||||
const NFT_HOOKS = ["useMintNFT", "useNFT", "useNFTs", "useTransferNFT"];
|
||||
|
||||
const DROP_HOOKS = [
|
||||
"useClaimedSupply",
|
||||
"useClaimNFT",
|
||||
"useLazyMintNFT",
|
||||
"useUnclaimedSupply",
|
||||
];
|
||||
|
||||
const TOKEN_HOOKS = [
|
||||
"useMintToken",
|
||||
"useTokenBalance",
|
||||
"useTokenSupply",
|
||||
"useTransferToken",
|
||||
];
|
||||
|
||||
const HOOKS_CONFIG = {
|
||||
useNFTCollection: [...NFT_HOOKS],
|
||||
useNFTDrop: [...NFT_HOOKS, ...DROP_HOOKS],
|
||||
useToken: [...TOKEN_HOOKS],
|
||||
useProgram: [],
|
||||
};
|
||||
|
||||
const tsdocParser = new TSDocParser();
|
||||
|
||||
const json = JSON.parse(
|
||||
fs.readFileSync(`${process.cwd()}/temp-solana/react.api.json`, "utf8"),
|
||||
);
|
||||
|
||||
function languageNameToKey(languageName) {
|
||||
switch (languageName) {
|
||||
case "js":
|
||||
case "jsx":
|
||||
return "javascript";
|
||||
case "ts":
|
||||
case "tsx":
|
||||
return "typescript";
|
||||
default:
|
||||
return languageName;
|
||||
}
|
||||
}
|
||||
|
||||
function parseExampleTag(docComment) {
|
||||
const exampleBlocks = docComment._customBlocks.filter(
|
||||
(b) => b._blockTag._tagName === "@example",
|
||||
);
|
||||
|
||||
const examplesString = Formatter.renderDocNodes(exampleBlocks);
|
||||
|
||||
const regex = /```([a-zA-Z]*)\n([\S\s]*?)\n```/g;
|
||||
|
||||
let matches;
|
||||
|
||||
const examples = {};
|
||||
|
||||
while ((matches = regex.exec(examplesString)) !== null) {
|
||||
// This is necessary to avoid infinite loops with zero-width matches
|
||||
if (matches.index === regex.lastIndex) {
|
||||
regex.lastIndex++;
|
||||
}
|
||||
|
||||
const re = /\n( *)\/\/ For example((.|\n)*)\.\.\.\n/g;
|
||||
const example = matches[2].replace(re, "");
|
||||
examples[languageNameToKey(matches[1])] = example;
|
||||
}
|
||||
return examples;
|
||||
}
|
||||
|
||||
const baseDocUrl = "https://portal.thirdweb.com/react/solana/react.";
|
||||
|
||||
const extractReferenceLink = (m, kind, contractName) => {
|
||||
if (kind === "Property") {
|
||||
return m.excerptTokens
|
||||
.filter((e) => e.kind === "Reference")
|
||||
.map((e) => `${baseDocUrl}${e.text.toLowerCase()}`)[0];
|
||||
}
|
||||
if (kind === "Method") {
|
||||
return `${baseDocUrl}${contractName}.${m.name}`;
|
||||
}
|
||||
return `${baseDocUrl}${m.name}`;
|
||||
};
|
||||
|
||||
const moduleMap = Object.keys(HOOKS_CONFIG).reduce((acc, hookName) => {
|
||||
let summary = "";
|
||||
let examples = {};
|
||||
let reference = "";
|
||||
|
||||
const doc = json.members[0].members.find(
|
||||
(m) =>
|
||||
m.kind === "Function" && Object.keys(HOOKS_CONFIG).includes(hookName),
|
||||
);
|
||||
|
||||
if (doc) {
|
||||
const parserContext = tsdocParser.parseString(doc);
|
||||
const docComment = parserContext.docComment;
|
||||
summary = Formatter.renderDocNode(docComment.summarySection);
|
||||
examples = parseExampleTag(docComment);
|
||||
reference = extractReferenceLink(doc);
|
||||
}
|
||||
|
||||
const contractSubhooks = json.members[0].members.filter(
|
||||
(f) => f.kind === "Function" && HOOKS_CONFIG[hookName].includes(f.name),
|
||||
);
|
||||
|
||||
const subhooks = contractSubhooks.map((subhookContent) => {
|
||||
const subhookContext = tsdocParser.parseString(subhookContent.docComment);
|
||||
const subhookComment = subhookContext.docComment;
|
||||
const subhookExamples = parseExampleTag(subhookComment);
|
||||
|
||||
return {
|
||||
name: subhookContent.name,
|
||||
example: subhookExamples?.javascript || "",
|
||||
reference: `${baseDocUrl}${subhookContent.name.toLowerCase()}`,
|
||||
};
|
||||
});
|
||||
|
||||
acc[hookName] = {
|
||||
name: hookName,
|
||||
summary,
|
||||
examples,
|
||||
subhooks,
|
||||
reference,
|
||||
};
|
||||
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
fs.writeFileSync(
|
||||
`${process.cwd()}/docs/solana/snippets.json`,
|
||||
JSON.stringify(moduleMap, null, 2),
|
||||
);
|
||||
@@ -1,6 +1,6 @@
|
||||
import { RequiredParam } from "../types/shared";
|
||||
import { QueryKey } from "@tanstack/react-query";
|
||||
import type { ChainId } from "@thirdweb-dev/sdk";
|
||||
import type { QueryKey } from "@tanstack/react-query";
|
||||
import type { ValidContractInstance } from "@thirdweb-dev/sdk";
|
||||
import type {
|
||||
Network,
|
||||
NFTCollection,
|
||||
@@ -13,7 +13,7 @@ const TW_QUERY_KEY_PREFIX = "__tw__";
|
||||
// marker to make sure the query will not get stored in local storage by a query persister
|
||||
const NEVER_PERSIST_QUERY_POSTFIX = { persist: false } as const;
|
||||
|
||||
function ensureTWPrefix<TKey extends QueryKey>(key: TKey) {
|
||||
export function ensureTWPrefix<TKey extends QueryKey>(key: TKey) {
|
||||
if (key[0] === TW_QUERY_KEY_PREFIX) {
|
||||
return key as unknown as Readonly<[typeof TW_QUERY_KEY_PREFIX, ...TKey]>;
|
||||
}
|
||||
@@ -27,7 +27,7 @@ export function neverPersist<TKey extends QueryKey>(key: TKey) {
|
||||
export function shouldNeverPersistQuery<TKey extends QueryKey>(
|
||||
key: TKey,
|
||||
): boolean {
|
||||
return key[key.length] === NEVER_PERSIST_QUERY_POSTFIX;
|
||||
return key[key.length - 1] === NEVER_PERSIST_QUERY_POSTFIX;
|
||||
}
|
||||
|
||||
// EVM
|
||||
@@ -37,11 +37,23 @@ export function createEVMQueryKey<TKey extends QueryKey>(key: TKey) {
|
||||
}
|
||||
export function createEVMQueryKeyWithChain<TKey extends QueryKey>(
|
||||
key: TKey,
|
||||
chainId: RequiredParam<ChainId>,
|
||||
chainId: RequiredParam<number>,
|
||||
) {
|
||||
return ensureTWPrefix([chainId, ...key] as const);
|
||||
}
|
||||
|
||||
export function createEVMContractQueryKey<TKey extends QueryKey>(
|
||||
contract: RequiredParam<ValidContractInstance>,
|
||||
key: TKey = [] as unknown as TKey,
|
||||
) {
|
||||
const chainId = contract?.chainId;
|
||||
const address = contract?.getAddress();
|
||||
return createEVMQueryKeyWithChain(
|
||||
["contract", address, ...key] as const,
|
||||
chainId,
|
||||
);
|
||||
}
|
||||
|
||||
// SOL
|
||||
|
||||
export function createSOLQueryKey<TKey extends QueryKey>(key: TKey) {
|
||||
|
||||
@@ -76,10 +76,8 @@ const chainIdToCurrencyMap: Record<
|
||||
> = {
|
||||
[ChainId.Mainnet]: "ethereum",
|
||||
[ChainId.Goerli]: "ethereum",
|
||||
[ChainId.Rinkeby]: "ethereum",
|
||||
|
||||
[ChainId.Arbitrum]: "arbitrum",
|
||||
[ChainId.ArbitrumRinkeby]: "arbitrum",
|
||||
[ChainId.ArbitrumGoerli]: "arbitrum",
|
||||
|
||||
[ChainId.Avalanche]: "avalanche",
|
||||
@@ -89,7 +87,6 @@ const chainIdToCurrencyMap: Record<
|
||||
[ChainId.FantomTestnet]: "fantom",
|
||||
|
||||
[ChainId.Optimism]: "optimism",
|
||||
[ChainId.OptimismKovan]: "optimism",
|
||||
[ChainId.OptimismGoerli]: "optimism",
|
||||
|
||||
[ChainId.Polygon]: "polygon",
|
||||
|
||||
@@ -13,7 +13,7 @@ import { ThemeProvider, ThemeProviderProps } from "../shared/ThemeProvider";
|
||||
import { FiWifi } from "@react-icons/all-files/fi/FiWifi";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import type { SmartContract } from "@thirdweb-dev/sdk/dist/declarations/src/evm/contracts/smart-contract";
|
||||
import type { CallOverrides } from "ethers";
|
||||
import type { CallOverrides, ContractInterface } from "ethers";
|
||||
import { PropsWithChildren, useMemo } from "react";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
@@ -23,6 +23,7 @@ interface Web3ButtonProps<TActionFn extends ActionFn>
|
||||
extends ThemeProviderProps {
|
||||
className?: string;
|
||||
contractAddress: `0x${string}` | `${string}.eth` | string;
|
||||
contractAbi?: ContractInterface;
|
||||
|
||||
overrides?: CallOverrides;
|
||||
// called with the result
|
||||
@@ -64,6 +65,7 @@ export const Web3Button = <TAction extends ActionFn>({
|
||||
onError,
|
||||
onSubmit,
|
||||
isDisabled,
|
||||
contractAbi,
|
||||
children,
|
||||
action,
|
||||
className,
|
||||
@@ -85,7 +87,7 @@ export const Web3Button = <TAction extends ActionFn>({
|
||||
return null;
|
||||
}, [sdkChainId, walletChainId]);
|
||||
|
||||
const { contract } = useContract(contractAddress);
|
||||
const { contract } = useContract(contractAddress, contractAbi || "custom");
|
||||
|
||||
const mutation = useMutation(
|
||||
async () => {
|
||||
|
||||
@@ -8,7 +8,6 @@ const CHAIN_ID_TO_GNOSIS_SERVER_URL = {
|
||||
[ChainId.Avalanche]: "https://safe-transaction.avalanche.gnosis.io",
|
||||
[ChainId.Polygon]: "https://safe-transaction.polygon.gnosis.io",
|
||||
[ChainId.Goerli]: "https://safe-transaction.goerli.gnosis.io",
|
||||
[ChainId.Rinkeby]: "https://safe-transaction.rinkeby.gnosis.io",
|
||||
};
|
||||
|
||||
export interface GnosisConnectorArguments {
|
||||
|
||||
@@ -16,20 +16,7 @@ const chain: Record<string, Chain> = {
|
||||
},
|
||||
],
|
||||
},
|
||||
rinkeby: {
|
||||
id: ChainId.Rinkeby,
|
||||
name: "Rinkeby",
|
||||
nativeCurrency: NATIVE_TOKENS[ChainId.Rinkeby],
|
||||
rpcUrls: ["https://rinkeby.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161"],
|
||||
blockExplorers: [
|
||||
{
|
||||
name: "Etherscan",
|
||||
url: "https://rinkeby.etherscan.io",
|
||||
},
|
||||
],
|
||||
testnet: true,
|
||||
deprecated: true,
|
||||
},
|
||||
|
||||
goerli: {
|
||||
id: ChainId.Goerli,
|
||||
name: "Goerli",
|
||||
@@ -147,20 +134,7 @@ const chain: Record<string, Chain> = {
|
||||
],
|
||||
testnet: false,
|
||||
},
|
||||
optimismKovan: {
|
||||
id: ChainId.OptimismKovan,
|
||||
name: "Optimism Kovan",
|
||||
nativeCurrency: NATIVE_TOKENS[ChainId.OptimismKovan],
|
||||
rpcUrls: ["https://kovan.optimism.io"],
|
||||
blockExplorers: [
|
||||
{
|
||||
name: "Etherscan",
|
||||
url: "https://kovan-optimistic.etherscan.io/",
|
||||
},
|
||||
],
|
||||
testnet: true,
|
||||
deprecated: true,
|
||||
},
|
||||
|
||||
optimismGoerli: {
|
||||
id: ChainId.OptimismGoerli,
|
||||
name: "Optimism Goerli Testnet",
|
||||
@@ -187,20 +161,7 @@ const chain: Record<string, Chain> = {
|
||||
],
|
||||
testnet: false,
|
||||
},
|
||||
arbitrumRinkeby: {
|
||||
id: ChainId.ArbitrumRinkeby,
|
||||
name: "Arbitrum Rinkeby",
|
||||
nativeCurrency: NATIVE_TOKENS[ChainId.ArbitrumRinkeby],
|
||||
rpcUrls: ["https://rinkeby.arbitrum.io/rpc"],
|
||||
blockExplorers: [
|
||||
{
|
||||
name: "Arbiscan",
|
||||
url: "https://testnet.arbiscan.io/",
|
||||
},
|
||||
],
|
||||
testnet: true,
|
||||
deprecated: true,
|
||||
},
|
||||
|
||||
arbitrumGoerli: {
|
||||
id: ChainId.ArbitrumGoerli,
|
||||
name: "Arbitrum Goerli",
|
||||
|
||||
@@ -13,7 +13,6 @@ interface ThirdwebConfigContext {
|
||||
|
||||
export const defaultChainRpc: Record<SupportedChainId | number, string> = {
|
||||
[ChainId.Mainnet]: "mainnet",
|
||||
[ChainId.Rinkeby]: "rinkeby",
|
||||
[ChainId.Goerli]: "goerli",
|
||||
[ChainId.Polygon]: "polygon",
|
||||
[ChainId.Mumbai]: "mumbai",
|
||||
|
||||
@@ -70,7 +70,10 @@ export function useActiveClaimCondition(
|
||||
cacheKeys.extensions.claimConditions.getActive(contractAddress, tokenId),
|
||||
() => {
|
||||
if (erc1155) {
|
||||
invariant(tokenId, "tokenId is required for ERC1155 claim conditions");
|
||||
invariant(
|
||||
tokenId !== undefined,
|
||||
"tokenId is required for ERC1155 claim conditions",
|
||||
);
|
||||
return erc1155.claimConditions.getActive(tokenId);
|
||||
}
|
||||
if (erc721) {
|
||||
|
||||
@@ -18,13 +18,16 @@ import {
|
||||
import {
|
||||
CommonContractSchemaInput,
|
||||
ContractEvent,
|
||||
ContractForPrebuiltContractType,
|
||||
ContractType,
|
||||
EventQueryFilter,
|
||||
PrebuiltContractType,
|
||||
SUPPORTED_CHAIN_ID,
|
||||
ThirdwebSDK,
|
||||
ValidContractInstance,
|
||||
} from "@thirdweb-dev/sdk";
|
||||
import type { SmartContract } from "@thirdweb-dev/sdk/dist/declarations/src/evm/contracts/smart-contract";
|
||||
import { CallOverrides } from "ethers";
|
||||
import { CallOverrides, ContractInterface } from "ethers";
|
||||
import { useEffect, useMemo } from "react";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
@@ -147,9 +150,55 @@ export type UseContractResult<
|
||||
* @returns a response object that includes the contract once it is resolved
|
||||
* @public
|
||||
*/
|
||||
export function useContract<
|
||||
TContract extends ValidContractInstance = SmartContract,
|
||||
>(contractAddress: RequiredParam<ContractAddress>) {
|
||||
export function useContract(
|
||||
contractAddress: RequiredParam<ContractAddress>,
|
||||
): UseContractResult<SmartContract>;
|
||||
|
||||
/**
|
||||
* Use this resolve a contract address to a smart contract instance.
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* const { contract, isLoading, error } = useContract("{{contract_address}}", "nft-drop");
|
||||
* ```
|
||||
*
|
||||
* @param contractAddress - the address of the deployed contract
|
||||
* @param _contractType - the type of the contract
|
||||
* @returns a response object that includes the contract once it is resolved
|
||||
* @public
|
||||
*/
|
||||
export function useContract<TContractType extends ContractType>(
|
||||
contractAddress: RequiredParam<ContractAddress>,
|
||||
_contractType: TContractType,
|
||||
): UseContractResult<
|
||||
TContractType extends PrebuiltContractType
|
||||
? ContractForPrebuiltContractType<TContractType>
|
||||
: SmartContract
|
||||
>;
|
||||
|
||||
/**
|
||||
* Use this resolve a contract address to a smart contract instance.
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* const { contract, isLoading, error } = useContract("{{contract_address}}", ABI);
|
||||
* ```
|
||||
*
|
||||
* @param contractAddress - the address of the deployed contract
|
||||
* @param _abi - the ABI of the contract to use
|
||||
* @returns a response object that includes the contract once it is resolved
|
||||
* @public
|
||||
*/
|
||||
|
||||
export function useContract(
|
||||
contractAddress: RequiredParam<ContractAddress>,
|
||||
_abi: ContractInterface,
|
||||
): UseContractResult<SmartContract>;
|
||||
|
||||
export function useContract(
|
||||
contractAddress: RequiredParam<ContractAddress>,
|
||||
contractTypeOrABI?: ContractType | ContractInterface,
|
||||
) {
|
||||
const sdk = useSDK();
|
||||
const queryClient = useQueryClient();
|
||||
const activeChainId = useSDKChainId();
|
||||
@@ -170,29 +219,33 @@ export function useContract<
|
||||
invariant(contractAddress, "contract address is required");
|
||||
invariant(sdk, "SDK not initialized");
|
||||
invariant(activeChainId, "active chain id is required");
|
||||
// first fetch the contract type (we fetch this explicitly via the queryClient so **it** gets cached!)
|
||||
const cType = await queryClient.fetchQuery(
|
||||
contractType.cacheKey(contractAddress, activeChainId),
|
||||
() => contractType.fetchQuery(contractAddress, sdk),
|
||||
{ cacheTime: Infinity, staleTime: Infinity },
|
||||
);
|
||||
// if we can't get the contract type, we need to exit
|
||||
invariant(cType, "could not get contract type");
|
||||
// if the contract type is NOT "custom", we can use the built-in contract method from the SDK
|
||||
if (cType !== "custom") {
|
||||
return await sdk.getBuiltInContract(contractAddress, cType);
|
||||
}
|
||||
// if the contract type is "custom", we need to fetch the compiler metadata
|
||||
|
||||
const compMetadata = await queryClient.fetchQuery(
|
||||
compilerMetadata.cacheKey(contractAddress, activeChainId),
|
||||
() => compilerMetadata.fetchQuery(contractAddress, sdk),
|
||||
{ cacheTime: Infinity, staleTime: Infinity },
|
||||
);
|
||||
// if we can't get the compiler metadata, we need to exit
|
||||
invariant(compMetadata, "could not get compiler metadata");
|
||||
// if we have the compiler metadata, we can use the custom contract
|
||||
return sdk.getContractFromAbi(contractAddress, compMetadata.abi);
|
||||
// if we don't have a contractType or ABI then we will have to resolve it regardless
|
||||
// we also handle it being "custom" just in case...
|
||||
if (!contractTypeOrABI || contractTypeOrABI === "custom") {
|
||||
// we just resolve here (sdk does this internally anyway)
|
||||
const resolvedContractType = await queryClient.fetchQuery(
|
||||
contractType.cacheKey(contractAddress, activeChainId),
|
||||
() => contractType.fetchQuery(contractAddress, sdk),
|
||||
{ cacheTime: Infinity, staleTime: Infinity },
|
||||
);
|
||||
let abi: ContractInterface | undefined;
|
||||
if (resolvedContractType === "custom") {
|
||||
abi = (
|
||||
await queryClient.fetchQuery(
|
||||
compilerMetadata.cacheKey(contractAddress, activeChainId),
|
||||
() => compilerMetadata.fetchQuery(contractAddress, sdk),
|
||||
{ cacheTime: Infinity, staleTime: Infinity },
|
||||
)
|
||||
)?.abi;
|
||||
}
|
||||
invariant(resolvedContractType, "failed to resolve contract type");
|
||||
// just let the sdk handle the rest
|
||||
// if we have resolved an ABI for a custom contract, use that otherwise use contract type
|
||||
return sdk.getContract(contractAddress, abi || resolvedContractType);
|
||||
}
|
||||
// every other case can just be handled by the sdk directly
|
||||
return sdk.getContract(contractAddress, contractTypeOrABI);
|
||||
},
|
||||
{
|
||||
// keep the previous value around while we fetch the new one
|
||||
@@ -211,7 +264,7 @@ export function useContract<
|
||||
...contractQuery,
|
||||
data: contractQuery.data,
|
||||
contract: contractQuery.data,
|
||||
} as UseContractResult<TContract>;
|
||||
} as UseContractResult<ValidContractInstance>;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -206,11 +206,17 @@ export function useClaimNFT<TContract extends DropContract>(
|
||||
|
||||
return useMutation(
|
||||
async (data: ClaimNFTParams) => {
|
||||
invariant(data.to, 'No "to" address provided');
|
||||
invariant(contract, "contract is undefined");
|
||||
|
||||
if (erc1155) {
|
||||
invariant(!!data.tokenId, "tokenId not provided");
|
||||
if (!data.to) {
|
||||
return (await erc1155.claim(
|
||||
data.tokenId,
|
||||
data.quantity,
|
||||
data.options,
|
||||
)) as ClaimNFTReturnType;
|
||||
}
|
||||
return (await erc1155.claimTo(
|
||||
data.to,
|
||||
data.tokenId,
|
||||
@@ -219,6 +225,12 @@ export function useClaimNFT<TContract extends DropContract>(
|
||||
)) as ClaimNFTReturnType;
|
||||
}
|
||||
if (erc721) {
|
||||
if (!data.to) {
|
||||
return (await erc721.claim(
|
||||
data.quantity,
|
||||
data.options,
|
||||
)) as ClaimNFTReturnType;
|
||||
}
|
||||
return (await erc721.claimTo(
|
||||
data.to,
|
||||
data.quantity,
|
||||
|
||||
@@ -6,10 +6,8 @@ import {
|
||||
MintNFTParams,
|
||||
MintNFTReturnType,
|
||||
MintNFTSupplyParams,
|
||||
NFT,
|
||||
TransferNFTParams,
|
||||
WalletAddress,
|
||||
Erc721OrErc1155,
|
||||
NFTContract,
|
||||
getErcs,
|
||||
} from "../../types";
|
||||
@@ -19,45 +17,10 @@ import {
|
||||
} from "../../utils/cache-keys";
|
||||
import { useQueryWithNetwork } from "../query-utils/useQueryWithNetwork";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import { Erc721, Erc1155, QueryAllParams } from "@thirdweb-dev/sdk";
|
||||
import { Erc1155, QueryAllParams, NFT } from "@thirdweb-dev/sdk";
|
||||
import { BigNumber, BigNumberish } from "ethers";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export function convertResponseToNFTType(
|
||||
contract: Erc721OrErc1155,
|
||||
metadata: Awaited<ReturnType<typeof contract["get"]>>,
|
||||
): NFT<typeof contract> {
|
||||
if (contract instanceof Erc721) {
|
||||
return {
|
||||
type: "ERC721",
|
||||
supply: 1,
|
||||
owner: "",
|
||||
...metadata,
|
||||
} as NFT<Erc721>;
|
||||
}
|
||||
if (contract instanceof Erc1155) {
|
||||
return {
|
||||
type: "ERC1155",
|
||||
supply: 0,
|
||||
owner: "",
|
||||
...metadata,
|
||||
} as NFT<Erc1155>;
|
||||
}
|
||||
invariant(false, "Unknown NFT type");
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export function convertResponseToNFTTypeArray(
|
||||
contract: Erc721OrErc1155,
|
||||
metadata: Awaited<ReturnType<typeof contract["get"]>>[],
|
||||
): NFT<typeof contract>[] {
|
||||
return metadata.map((m) => convertResponseToNFTType(contract, m));
|
||||
}
|
||||
/** **********************/
|
||||
/** READ HOOKS **/
|
||||
/** **********************/
|
||||
@@ -84,24 +47,18 @@ export function useNFT<TContract extends NFTContract>(
|
||||
const contractAddress = contract?.getAddress();
|
||||
const { erc721, erc1155 } = getErcs(contract);
|
||||
|
||||
return useQueryWithNetwork<NFT<Erc721OrErc1155>>(
|
||||
return useQueryWithNetwork<NFT>(
|
||||
cacheKeys.contract.nft.get(contractAddress, tokenId),
|
||||
async () => {
|
||||
invariant(contract, "No Contract instance provided");
|
||||
|
||||
if (erc1155) {
|
||||
invariant(erc1155.get, "Contract instance does not support get");
|
||||
return convertResponseToNFTType(
|
||||
erc1155,
|
||||
await erc1155.get(BigNumber.from(tokenId || 0)),
|
||||
);
|
||||
return await erc1155.get(BigNumber.from(tokenId || 0));
|
||||
}
|
||||
if (erc721) {
|
||||
invariant(erc721.get, "Contract instance does not support get");
|
||||
return convertResponseToNFTType(
|
||||
erc721,
|
||||
await erc721.get(BigNumber.from(tokenId || 0)),
|
||||
);
|
||||
return await erc721.get(BigNumber.from(tokenId || 0));
|
||||
}
|
||||
invariant(false, "Unknown NFT type");
|
||||
},
|
||||
@@ -133,24 +90,18 @@ export function useNFTs<TContract extends NFTContract>(
|
||||
const contractAddress = contract?.getAddress();
|
||||
const { erc721, erc1155 } = getErcs(contract);
|
||||
|
||||
return useQueryWithNetwork<NFT<Erc721OrErc1155>[]>(
|
||||
return useQueryWithNetwork<NFT[]>(
|
||||
cacheKeys.contract.nft.query.all(contractAddress, queryParams),
|
||||
async () => {
|
||||
invariant(contract, "No Contract instance provided");
|
||||
|
||||
if (erc721) {
|
||||
invariant(erc721.getAll, "Contract instance does not support getAll");
|
||||
return convertResponseToNFTTypeArray(
|
||||
erc721,
|
||||
await erc721.getAll(queryParams),
|
||||
);
|
||||
return await erc721.getAll(queryParams);
|
||||
}
|
||||
if (erc1155) {
|
||||
invariant(erc1155.getAll, "Contract instance does not support getAll");
|
||||
return convertResponseToNFTTypeArray(
|
||||
erc1155,
|
||||
await erc1155.getAll(queryParams),
|
||||
);
|
||||
return await erc1155.getAll(queryParams);
|
||||
}
|
||||
invariant(false, "Unknown NFT type");
|
||||
},
|
||||
@@ -278,22 +229,16 @@ export function useOwnedNFTs<TContract extends NFTContract>(
|
||||
const contractAddress = contract?.getAddress();
|
||||
const { erc721, erc1155 } = getErcs(contract);
|
||||
|
||||
return useQueryWithNetwork<NFT<Erc721OrErc1155>[]>(
|
||||
return useQueryWithNetwork<NFT[]>(
|
||||
cacheKeys.contract.nft.query.owned.all(contractAddress, ownerWalletAddress),
|
||||
async () => {
|
||||
invariant(contract, "No Contract instance provided");
|
||||
invariant(ownerWalletAddress, "No wallet address provided");
|
||||
if (erc721) {
|
||||
return convertResponseToNFTTypeArray(
|
||||
erc721,
|
||||
await erc721.getOwned(ownerWalletAddress),
|
||||
);
|
||||
return await erc721.getOwned(ownerWalletAddress);
|
||||
}
|
||||
if (erc1155) {
|
||||
return convertResponseToNFTTypeArray(
|
||||
erc1155,
|
||||
await erc1155.getOwned(ownerWalletAddress),
|
||||
);
|
||||
return await erc1155.getOwned(ownerWalletAddress);
|
||||
}
|
||||
invariant(false, "Unknown NFT type");
|
||||
},
|
||||
|
||||
@@ -2,7 +2,9 @@ import { RequiredParam } from "../../../core/types/shared";
|
||||
import { useSDKChainId } from "../../providers/base";
|
||||
import {
|
||||
ClaimTokenParams,
|
||||
getErc20,
|
||||
TokenBurnParams,
|
||||
TokenContract,
|
||||
TokenParams,
|
||||
WalletAddress,
|
||||
} from "../../types";
|
||||
@@ -12,7 +14,6 @@ import {
|
||||
} from "../../utils/cache-keys";
|
||||
import { useQueryWithNetwork } from "../query-utils/useQueryWithNetwork";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import type { Erc20 } from "@thirdweb-dev/sdk";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
/** **********************/
|
||||
@@ -24,21 +25,26 @@ import invariant from "tiny-invariant";
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* const { data: totalSupply, isLoading, error } = useTokenSupply(<YourTokenContractInstance>);
|
||||
* const { contract } = useContract(<ContractAddress>);
|
||||
* const { data: totalSupply, isLoading, error } = useTokenSupply(contract);
|
||||
* ```
|
||||
*
|
||||
* @param contract - an instance of a ERC20 contract.
|
||||
* @param contract - an instance of a {@link TokenContract}
|
||||
* @returns a response object that incudes the total minted supply
|
||||
* @twfeature ERC20
|
||||
* @beta
|
||||
*/
|
||||
export function useTokenSupply(contract: RequiredParam<Erc20>) {
|
||||
export function useTokenSupply(contract: RequiredParam<TokenContract>) {
|
||||
const contractAddress = contract?.getAddress();
|
||||
return useQueryWithNetwork(
|
||||
cacheKeys.contract.token.totalSupply(contractAddress),
|
||||
() => {
|
||||
invariant(contract, "No Contract instance provided");
|
||||
return contract.totalSupply();
|
||||
const erc20 = getErc20(contract);
|
||||
if (erc20) {
|
||||
return erc20.totalSupply();
|
||||
}
|
||||
invariant(false, "Smart contract is not a valid erc20 contract");
|
||||
},
|
||||
{
|
||||
enabled: !!contract || !!contractAddress,
|
||||
@@ -51,26 +57,32 @@ export function useTokenSupply(contract: RequiredParam<Erc20>) {
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* const { data: balance, isLoading, error } = useTokenBalance(<YourTokenContractInstance>);
|
||||
* const { contract } = useContract(<ContractAddress>);
|
||||
* const { data: balance, isLoading, error } = useTokenBalance(contract);
|
||||
* ```
|
||||
*
|
||||
* @param contract - an instance of a ERC20 contract.
|
||||
* @param contract - an instance of a {@link TokenContract}
|
||||
* @returns a response object that includes the balance of the address
|
||||
* @twfeature ERC20
|
||||
* @beta
|
||||
*/
|
||||
export function useTokenBalance(
|
||||
contract: RequiredParam<Erc20>,
|
||||
contract: RequiredParam<TokenContract>,
|
||||
walletAddress: RequiredParam<WalletAddress>,
|
||||
) {
|
||||
const contractAddress = contract?.getAddress();
|
||||
const erc20 = getErc20(contract);
|
||||
return useQueryWithNetwork(
|
||||
cacheKeys.contract.token.balanceOf(contractAddress, walletAddress),
|
||||
async () => {
|
||||
invariant(contract, "No Contract instance provided");
|
||||
invariant(walletAddress, "No address provided");
|
||||
return await contract.balanceOf(walletAddress);
|
||||
if (erc20) {
|
||||
return await erc20.balanceOf(walletAddress);
|
||||
}
|
||||
invariant(false, "Smart contract is not a valid erc20 contract");
|
||||
},
|
||||
|
||||
{
|
||||
enabled: !!walletAddress && !!contract,
|
||||
},
|
||||
@@ -82,21 +94,27 @@ export function useTokenBalance(
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* const { data: decimals, isLoading, error } = useTokenDecimals(<YourTokenContractInstance>);
|
||||
* const { contract } = useContract(<ContractAddress>);
|
||||
* const { data: decimals, isLoading, error } = useTokenDecimals(contract);
|
||||
* ```
|
||||
*
|
||||
* @param contract - an instance of an ERC20 contract.
|
||||
* @param contract - an instance of a {@link TokenContract}
|
||||
* @returns a response object that includes the decimals of the ERC20 token
|
||||
* @twfeature ERC20
|
||||
* @beta
|
||||
*/
|
||||
export function useTokenDecimals(contract: RequiredParam<Erc20>) {
|
||||
export function useTokenDecimals(contract: RequiredParam<TokenContract>) {
|
||||
const contractAddress = contract?.getAddress();
|
||||
const erc20 = getErc20(contract);
|
||||
return useQueryWithNetwork(
|
||||
cacheKeys.contract.token.decimals(contractAddress),
|
||||
async () => {
|
||||
invariant(contract, "No Contract instance provided");
|
||||
return (await contract.get()).decimals;
|
||||
|
||||
if (erc20) {
|
||||
return (await erc20.get()).decimals;
|
||||
}
|
||||
invariant(false, "Smart contract is not a valid erc20 contract");
|
||||
},
|
||||
{
|
||||
enabled: !!contract,
|
||||
@@ -114,11 +132,12 @@ export function useTokenDecimals(contract: RequiredParam<Erc20>) {
|
||||
* @example
|
||||
* ```jsx
|
||||
* const Component = () => {
|
||||
* const { contract } = useContract(<ContractAddress>);
|
||||
* const {
|
||||
* mutate: mintTokens,
|
||||
* isLoading,
|
||||
* error,
|
||||
* } = useMintToken(">>YourERC20ContractInstance<<");
|
||||
* } = useMintToken(contract);
|
||||
*
|
||||
* if (error) {
|
||||
* console.error("failed to mint tokens", error);
|
||||
@@ -135,21 +154,25 @@ export function useTokenDecimals(contract: RequiredParam<Erc20>) {
|
||||
* };
|
||||
* ```
|
||||
*
|
||||
* @param contract - an instance of a contract that extends the ERC20 spec (token, token drop, custom contract that follows the ERC20 spec)
|
||||
* @param contract - an instance of a {@link TokenContract}
|
||||
* @returns a mutation object that can be used to mint new tokens to the connected wallet
|
||||
* @twfeature ERC20Mintable
|
||||
* @beta
|
||||
*/
|
||||
export function useMintToken(contract: RequiredParam<Erc20>) {
|
||||
export function useMintToken(contract: RequiredParam<TokenContract>) {
|
||||
const activeChainId = useSDKChainId();
|
||||
const contractAddress = contract?.getAddress();
|
||||
const queryClient = useQueryClient();
|
||||
const erc20 = getErc20(contract);
|
||||
|
||||
return useMutation(
|
||||
(data: TokenParams) => {
|
||||
const { to, amount } = data;
|
||||
invariant(contract, "contract is undefined");
|
||||
return contract.mintTo(to, amount);
|
||||
if (erc20) {
|
||||
return erc20.mintTo(to, amount);
|
||||
}
|
||||
invariant(false, "Smart contract is not a valid erc20 contract");
|
||||
},
|
||||
{
|
||||
onSettled: () =>
|
||||
@@ -168,11 +191,12 @@ export function useMintToken(contract: RequiredParam<Erc20>) {
|
||||
* @example
|
||||
* ```jsx
|
||||
* const Component = () => {
|
||||
* const { contract } = useContract(<ContractAddress>);
|
||||
* const {
|
||||
* mutate: claimTokens,
|
||||
* isLoading,
|
||||
* error,
|
||||
* } = useClaimToken(TokenDropContract);
|
||||
* } = useClaimToken(contract);
|
||||
*
|
||||
* if (error) {
|
||||
* console.error("failed to claim tokens", error);
|
||||
@@ -189,27 +213,29 @@ export function useMintToken(contract: RequiredParam<Erc20>) {
|
||||
* };
|
||||
* ```
|
||||
*
|
||||
* @param contract - an instance of a {@link Erc20}
|
||||
* @param contract - an instance of a {@link TokenContract}
|
||||
* @returns a mutation object that can be used to tokens to the wallet specificed in the params
|
||||
* @twfeature ERC20ClaimableWithConditions
|
||||
* @beta
|
||||
*/
|
||||
export function useClaimToken<TContract extends Erc20>(
|
||||
contract: RequiredParam<TContract>,
|
||||
) {
|
||||
export function useClaimToken(contract: RequiredParam<TokenContract>) {
|
||||
const activeChainId = useSDKChainId();
|
||||
const contractAddress = contract?.getAddress();
|
||||
const queryClient = useQueryClient();
|
||||
const erc20 = getErc20(contract);
|
||||
|
||||
return useMutation(
|
||||
async (data: ClaimTokenParams) => {
|
||||
invariant(data.to, 'No "to" address provided');
|
||||
invariant(contract?.claimTo, "contract does not support claimTo");
|
||||
return await contract.claimTo(
|
||||
data.to,
|
||||
data.amount,
|
||||
data.checkERC20Allowance,
|
||||
);
|
||||
if (erc20) {
|
||||
invariant(erc20?.claimTo, "contract does not support claimTo");
|
||||
return await erc20.claimTo(
|
||||
data.to,
|
||||
data.amount,
|
||||
data.checkERC20Allowance,
|
||||
);
|
||||
}
|
||||
invariant(false, "Smart contract is not a valid erc20 contract");
|
||||
},
|
||||
{
|
||||
onSettled: () =>
|
||||
@@ -228,11 +254,12 @@ export function useClaimToken<TContract extends Erc20>(
|
||||
* @example
|
||||
* ```jsx
|
||||
* const Component = () => {
|
||||
* const { contract } = useContract(<ContractAddress>);
|
||||
* const {
|
||||
* mutate: transferTokens,
|
||||
* isLoading,
|
||||
* error,
|
||||
* } = useTransferToken(">>YourERC20ContractInstance<<");
|
||||
* } = useTransferToken(contract);
|
||||
*
|
||||
* if (error) {
|
||||
* console.error("failed to transfer tokens", error);
|
||||
@@ -249,21 +276,25 @@ export function useClaimToken<TContract extends Erc20>(
|
||||
* };
|
||||
* ```
|
||||
*
|
||||
* @param contract - an instance of a contract that extends the ERC20 spec (token, token drop, custom contract that follows the ERC20 spec)
|
||||
* @param contract - an instance of a {@link TokenContract}
|
||||
* @returns a mutation object that can be used to transfer tokens
|
||||
* @twfeature ERC20
|
||||
* @beta
|
||||
*/
|
||||
export function useTransferToken(contract: RequiredParam<Erc20>) {
|
||||
export function useTransferToken(contract: RequiredParam<TokenContract>) {
|
||||
const activeChainId = useSDKChainId();
|
||||
const contractAddress = contract?.getAddress();
|
||||
const queryClient = useQueryClient();
|
||||
const erc20 = getErc20(contract);
|
||||
|
||||
return useMutation(
|
||||
(data: TokenParams) => {
|
||||
const { to, amount } = data;
|
||||
invariant(contract?.transfer, "contract does not support transfer");
|
||||
return contract.transfer(to, amount);
|
||||
if (erc20) {
|
||||
invariant(erc20?.transfer, "contract does not support transfer");
|
||||
return erc20.transfer(to, amount);
|
||||
}
|
||||
invariant(false, "Smart contract is not a valid erc20 contract");
|
||||
},
|
||||
{
|
||||
onSettled: () =>
|
||||
@@ -282,11 +313,12 @@ export function useTransferToken(contract: RequiredParam<Erc20>) {
|
||||
* @example
|
||||
* ```jsx
|
||||
* const Component = () => {
|
||||
* const { contract } = useContract(<ContractAddress>);
|
||||
* const {
|
||||
* mutate: transferBatchTokens,
|
||||
* isLoading,
|
||||
* error,
|
||||
* } = useTransferToken(">>YourERC20ContractInstance<<");
|
||||
* } = useTransferToken(contract);
|
||||
*
|
||||
* if (error) {
|
||||
* console.error("failed to transfer batch tokens", error);
|
||||
@@ -303,28 +335,32 @@ export function useTransferToken(contract: RequiredParam<Erc20>) {
|
||||
* };
|
||||
* ```
|
||||
*
|
||||
* @param contract - an instance of a contract that extends the ERC20 spec (token, token drop, custom contract that follows the ERC20 spec)
|
||||
* @param contract - an instance of a {@link TokenContract}
|
||||
* @returns a mutation object that can be used to transfer batch tokens
|
||||
* @twfeature ERC20
|
||||
* @beta
|
||||
*/
|
||||
export function useTransferBatchToken(contract: RequiredParam<Erc20>) {
|
||||
export function useTransferBatchToken(contract: RequiredParam<TokenContract>) {
|
||||
const activeChainId = useSDKChainId();
|
||||
const contractAddress = contract?.getAddress();
|
||||
const queryClient = useQueryClient();
|
||||
const erc20 = getErc20(contract);
|
||||
|
||||
return useMutation(
|
||||
(data: TokenParams[]) => {
|
||||
invariant(
|
||||
contract?.transferBatch,
|
||||
"contract does not support transferBatch",
|
||||
);
|
||||
const convertedData = data.map((token) => ({
|
||||
toAddress: token.to,
|
||||
amount: token.amount,
|
||||
}));
|
||||
if (erc20) {
|
||||
invariant(
|
||||
erc20?.transferBatch,
|
||||
"contract does not support transferBatch",
|
||||
);
|
||||
const convertedData = data.map((token) => ({
|
||||
toAddress: token.to,
|
||||
amount: token.amount,
|
||||
}));
|
||||
|
||||
return contract.transferBatch(convertedData);
|
||||
return erc20.transferBatch(convertedData);
|
||||
}
|
||||
invariant(false, "Smart contract is not a valid erc20 contract");
|
||||
},
|
||||
{
|
||||
onSettled: () =>
|
||||
@@ -343,11 +379,12 @@ export function useTransferBatchToken(contract: RequiredParam<Erc20>) {
|
||||
* @example
|
||||
* ```jsx
|
||||
* const Component = () => {
|
||||
* const { contract } = useContract(<ContractAddress>);
|
||||
* const {
|
||||
* mutate: burnTokens,
|
||||
* isLoading,
|
||||
* error,
|
||||
* } = useBurnToken(">>YourERC20ContractInstance<<");
|
||||
* } = useBurnToken(contract);
|
||||
*
|
||||
* if (error) {
|
||||
* console.error("failed to burn tokens", error);
|
||||
@@ -364,21 +401,26 @@ export function useTransferBatchToken(contract: RequiredParam<Erc20>) {
|
||||
* };
|
||||
* ```
|
||||
*
|
||||
* @param contract - an instance of a contract that extends the ERC20 spec (token, token drop, custom contract that follows the ERC20 spec)
|
||||
* @param contract - an instance of a {@link TokenContract}
|
||||
* @returns a mutation object that can be used to burn tokens from the connected wallet
|
||||
* @twfeature ERC20Burnable
|
||||
* @beta
|
||||
*/
|
||||
export function useBurnToken(contract: RequiredParam<Erc20>) {
|
||||
export function useBurnToken(contract: RequiredParam<TokenContract>) {
|
||||
const activeChainId = useSDKChainId();
|
||||
const contractAddress = contract?.getAddress();
|
||||
const queryClient = useQueryClient();
|
||||
const erc20 = getErc20(contract);
|
||||
|
||||
return useMutation(
|
||||
(data: TokenBurnParams) => {
|
||||
const { amount } = data;
|
||||
invariant(contract, "contract is undefined");
|
||||
return contract.burn(amount);
|
||||
if (erc20) {
|
||||
invariant(erc20?.burn, "contract does not support burn");
|
||||
return erc20.burn(amount);
|
||||
}
|
||||
invariant(false, "Smart contract is not a valid erc20 contract");
|
||||
},
|
||||
{
|
||||
onSettled: () =>
|
||||
|
||||
@@ -2,6 +2,9 @@ import { useConnect } from "../wagmi-required/useConnect";
|
||||
import invariant from "tiny-invariant";
|
||||
import { useContext as useWagmiContext } from "wagmi";
|
||||
|
||||
if (!globalThis.Buffer) {
|
||||
globalThis.Buffer = require("buffer/").Buffer;
|
||||
}
|
||||
/**
|
||||
* Hook for connecting to a mobile wallet with Wallet Connect
|
||||
*
|
||||
|
||||
@@ -2,6 +2,9 @@ import { useConnect } from "../wagmi-required/useConnect";
|
||||
import invariant from "tiny-invariant";
|
||||
import { useContext as useWagmiContext } from "wagmi";
|
||||
|
||||
if (!globalThis.Buffer) {
|
||||
globalThis.Buffer = require("buffer/").Buffer;
|
||||
}
|
||||
/**
|
||||
* Hook for connecting to a Coinbase wallet.
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import { showDeprecationWarning } from "../../utils/deprecation-warning";
|
||||
import { useContract } from "../async/contracts";
|
||||
import { Edition } from "@thirdweb-dev/sdk/dist/declarations/src/evm/contracts/prebuilt-implementations/edition";
|
||||
|
||||
/**
|
||||
* Hook for getting an instance of an `Edition` contract. This contract is used to interface with ERC1155 compliant NFTs.
|
||||
@@ -8,16 +8,16 @@ import { Edition } from "@thirdweb-dev/sdk/dist/declarations/src/evm/contracts/p
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* import { useEdition } from '@thirdweb-dev/react'
|
||||
* import { useContract } from '@thirdweb-dev/react'
|
||||
*
|
||||
* export default function Component() {
|
||||
* const edition = useEdition("<YOUR-CONTRACT-ADDRESS>")
|
||||
* const { contract } = useContract("<YOUR-CONTRACT-ADDRESS>", "edition")
|
||||
*
|
||||
* // Now you can use the edition contract in the rest of the component
|
||||
*
|
||||
* // For example, this function will return all the NFTs on this contract
|
||||
* async function getNFTs() {
|
||||
* const nfts = await edition.getAll()
|
||||
* const nfts = await contract.getAll()
|
||||
* return nfts
|
||||
* }
|
||||
*
|
||||
@@ -25,9 +25,17 @@ import { Edition } from "@thirdweb-dev/sdk/dist/declarations/src/evm/contracts/p
|
||||
* }
|
||||
* ```
|
||||
* @public
|
||||
* @deprecated use `useContract()` instead
|
||||
* @deprecated
|
||||
* This hook is deprecated and will be removed in a future major version. You should use {@link useContract} instead.
|
||||
* ```diff
|
||||
* - const edition = await sdk.useEdition("0x1234...");
|
||||
* + const edition = await sdk.useContract("0x1234...", "edition").contract;
|
||||
* ```
|
||||
*/
|
||||
export function useEdition(contractAddress?: string) {
|
||||
showDeprecationWarning("useEdition()", "useContract<Edition>()");
|
||||
return useContract<Edition>(contractAddress).contract;
|
||||
export function useEdition(contractAddress: RequiredParam<string>) {
|
||||
showDeprecationWarning(
|
||||
`useEdition("${contractAddress || "0x..."}")`,
|
||||
`useContract("${contractAddress || "0x..."}", "edition")`,
|
||||
);
|
||||
return useContract(contractAddress, "edition").contract;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import { showDeprecationWarning } from "../../utils/deprecation-warning";
|
||||
import { useContract } from "../async/contracts";
|
||||
import { EditionDrop } from "@thirdweb-dev/sdk/dist/declarations/src/evm/contracts/prebuilt-implementations/edition-drop";
|
||||
|
||||
/**
|
||||
* Hook for getting an instance of an `EditionDrop` contract. This conract is used to interface with ERC1155 compliant NFTs that can be lazily minted.
|
||||
@@ -8,25 +8,33 @@ import { EditionDrop } from "@thirdweb-dev/sdk/dist/declarations/src/evm/contrac
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* import { useEditionDrop } from '@thirdweb-dev/react'
|
||||
* import { useContract } from '@thirdweb-dev/react'
|
||||
*
|
||||
* export default function Component() {
|
||||
* const editionDrop = useEditionDrop("<YOUR-CONTRACT-ADDRESS>")
|
||||
* const { contract } = useContract("<YOUR-CONTRACT-ADDRESS>", "edition-drop")
|
||||
*
|
||||
* // Now you can use the edition drop contract in the rest of the component
|
||||
*
|
||||
* // For example, this function will let the connected wallet claim a new NFT
|
||||
* async function claim(tokenId, quantity) {
|
||||
* await editionDrop.claim(tokenId, quantity)
|
||||
* await contract.claim(tokenId, quantity)
|
||||
* }
|
||||
*
|
||||
* ...
|
||||
* }
|
||||
* ```
|
||||
* @public
|
||||
* @deprecated use `useContract()` instead
|
||||
* @deprecated
|
||||
* This hook is deprecated and will be removed in a future major version. You should use {@link useContract} instead.
|
||||
* ```diff
|
||||
* - const editionDrop = await sdk.useEditionDrop("0x1234...");
|
||||
* + const editionDrop = await sdk.useContract("0x1234...", "edition-drop").contract;
|
||||
* ```
|
||||
*/
|
||||
export function useEditionDrop(contractAddress?: string) {
|
||||
showDeprecationWarning("useEditionDrop()", "useContract<EditionDrop>()");
|
||||
return useContract<EditionDrop>(contractAddress).contract;
|
||||
export function useEditionDrop(contractAddress: RequiredParam<string>) {
|
||||
showDeprecationWarning(
|
||||
`useEditionDrop("${contractAddress || "0x..."}")`,
|
||||
`useContract("${contractAddress || "0x..."}", "edition-drop")`,
|
||||
);
|
||||
return useContract(contractAddress, "edition-drop").contract;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import { showDeprecationWarning } from "../../utils/deprecation-warning";
|
||||
import { useContract } from "../async/contracts";
|
||||
import { Marketplace } from "@thirdweb-dev/sdk/dist/declarations/src/evm/contracts/prebuilt-implementations/marketplace";
|
||||
|
||||
/**
|
||||
* Hook for getting an instance of a `Marketplace` contract. This contract is used to support marketplace for purchase and sale of on-chain assets.
|
||||
@@ -8,16 +8,16 @@ import { Marketplace } from "@thirdweb-dev/sdk/dist/declarations/src/evm/contrac
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* import { useMarketplace } from '@thirdweb-dev/react'
|
||||
* import { useContract } from '@thirdweb-dev/react'
|
||||
*
|
||||
* export default function Component() {
|
||||
* const marketplace = useMarketplace("<YOUR-CONTRACT-ADDRESS>")
|
||||
* const { contract } = useContract("<YOUR-CONTRACT-ADDRESS>", "marketplace")
|
||||
*
|
||||
* // Now you can use the marketplace contract in the rest of the component
|
||||
*
|
||||
* // For example, this function will return all the listings on the marketplace
|
||||
* async function getListings() {
|
||||
* const listings = await marketplace.getAll()
|
||||
* const listings = await contract.getAll()
|
||||
* return listings
|
||||
* }
|
||||
*
|
||||
@@ -25,9 +25,17 @@ import { Marketplace } from "@thirdweb-dev/sdk/dist/declarations/src/evm/contrac
|
||||
* }
|
||||
* ```
|
||||
* @public
|
||||
* @deprecated use `useContract()` instead
|
||||
* @deprecated
|
||||
* This hook is deprecated and will be removed in a future major version. You should use {@link useContract} instead.
|
||||
* ```diff
|
||||
* - const marketplace = await sdk.useMarketplace("0x1234...");
|
||||
* + const marketplace = await sdk.useContract("0x1234...", "marketplace").contract;
|
||||
* ```
|
||||
*/
|
||||
export function useMarketplace(contractAddress?: string) {
|
||||
showDeprecationWarning("useMarketplace()", "useContract<Marketplace>()");
|
||||
return useContract<Marketplace>(contractAddress).contract;
|
||||
export function useMarketplace(contractAddress: RequiredParam<string>) {
|
||||
showDeprecationWarning(
|
||||
`useMarketplace("${contractAddress || "0x..."}")`,
|
||||
`useContract("${contractAddress || "0x..."}", "marketplace")`,
|
||||
);
|
||||
return useContract(contractAddress, "marketplace").contract;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import { showDeprecationWarning } from "../../utils/deprecation-warning";
|
||||
import { useContract } from "../async/contracts";
|
||||
import { Multiwrap } from "@thirdweb-dev/sdk/dist/declarations/src/evm/contracts/prebuilt-implementations/multiwrap";
|
||||
|
||||
/**
|
||||
* Hook for getting an instance of an `Multiwrap` contract. This contract is an ERC721 in which you can wrap ERC721, ERC1155 and ERC20 tokens.
|
||||
@@ -8,25 +8,33 @@ import { Multiwrap } from "@thirdweb-dev/sdk/dist/declarations/src/evm/contracts
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* import { useMultiwrap } from '@thirdweb-dev/react'
|
||||
* import { useContract } from '@thirdweb-dev/react'
|
||||
*
|
||||
* export default function Component() {
|
||||
* const multiwrap = useMultiwrap("<YOUR-CONTRACT-ADDRESS>")
|
||||
* const { contract } = useContract("<YOUR-CONTRACT-ADDRESS>", "multiwrap")
|
||||
*
|
||||
* // Now you can use the multiwrap contract in the rest of the component
|
||||
*
|
||||
* // For example, this function will let the connected wallet wrap tokens
|
||||
* async function wrap(tokensToWrap, wrappedNFTMetadata) {
|
||||
* await multiwrap.wrap(tokensToWrap, wrappedNFTMetadata)
|
||||
* await contract.wrap(tokensToWrap, wrappedNFTMetadata)
|
||||
* }
|
||||
*
|
||||
* ...
|
||||
* }
|
||||
* ```
|
||||
* @public
|
||||
* @deprecated use `useContract()` instead
|
||||
* @deprecated
|
||||
* This hook is deprecated and will be removed in a future major version. You should use {@link useContract} instead.
|
||||
* ```diff
|
||||
* - const multiwrap = await sdk.useMultiwrap("0x1234...");
|
||||
* + const multiwrap = await sdk.useContract("0x1234...", "multiwrap").contract;
|
||||
* ```
|
||||
*/
|
||||
export function useMultiwrap(contractAddress?: string) {
|
||||
showDeprecationWarning("useMultiwrap()", "useContract<Multiwrap>()");
|
||||
return useContract<Multiwrap>(contractAddress).contract;
|
||||
export function useMultiwrap(contractAddress: RequiredParam<string>) {
|
||||
showDeprecationWarning(
|
||||
`useMultiwrap("${contractAddress || "0x..."}")`,
|
||||
`useContract("${contractAddress || "0x..."}", "multiwrap")`,
|
||||
);
|
||||
return useContract(contractAddress, "multiwrap").contract;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import { showDeprecationWarning } from "../../utils/deprecation-warning";
|
||||
import { useContract } from "../async/contracts";
|
||||
import { NFTCollection } from "@thirdweb-dev/sdk/dist/declarations/src/evm/contracts/prebuilt-implementations/nft-collection";
|
||||
|
||||
/**
|
||||
* Hook for getting an instance of an `NFTCollection` contract. This contract is meant to interface with ERC721 compliant NFTs.
|
||||
@@ -8,16 +8,16 @@ import { NFTCollection } from "@thirdweb-dev/sdk/dist/declarations/src/evm/contr
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* import { useNFTCollection } from '@thirdweb-dev/react'
|
||||
* import { useContract } from '@thirdweb-dev/react'
|
||||
*
|
||||
* export default function Component() {
|
||||
* const nftCollection = useNFTCollection("<YOUR-CONTRACT-ADDRESS>")
|
||||
* const { contract } = useNFTCollection("<YOUR-CONTRACT-ADDRESS>", "nft-collection")
|
||||
*
|
||||
* // Now you can use the nftCollection contract in the rest of the component
|
||||
*
|
||||
* // For example, this function will return all the NFTs on this contract
|
||||
* async function getNFTs() {
|
||||
* const nfts = await nftCollection.getAll()
|
||||
* const nfts = await contract.getAll()
|
||||
* return nfts
|
||||
* }
|
||||
*
|
||||
@@ -25,9 +25,17 @@ import { NFTCollection } from "@thirdweb-dev/sdk/dist/declarations/src/evm/contr
|
||||
* }
|
||||
* ```
|
||||
* @public
|
||||
* @deprecated use `useContract()` instead
|
||||
* @deprecated
|
||||
* This hook is deprecated and will be removed in a future major version. You should use {@link useContract} instead.
|
||||
* ```diff
|
||||
* - const nftCollection = await sdk.useNFTCollection("0x1234...");
|
||||
* + const nftCollection = await sdk.useContract("0x1234...", "nft-collection").contract;
|
||||
* ```
|
||||
*/
|
||||
export function useNFTCollection(contractAddress?: string) {
|
||||
showDeprecationWarning("useNFTCollection()", "useContract<NFTCollection>()");
|
||||
return useContract<NFTCollection>(contractAddress).contract;
|
||||
export function useNFTCollection(contractAddress: RequiredParam<string>) {
|
||||
showDeprecationWarning(
|
||||
`useNFTCollection("${contractAddress || "0x..."}")`,
|
||||
`useContract("${contractAddress || "0x..."}", "nft-collection")`,
|
||||
);
|
||||
return useContract(contractAddress, "nft-collection").contract;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import { showDeprecationWarning } from "../../utils/deprecation-warning";
|
||||
import { useContract } from "../async/contracts";
|
||||
import { NFTDrop } from "@thirdweb-dev/sdk/dist/declarations/src/evm/contracts/prebuilt-implementations/nft-drop";
|
||||
|
||||
/**
|
||||
* Hook for getting an instance of an `NFTDrop` contract. This contract is meant to interface with ERC721 compliant NFTs that can be lazily minted.
|
||||
@@ -8,25 +8,33 @@ import { NFTDrop } from "@thirdweb-dev/sdk/dist/declarations/src/evm/contracts/p
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* import { useNFTDrop } from '@thirdweb-dev/react'
|
||||
* import { useContract } from '@thirdweb-dev/react'
|
||||
*
|
||||
* export default function Component() {
|
||||
* const nftDrop = useNFTDrop("<YOUR-CONTRACT-ADDRESS>")
|
||||
* const { contract } = useContract("<YOUR-CONTRACT-ADDRESS>", "nft-drop")
|
||||
*
|
||||
* // Now you can use the nft drop contract in the rest of the component
|
||||
*
|
||||
* // For example, this function will let the connected wallet claim a new NFT
|
||||
* async function claim(quantity) {
|
||||
* await nftDrop.claim(quantity)
|
||||
* await contract.claim(quantity)
|
||||
* }
|
||||
*
|
||||
* ...
|
||||
* }
|
||||
* ```
|
||||
* @public
|
||||
* @deprecated use `useContract()` instead
|
||||
* @deprecated
|
||||
* This hook is deprecated and will be removed in a future major version. You should use {@link useContract} instead.
|
||||
* ```diff
|
||||
* - const nftDrop = await sdk.useNFTDrop("0x1234...");
|
||||
* + const nftDrop = await sdk.useContract("0x1234...", "nft-drop").contract;
|
||||
* ```
|
||||
*/
|
||||
export function useNFTDrop(contractAddress?: string) {
|
||||
showDeprecationWarning("useNFTDrop()", "useContract<NFTDrop>()");
|
||||
return useContract<NFTDrop>(contractAddress).contract;
|
||||
export function useNFTDrop(contractAddress: RequiredParam<string>) {
|
||||
showDeprecationWarning(
|
||||
`useNFTDrop("${contractAddress || "0x..."}")`,
|
||||
`useContract("${contractAddress || "0x..."}", "nft-drop")`,
|
||||
);
|
||||
return useContract(contractAddress, "nft-drop").contract;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import { showDeprecationWarning } from "../../utils/deprecation-warning";
|
||||
import { useContract } from "../async/contracts";
|
||||
import { Pack } from "@thirdweb-dev/sdk/dist/declarations/src/evm/contracts/prebuilt-implementations/pack";
|
||||
|
||||
/**
|
||||
* Hook for getting an instance of a `Pack` contract. This contract supports the creation of on-chain luck-based lootboxes.
|
||||
@@ -8,16 +8,16 @@ import { Pack } from "@thirdweb-dev/sdk/dist/declarations/src/evm/contracts/preb
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* import { usePack } from '@thirdweb-dev/react'
|
||||
* import { useContract } from '@thirdweb-dev/react'
|
||||
*
|
||||
* export default function Component() {
|
||||
* const pack = usePack("<YOUR-CONTRACT-ADDRESS>")
|
||||
* const { contract } = usePack("<YOUR-CONTRACT-ADDRESS>", "pack")
|
||||
*
|
||||
* // Now you can use the pack contract in the rest of the component
|
||||
*
|
||||
* // For example, this function will get all the packs on this contract
|
||||
* async function getPacks() {
|
||||
* const packs = await pack.getAll()
|
||||
* const packs = await contract.getAll()
|
||||
* return packs
|
||||
* }
|
||||
*
|
||||
@@ -25,9 +25,17 @@ import { Pack } from "@thirdweb-dev/sdk/dist/declarations/src/evm/contracts/preb
|
||||
* }
|
||||
* ```
|
||||
* @public
|
||||
* @deprecated use `useContract()` instead
|
||||
* @deprecated
|
||||
* This hook is deprecated and will be removed in a future major version. You should use {@link useContract} instead.
|
||||
* ```diff
|
||||
* - const pack = await sdk.usePack("0x1234...");
|
||||
* + const pack = await sdk.useContract("0x1234...", "pack").contract;
|
||||
* ```
|
||||
*/
|
||||
export function usePack(contractAddress?: string) {
|
||||
showDeprecationWarning("usePack()", "useContract<Pack>()");
|
||||
return useContract<Pack>(contractAddress).contract;
|
||||
export function usePack(contractAddress: RequiredParam<string>) {
|
||||
showDeprecationWarning(
|
||||
`usePack("${contractAddress || "0x..."}")`,
|
||||
`useContract("${contractAddress || "0x..."}", "pack")`,
|
||||
);
|
||||
return useContract(contractAddress, "pack").contract;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import { showDeprecationWarning } from "../../utils/deprecation-warning";
|
||||
import { useContract } from "../async/contracts";
|
||||
import { SignatureDrop } from "@thirdweb-dev/sdk/dist/declarations/src/evm/contracts/prebuilt-implementations/signature-drop";
|
||||
|
||||
/**
|
||||
* Hook for getting an instance of an `SignatureDrop` contract. This contract is meant to interface with ERC721 compliant NFTs that can be lazily minted.
|
||||
@@ -8,25 +8,33 @@ import { SignatureDrop } from "@thirdweb-dev/sdk/dist/declarations/src/evm/contr
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* import { useSignatureDrop } from '@thirdweb-dev/react'
|
||||
* import { useContract } from '@thirdweb-dev/react'
|
||||
*
|
||||
* export default function Component() {
|
||||
* const signatureDrop = useSignatureDrop("<YOUR-CONTRACT-ADDRESS>")
|
||||
* const { contract } = useContract("<YOUR-CONTRACT-ADDRESS>", "signature-drop")
|
||||
*
|
||||
* // Now you can use the Signature drop contract in the rest of the component
|
||||
*
|
||||
* // For example, this function will let the connected wallet claim a new NFT
|
||||
* async function claim(quantity) {
|
||||
* await signatureDrop.claim(quantity)
|
||||
* await contract.claim(quantity)
|
||||
* }
|
||||
*
|
||||
* ...
|
||||
* }
|
||||
* ```
|
||||
* @public
|
||||
* @deprecated use `useContract()` instead
|
||||
* @deprecated
|
||||
* This hook is deprecated and will be removed in a future major version. You should use {@link useContract} instead.
|
||||
* ```diff
|
||||
* - const signatureDrop = await sdk.useSignatureDrop("0x1234...");
|
||||
* + const signatureDrop = await sdk.useContract("0x1234...", "signature-drop").contract;
|
||||
* ```
|
||||
*/
|
||||
export function useSignatureDrop(contractAddress?: string) {
|
||||
showDeprecationWarning("useSignatureDrop()", "useContract<SignatureDrop>()");
|
||||
return useContract<SignatureDrop>(contractAddress).contract;
|
||||
export function useSignatureDrop(contractAddress?: RequiredParam<string>) {
|
||||
showDeprecationWarning(
|
||||
`useSignatureDrop("${contractAddress || "0x..."}")`,
|
||||
`useContract("${contractAddress || "0x..."}", "signature-drop")`,
|
||||
);
|
||||
return useContract(contractAddress, "signature-drop").contract;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import { showDeprecationWarning } from "../../utils/deprecation-warning";
|
||||
import { useContract } from "../async/contracts";
|
||||
import { Split } from "@thirdweb-dev/sdk/dist/declarations/src/evm/contracts/prebuilt-implementations/split";
|
||||
|
||||
/**
|
||||
* Hook for getting an instance of a `Split` contract. This contract supports fund distribution to multiple parties.
|
||||
@@ -8,16 +8,16 @@ import { Split } from "@thirdweb-dev/sdk/dist/declarations/src/evm/contracts/pre
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* import { useSplit } from '@thirdweb-dev/react'
|
||||
* import { useContract } from '@thirdweb-dev/react'
|
||||
*
|
||||
* export default function Component() {
|
||||
* const split = useSplit("<YOUR-CONTRACT-ADDRESS>")
|
||||
* const { contract } = useContract("<YOUR-CONTRACT-ADDRESS>", "split")
|
||||
*
|
||||
* // Now you can use the split contract in the rest of the component
|
||||
*
|
||||
* // For example, this function will retrun all the receipients of the split
|
||||
* async function getRecipients() {
|
||||
* const recipients = await split.getAllRecipients()
|
||||
* const recipients = await contract.getAllRecipients()
|
||||
* return recipients
|
||||
* }
|
||||
*
|
||||
@@ -25,9 +25,17 @@ import { Split } from "@thirdweb-dev/sdk/dist/declarations/src/evm/contracts/pre
|
||||
* }
|
||||
* ```
|
||||
* @public
|
||||
* @deprecated use `useContract()` instead
|
||||
* @deprecated
|
||||
* This hook is deprecated and will be removed in a future major version. You should use {@link useContract} instead.
|
||||
* ```diff
|
||||
* - const split = await sdk.useSplit("0x1234...");
|
||||
* + const split = await sdk.useContract("0x1234...", "split").contract;
|
||||
* ```
|
||||
*/
|
||||
export function useSplit(contractAddress?: string) {
|
||||
showDeprecationWarning("useSplit()", "useContract<Split>()");
|
||||
return useContract<Split>(contractAddress).contract;
|
||||
export function useSplit(contractAddress: RequiredParam<string>) {
|
||||
showDeprecationWarning(
|
||||
`useSplit("${contractAddress || "0x..."}")`,
|
||||
`useContract("${contractAddress || "0x..."}", "split")`,
|
||||
);
|
||||
return useContract(contractAddress, "split").contract;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import { showDeprecationWarning } from "../../utils/deprecation-warning";
|
||||
import { useContract } from "../async/contracts";
|
||||
import { Token } from "@thirdweb-dev/sdk/dist/declarations/src/evm/contracts/prebuilt-implementations/token";
|
||||
|
||||
/**
|
||||
* Hook for getting an instance of a `Token` contract. This contract supports ERC20 compliant tokens.
|
||||
@@ -8,16 +8,16 @@ import { Token } from "@thirdweb-dev/sdk/dist/declarations/src/evm/contracts/pre
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* import { useToken } from '@thirdweb-dev/react'
|
||||
* import { useContract } from '@thirdweb-dev/react'
|
||||
*
|
||||
* export default function Component() {
|
||||
* const token = useToken("<YOUR-CONTRACT-ADDRESS>")
|
||||
* const { contract } = useContract("<YOUR-CONTRACT-ADDRESS>", "token")
|
||||
*
|
||||
* // Now you can use the token contract in the rest of the component
|
||||
*
|
||||
* // For example, this function will get the connected wallets token balance
|
||||
* async function balance() {
|
||||
* const balance = await token.balance()
|
||||
* const balance = await contract.balance()
|
||||
* return balance
|
||||
* }
|
||||
*
|
||||
@@ -25,9 +25,17 @@ import { Token } from "@thirdweb-dev/sdk/dist/declarations/src/evm/contracts/pre
|
||||
* }
|
||||
* ```
|
||||
* @public
|
||||
* @deprecated use `useContract()` instead
|
||||
* @deprecated
|
||||
* This hook is deprecated and will be removed in a future major version. You should use {@link useContract} instead.
|
||||
* ```diff
|
||||
* - const token = await sdk.useToken("0x1234...");
|
||||
* + const token = await sdk.useContract("0x1234...", "token").contract;
|
||||
* ```
|
||||
*/
|
||||
export function useToken(contractAddress?: string) {
|
||||
showDeprecationWarning("useToken()", "useContract<Token>()");
|
||||
return useContract<Token>(contractAddress).contract;
|
||||
export function useToken(contractAddress: RequiredParam<string>) {
|
||||
showDeprecationWarning(
|
||||
`useToken("${contractAddress || "0x..."}")`,
|
||||
`useContract("${contractAddress || "0x..."}", "token")`,
|
||||
);
|
||||
return useContract(contractAddress, "token").contract;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import { showDeprecationWarning } from "../../utils/deprecation-warning";
|
||||
import { useContract } from "../async/contracts";
|
||||
import { TokenDrop } from "@thirdweb-dev/sdk/dist/declarations/src/evm/contracts/prebuilt-implementations/token-drop";
|
||||
|
||||
/**
|
||||
* Hook for getting an instance of a `Token Drop` contract.
|
||||
@@ -8,16 +8,16 @@ import { TokenDrop } from "@thirdweb-dev/sdk/dist/declarations/src/evm/contracts
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* import { useTokenDrop } from '@thirdweb-dev/react'
|
||||
* import { useContract } from '@thirdweb-dev/react'
|
||||
*
|
||||
* export default function Component() {
|
||||
* const tokenDrop = useTokenDrop("<YOUR-CONTRACT-ADDRESS>")
|
||||
* const { contract } = useContract("<YOUR-CONTRACT-ADDRESS>", "token-drop")
|
||||
*
|
||||
* // Now you can use the token drop contract in the rest of the component
|
||||
*
|
||||
* // For example, this function will get the connected wallets token balance
|
||||
* async function balance() {
|
||||
* const balance = await tokenDrop.balance()
|
||||
* const balance = await contract.balance()
|
||||
* return balance
|
||||
* }
|
||||
*
|
||||
@@ -25,9 +25,17 @@ import { TokenDrop } from "@thirdweb-dev/sdk/dist/declarations/src/evm/contracts
|
||||
* }
|
||||
* ```
|
||||
* @public
|
||||
* @deprecated use `useContract()` instead
|
||||
* @deprecated
|
||||
* This hook is deprecated and will be removed in a future major version. You should use {@link useContract} instead.
|
||||
* ```diff
|
||||
* - const token = await sdk.useTokenDrop("0x1234...");
|
||||
* + const token = await sdk.useContract("0x1234...", "token-drop").contract;
|
||||
* ```
|
||||
*/
|
||||
export function useTokenDrop(contractAddress?: string) {
|
||||
showDeprecationWarning("useTokenDrop()", "useContract<TokenDrop>()");
|
||||
return useContract<TokenDrop>(contractAddress).contract;
|
||||
export function useTokenDrop(contractAddress: RequiredParam<string>) {
|
||||
showDeprecationWarning(
|
||||
`useTokenDrop("${contractAddress || "0x..."}")`,
|
||||
`useContract("${contractAddress || "0x..."}", "token-drop")`,
|
||||
);
|
||||
return useContract(contractAddress, "token-drop").contract;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import { showDeprecationWarning } from "../../utils/deprecation-warning";
|
||||
import { useContract } from "../async/contracts";
|
||||
import { Vote } from "@thirdweb-dev/sdk/dist/declarations/src/evm/contracts/prebuilt-implementations/vote";
|
||||
|
||||
/**
|
||||
* Hook for getting an instance of an `Vote` contract. This contract enables fully featured voting-based decentralized governance systems.
|
||||
@@ -8,16 +8,16 @@ import { Vote } from "@thirdweb-dev/sdk/dist/declarations/src/evm/contracts/preb
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* import { useVote } from '@thirdweb-dev/react'
|
||||
* import { useContract } from '@thirdweb-dev/react'
|
||||
*
|
||||
* export default function Component() {
|
||||
* const vote = useVote("<YOUR-CONTRACT-ADDRESS>")
|
||||
* const { contract } = useContract("<YOUR-CONTRACT-ADDRESS>", "vote")
|
||||
*
|
||||
* // Now you can use the vote contract in the rest of the component
|
||||
*
|
||||
* // For example, this function will get all the proposals on this contract
|
||||
* async function getProposals() {
|
||||
* const proposals = await vote.getAll()
|
||||
* const proposals = await contract.getAll()
|
||||
* return proposals
|
||||
* }
|
||||
*
|
||||
@@ -25,9 +25,17 @@ import { Vote } from "@thirdweb-dev/sdk/dist/declarations/src/evm/contracts/preb
|
||||
* }
|
||||
* ```
|
||||
* @public
|
||||
* @deprecated use `useContract()` instead
|
||||
* @deprecated
|
||||
* This hook is deprecated and will be removed in a future major version. You should use {@link useContract} instead.
|
||||
* ```diff
|
||||
* - const vote = await sdk.useVote("0x1234...");
|
||||
* + const vote = await sdk.useContract("0x1234...", "vote").contract;
|
||||
* ```
|
||||
*/
|
||||
export function useVote(contractAddress?: string) {
|
||||
showDeprecationWarning("useVote()", "useContract<Vote>()");
|
||||
return useContract<Vote>(contractAddress).contract;
|
||||
export function useVote(contractAddress: RequiredParam<string>) {
|
||||
showDeprecationWarning(
|
||||
`useVote("${contractAddress || "0x..."}")`,
|
||||
`useContract("${contractAddress || "0x..."}", "vote")`,
|
||||
);
|
||||
return useContract(contractAddress, "vote").contract;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
import { useSDK } from "../../providers/base";
|
||||
|
||||
export * from "./useStorageUpload";
|
||||
|
||||
/**
|
||||
* Get the configured `ThirdwebStorage` instance
|
||||
* @returns The `storageInterface` configured on the `ThirdwebProvider`
|
||||
*/
|
||||
export function useStorage() {
|
||||
const sdk = useSDK();
|
||||
return sdk?.storage;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
import { useSDK } from "../../providers/base";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import { IpfsUploadBatchOptions, UploadOptions } from "@thirdweb-dev/storage";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
interface StorageUploadOptions<T extends UploadOptions> {
|
||||
data: unknown[];
|
||||
options?: T;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook used to upload any files or JSON data to decentralized storage systems like IPFS,
|
||||
* using the `storageInterface` configured on the `ThirdwebProvider`
|
||||
*
|
||||
* @param options - Configure the options for your upload
|
||||
* @returns Function used to upload files or JSON to decentralized storage systems
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* import { useStorageUpload } from "@thirdweb-dev/react";
|
||||
*
|
||||
* export default function Component() {
|
||||
* const { mutateAsync: upload, isLoading } = useStorageUpload();
|
||||
*
|
||||
* async function uploadData() {
|
||||
* const filesToUpload = [...];
|
||||
* const uris = await upload({ data: files });
|
||||
* console.log(uris);
|
||||
* }
|
||||
*
|
||||
* return (
|
||||
* <button onClick={uploadData}>
|
||||
* Upload
|
||||
* </button>
|
||||
* )
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export function useStorageUpload<
|
||||
T extends UploadOptions = IpfsUploadBatchOptions,
|
||||
>(uploadOptions?: T) {
|
||||
const sdk = useSDK();
|
||||
|
||||
return useMutation(async ({ data, options }: StorageUploadOptions<T>) => {
|
||||
invariant(sdk, "sdk must be defined");
|
||||
|
||||
return await sdk.storage.uploadBatch(data, options || uploadOptions);
|
||||
});
|
||||
}
|
||||
@@ -15,8 +15,9 @@ export * from "./hooks/async/claim-conditions";
|
||||
export * from "./hooks/async/contract-settings";
|
||||
export * from "./hooks/async/roles";
|
||||
|
||||
// thirdweb hooks (work as long as at least `<ThirdwebSDkProvider>` is used)
|
||||
// thirdweb hooks (work as long as at least `<ThirdwebSdkProvider>` is used)
|
||||
export * from "./hooks/auth";
|
||||
export * from "./hooks/storage";
|
||||
export * from "./hooks/useSigner";
|
||||
export * from "./hooks/useReadonlySDK";
|
||||
export * from "./hooks/useNetworkMismatch";
|
||||
|
||||
@@ -7,13 +7,13 @@ import type {
|
||||
Erc1155,
|
||||
Erc1155Mintable,
|
||||
ListingType,
|
||||
NFTMetadata,
|
||||
NFTMetadataInput,
|
||||
NFTMetadataOrUri,
|
||||
Price,
|
||||
ValidContractInstance,
|
||||
Erc20,
|
||||
ClaimOptions,
|
||||
NFTMetadataOrUri,
|
||||
Token,
|
||||
} from "@thirdweb-dev/sdk";
|
||||
import type { Edition } from "@thirdweb-dev/sdk/dist/declarations/src/evm/contracts/prebuilt-implementations/edition";
|
||||
import type { EditionDrop } from "@thirdweb-dev/sdk/dist/declarations/src/evm/contracts/prebuilt-implementations/edition-drop";
|
||||
@@ -70,37 +70,22 @@ export type NFTContract =
|
||||
| Edition
|
||||
| Exclude<DropContract, "TokenDrop">;
|
||||
|
||||
/**
|
||||
* The possible Token contract types.
|
||||
* @example
|
||||
* ```javascript
|
||||
* const { contract } = useContract(<ContractAddress>);
|
||||
* ```
|
||||
* @beta
|
||||
*/
|
||||
export type TokenContract = TokenDrop | Token | SmartContract | null;
|
||||
|
||||
/**
|
||||
* Possible NFT contract types.
|
||||
* @beta
|
||||
*/
|
||||
export type Erc721OrErc1155 = Erc721 | Erc1155;
|
||||
|
||||
/**
|
||||
* A single NFT token
|
||||
* @beta
|
||||
*/
|
||||
export type NFT<TContract extends Erc721OrErc1155> = {
|
||||
/**
|
||||
* The actual metadata of the NFT (name, image, etc)
|
||||
*/
|
||||
metadata: NFTMetadata;
|
||||
/**
|
||||
* The owner of the nft (this will be an empty string for ERC1155 tokens)
|
||||
*/
|
||||
owner: string;
|
||||
/**
|
||||
* The type of the NFT (ERC721 or ERC1155)
|
||||
*/
|
||||
type: TContract extends Erc721 ? "ERC721" : "ERC1155";
|
||||
/**
|
||||
* The total supply of the NFT (this will *always* be 1 for ERC721 tokens)
|
||||
*/
|
||||
supply: TContract extends Erc721 ? 1 : number;
|
||||
|
||||
[key: string]: unknown;
|
||||
};
|
||||
|
||||
/**
|
||||
* The params to pass to `useTransferNFT`.
|
||||
* @beta
|
||||
@@ -206,7 +191,7 @@ export type RevealLazyMintInput = {
|
||||
* @beta
|
||||
*/
|
||||
export type ClaimNFTParams = {
|
||||
to: WalletAddress;
|
||||
to?: WalletAddress;
|
||||
quantity: BigNumberish;
|
||||
options?: ClaimOptions;
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
import React, {
|
||||
PropsWithChildren,
|
||||
createContext,
|
||||
useContext,
|
||||
useMemo,
|
||||
} from "react";
|
||||
|
||||
/**
|
||||
* The configuration to use the react SDK with an [auth](https://portal.thirdweb.com/auth) server.
|
||||
*
|
||||
* @beta
|
||||
*/
|
||||
export interface ThirdwebAuthConfig {
|
||||
/**
|
||||
* The backend URL of the authentication endoints. For example, if your endpoints are
|
||||
* at `/api/auth/login`, `/api/auth/logout`, etc. then this should be set to `/api/auth`.
|
||||
*/
|
||||
authUrl: string;
|
||||
|
||||
/**
|
||||
* The frontend domain used to generate the login payload.
|
||||
* This domain should match the domain used on your auth backend.
|
||||
*/
|
||||
domain: string;
|
||||
|
||||
/**
|
||||
* The URL to redirect to after a succesful login.
|
||||
*/
|
||||
loginRedirect?: string;
|
||||
}
|
||||
|
||||
const ThirdwebAuthConfigContext = createContext<ThirdwebAuthConfig | undefined>(
|
||||
undefined,
|
||||
);
|
||||
|
||||
export const ThirdwebAuthConfigProvider: React.FC<
|
||||
PropsWithChildren<{ value?: ThirdwebAuthConfig }>
|
||||
> = ({ value, children }) => {
|
||||
// Remove trailing slash from URL if present
|
||||
const authConfig = useMemo(
|
||||
() =>
|
||||
value
|
||||
? {
|
||||
...value,
|
||||
authUrl: value.authUrl.replace(/\/$/, ""),
|
||||
}
|
||||
: undefined,
|
||||
[value],
|
||||
);
|
||||
return (
|
||||
<ThirdwebAuthConfigContext.Provider value={authConfig}>
|
||||
{children}
|
||||
</ThirdwebAuthConfigContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export function useThirdwebAuthConfig() {
|
||||
return useContext(ThirdwebAuthConfigContext);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import { LoginConfig, useLogin } from "./useLogin";
|
||||
import { useLogout } from "./useLogout";
|
||||
import { useUser } from "./useUser";
|
||||
|
||||
export * from "./useLogin";
|
||||
export * from "./useLogout";
|
||||
export * from "./useUser";
|
||||
|
||||
/**
|
||||
*
|
||||
* @returns
|
||||
* @internal
|
||||
*/
|
||||
export function useAuth(loginConfig?: LoginConfig) {
|
||||
const user = useUser();
|
||||
const login = useLogin(loginConfig);
|
||||
const logout = useLogout();
|
||||
return { ...user, login, logout };
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
import { ensureTWPrefix } from "../../../core/query-utils/query-key";
|
||||
import { useThirdwebAuthConfig } from "../../contexts/thirdweb-auth";
|
||||
import { useSDK } from "../../providers/base";
|
||||
import { useQueryClient } from "@tanstack/react-query";
|
||||
import { LoginOptions } from "@thirdweb-dev/sdk";
|
||||
import React from "react";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
export interface LoginConfig {
|
||||
/**
|
||||
* The URL to redirect to on login.
|
||||
*/
|
||||
redirectTo?: string;
|
||||
/**
|
||||
* Function to run on error.
|
||||
*/
|
||||
onError?: (error: string) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook to securely login to a backend with the connected wallet. The backend
|
||||
* authentication URL must be configured on the ThirdwebProvider.
|
||||
*
|
||||
* @param config - Configuration for the login.
|
||||
* @returns - A function to invoke to login with the connected wallet.
|
||||
*
|
||||
* @beta
|
||||
*/
|
||||
export function useLogin(config?: LoginConfig) {
|
||||
const sdk = useSDK();
|
||||
const queryClient = useQueryClient();
|
||||
const authConfig = useThirdwebAuthConfig();
|
||||
|
||||
React.useEffect(() => {
|
||||
const queryParams = new URLSearchParams(window.location.search);
|
||||
const error = queryParams.get("error");
|
||||
|
||||
if (error && config?.onError) {
|
||||
// If there is an error, parse it and trigger the onError callback
|
||||
config.onError(decodeURI(error));
|
||||
}
|
||||
}, [config]);
|
||||
|
||||
async function login(cfg?: LoginOptions) {
|
||||
invariant(
|
||||
authConfig,
|
||||
"Please specify an authConfig in the ThirdwebProvider",
|
||||
);
|
||||
const payload = await sdk?.auth.login(authConfig.domain, cfg);
|
||||
|
||||
const encodedPayload = encodeURIComponent(btoa(JSON.stringify(payload)));
|
||||
const encodedRedirectTo = encodeURIComponent(
|
||||
config?.redirectTo ||
|
||||
authConfig.loginRedirect ||
|
||||
window.location.toString(),
|
||||
);
|
||||
|
||||
queryClient.invalidateQueries(ensureTWPrefix(["user"]));
|
||||
|
||||
// Redirect to the login URL with the encoded payload
|
||||
window.location.href = `${authConfig.authUrl}/login?payload=${encodedPayload}&redirect=${encodedRedirectTo}`;
|
||||
}
|
||||
|
||||
return login;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import { ensureTWPrefix } from "../../../core/query-utils/query-key";
|
||||
import { useThirdwebAuthConfig } from "../../contexts/thirdweb-auth";
|
||||
import { useQueryClient } from "@tanstack/react-query";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
/**
|
||||
* Hook to logout the connected wallet from the backend.
|
||||
* The backend logout URL must be configured on the ThirdwebProvider.
|
||||
*
|
||||
* @returns - A function to invoke to logout.
|
||||
*
|
||||
* @beta
|
||||
*/
|
||||
export function useLogout() {
|
||||
const queryClient = useQueryClient();
|
||||
const authConfig = useThirdwebAuthConfig();
|
||||
|
||||
function logout() {
|
||||
invariant(
|
||||
authConfig,
|
||||
"Please specify an authConfig in the ThirdwebProvider",
|
||||
);
|
||||
queryClient.invalidateQueries(ensureTWPrefix(["user"]));
|
||||
window.location.href = `${authConfig.authUrl}/logout`;
|
||||
}
|
||||
|
||||
return logout;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import { ensureTWPrefix } from "../../../core/query-utils/query-key";
|
||||
import { useThirdwebAuthConfig } from "../../contexts/thirdweb-auth";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
export interface ThirdwebAuthUser {
|
||||
address: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook to get the currently logged in user.
|
||||
*
|
||||
* @returns - The currently logged in user or null if not logged in, as well as a loading state.
|
||||
*
|
||||
* @beta
|
||||
*/
|
||||
export function useUser() {
|
||||
const authConfig = useThirdwebAuthConfig();
|
||||
|
||||
const { data: user, isLoading } = useQuery(
|
||||
ensureTWPrefix(["user"]),
|
||||
async () => {
|
||||
invariant(
|
||||
authConfig,
|
||||
"Please specify an authConfig in the ThirdwebProvider",
|
||||
);
|
||||
const res = await fetch(`${authConfig.authUrl}/user`);
|
||||
return (await res.json()) as ThirdwebAuthUser;
|
||||
},
|
||||
{
|
||||
enabled: !!authConfig,
|
||||
},
|
||||
);
|
||||
|
||||
return { user, isLoading };
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import { createSOLProgramQueryKey } from "../../../../core/query-utils/query-key";
|
||||
import { RequiredParam } from "../../../../core/types/shared";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import type { NFTDrop } from "@thirdweb-dev/sdk/solana";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
export function claimConditionsQuery(program: RequiredParam<NFTDrop>) {
|
||||
return {
|
||||
queryKey: createSOLProgramQueryKey(program, ["claimConditions"] as const),
|
||||
|
||||
queryFn: async () => {
|
||||
invariant(program, "program is required");
|
||||
|
||||
return await program.claimConditions.get();
|
||||
},
|
||||
enabled: !!program,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current claim conditions on an NFT Drop
|
||||
* @param program - The NFT Drop program to get the claim conditions for
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* import { useProgram, useClaimConditions } from "@thirdweb-dev/react/solana";
|
||||
*
|
||||
* export default function Component() {
|
||||
* const { program } = useProgram("{{program_address}}");
|
||||
* const { data: claimConditions, isLoading } = useClaimConditions(program);
|
||||
*
|
||||
* return (
|
||||
* <p>{claimConditions?.price.displayValue}</p>
|
||||
* )
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function useClaimConditions(program: RequiredParam<NFTDrop>) {
|
||||
return useQuery(claimConditionsQuery(program));
|
||||
}
|
||||
@@ -1,15 +1,41 @@
|
||||
import { createSOLProgramQueryKey } from "../../../../core/query-utils/query-key";
|
||||
import { RequiredParam } from "../../../../core/types/shared";
|
||||
import { ClaimNFTParams } from "../../../types";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import type { NFTDrop } from "@thirdweb-dev/sdk/solana";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
/**
|
||||
* Claim NFTs from an NFT Drop program
|
||||
* @param program - The NFT Drop program instance to claim from
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* import { useProgram, useClaimNFT } from "@thirdweb-dev/react/solana";
|
||||
*
|
||||
* export default function Component() {
|
||||
* const { program } = useProgram("{{program_address}}");
|
||||
* const { mutateAsync: claim, isLoading, error } = useClaimNFT(program);
|
||||
*
|
||||
* return (
|
||||
* <button onClick={() => claim({amount: 1})}>
|
||||
* Claim
|
||||
* </button>
|
||||
* )
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function useClaimNFT(program: RequiredParam<NFTDrop>) {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation(
|
||||
async (quantity: number) => {
|
||||
async (data: ClaimNFTParams) => {
|
||||
invariant(program, "program is required");
|
||||
return await program.claim(quantity);
|
||||
if (!data.to) {
|
||||
return await program.claim(data.amount);
|
||||
}
|
||||
return await program.claimTo(data.to, data.amount);
|
||||
},
|
||||
{
|
||||
onSettled: () =>
|
||||
|
||||
@@ -19,6 +19,26 @@ export function dropTotalClaimedSupplyQuery(program: RequiredParam<NFTDrop>) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the total claimed supply of NFTs on an NFT Drop
|
||||
* @param program - The NFT Drop program to get the claimed supply on
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* import { useProgram, useDropTotalClaimedSupply } from "@thirdweb-dev/react/solana";
|
||||
*
|
||||
* export default function Component() {
|
||||
* const { program } = useProgram("{{program_address}}");
|
||||
* const { data: claimedSupply, isLoading } = useDropTotalClaimedSupply(program);
|
||||
*
|
||||
* return (
|
||||
* <p>{claimedSupply}</p>
|
||||
* )
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function useDropTotalClaimedSupply(program: RequiredParam<NFTDrop>) {
|
||||
return useQuery(dropTotalClaimedSupplyQuery(program));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
import { createSOLProgramQueryKey } from "../../../../core/query-utils/query-key";
|
||||
import { RequiredParam } from "../../../../core/types/shared";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import { NFTMetadataInput, UploadProgressEvent } from "@thirdweb-dev/sdk";
|
||||
import type { NFTDrop } from "@thirdweb-dev/sdk/solana";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
/**
|
||||
* Lazy mint NFTs on an NFT Drop program
|
||||
* @param program - The NFT Drop program instance to lazy mint on
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* import { useProgram, useLazyMintNFT } from "@thirdweb-dev/react/solana";
|
||||
*
|
||||
* export default function Component() {
|
||||
* const { program } = useProgram("{{program_address}}");
|
||||
* const { mutateAsync: lazyMint, isLoading, error } = useLazyMintNFT(program);
|
||||
*
|
||||
* return (
|
||||
* <button onClick={() => lazyMint({ name: "My NFT", description: "..." })}>
|
||||
* Claim
|
||||
* </button>
|
||||
* )
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function useLazyMint(
|
||||
program: RequiredParam<NFTDrop>,
|
||||
onProgress?: (progress: UploadProgressEvent) => void,
|
||||
) {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation(
|
||||
async (data: { metadatas: NFTMetadataInput[] }) => {
|
||||
invariant(program, "program is required");
|
||||
let options;
|
||||
if (onProgress) {
|
||||
options = {
|
||||
onProgress,
|
||||
};
|
||||
}
|
||||
return await program.lazyMint(data.metadatas, options);
|
||||
},
|
||||
{
|
||||
onSettled: () =>
|
||||
queryClient.invalidateQueries(createSOLProgramQueryKey(program)),
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
import { createSOLProgramQueryKey } from "../../../../core/query-utils/query-key";
|
||||
import { RequiredParam } from "../../../../core/types/shared";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import type { NFTDrop, NFTMetadataInput } from "@thirdweb-dev/sdk/solana";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
export function useLazyMintNFT(program: RequiredParam<NFTDrop>) {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation(
|
||||
async (metadata: NFTMetadataInput[]) => {
|
||||
invariant(program, "program is required");
|
||||
return await program.lazyMint(metadata);
|
||||
},
|
||||
{
|
||||
onSettled: () =>
|
||||
queryClient.invalidateQueries(createSOLProgramQueryKey(program)),
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { createSOLProgramQueryKey } from "../../../../core/query-utils/query-key";
|
||||
import { RequiredParam } from "../../../../core/types/shared";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import type { NFTDrop, NFTDropConditionsInput } from "@thirdweb-dev/sdk/solana";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
/**
|
||||
* Set Claim Conditions to an NFT Drop program
|
||||
* @param program - The NFT Drop program to set claim conditions for
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* import { useProgram, useSetClaimConditions } from "@thirdweb-dev/react/solana";
|
||||
*
|
||||
* export default function Component() {
|
||||
* const { program } = useProgram("{{program_address}}");
|
||||
* const { mutateAsync: setClaimConditions, isLoading, error } = useSetClaimConditions(program);
|
||||
*
|
||||
* return (
|
||||
* <button onClick={() => setClaimConditions(metadata)}>
|
||||
* Set Claim Conditions
|
||||
* </button>
|
||||
* )
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function useSetClaimConditions(program: RequiredParam<NFTDrop>) {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation(
|
||||
async (metadata: NFTDropConditionsInput) => {
|
||||
invariant(program, "program is required");
|
||||
return await program.claimConditions.set(metadata);
|
||||
},
|
||||
{
|
||||
onSettled: () =>
|
||||
queryClient.invalidateQueries(createSOLProgramQueryKey(program)),
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -19,6 +19,26 @@ export function dropUnclaimedSupplyQuery(program: RequiredParam<NFTDrop>) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the total unclaimed supply of NFTs on an NFT Drop
|
||||
* @param program - The NFT Drop program to get the unclaimed supply on
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* import { useProgram, useDropTotalUnclaimedSupply } from "@thirdweb-dev/react/solana";
|
||||
*
|
||||
* export default function Component() {
|
||||
* const { program } = useProgram("{{program_address}}");
|
||||
* const { data: unclaimedSupply, isLoading } = useDropTotalUnclaimedSupply(program);
|
||||
*
|
||||
* return (
|
||||
* <p>{unclaimedSupply}</p>
|
||||
* )
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function useDropUnclaimedSupply(program: RequiredParam<NFTDrop>) {
|
||||
return useQuery(dropUnclaimedSupplyQuery(program));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import { createSOLProgramQueryKey } from "../../../core/query-utils/query-key";
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import type { NFTCollection, NFTDrop } from "@thirdweb-dev/sdk/solana";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
/**
|
||||
* Burn an NFT owned by the connected wallet
|
||||
* @param program - The NFT program instance to burn NFTs on
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* import { useProgram, useBurnNFT } from "@thirdweb-dev/react/solana";
|
||||
*
|
||||
* export default function Component() {
|
||||
* const { program } = useProgram("{{program_address}}");
|
||||
* const { mutateAsync: burn, isLoading, error } = useBurnNFT(program);
|
||||
*
|
||||
* return (
|
||||
* <button
|
||||
* onClick={() => burn("...")}
|
||||
* >
|
||||
* Burn
|
||||
* </button>
|
||||
* )
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function useBurnNFT(program: RequiredParam<NFTCollection | NFTDrop>) {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation(
|
||||
async (nftAddress: string) => {
|
||||
invariant(program, "program is required");
|
||||
return await program.burn(nftAddress);
|
||||
},
|
||||
{
|
||||
onSettled: () =>
|
||||
queryClient.invalidateQueries(createSOLProgramQueryKey(program)),
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -2,16 +2,42 @@ import { createSOLProgramQueryKey } from "../../../core/query-utils/query-key";
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import { MintNFTParams } from "../../../evm/types";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import type { NFTCollection, NFTMetadataInput } from "@thirdweb-dev/sdk/solana";
|
||||
import type { NFTCollection } from "@thirdweb-dev/sdk/solana";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
/**
|
||||
* Mint NFTs on your NFT program
|
||||
* @param program - The NFT program to mint NFTs to
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* import { useProgram, useMintNFT } from "@thirdweb-dev/react/solana";
|
||||
*
|
||||
* export default function Component() {
|
||||
* const { program } = useProgram("{{program_address}}");
|
||||
* const { mutateAsync: mint, isLoading, error } = useMintNFT(program);
|
||||
*
|
||||
* function mintNFT() {
|
||||
* const metadata = { name: "First NFT", description: "This is a cool NFT!" };
|
||||
* mint({ to: "{{wallet_address}}", metadata });
|
||||
* }
|
||||
*
|
||||
* return (
|
||||
* <button onClick={() => mintNFT()}>
|
||||
* Mint
|
||||
* </button>
|
||||
* )
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function useMintNFT(program: RequiredParam<NFTCollection>) {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation(
|
||||
async (data: MintNFTParams) => {
|
||||
invariant(program, "program is required");
|
||||
// TODO fix this once consolidated
|
||||
return await program.mintTo(data.to, data.metadata as NFTMetadataInput);
|
||||
return await program.mintTo(data.to, data.metadata);
|
||||
},
|
||||
{
|
||||
onSettled: () =>
|
||||
|
||||
@@ -23,6 +23,27 @@ export function nftGetOneQuery(
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the metadata for a minted NFT
|
||||
* @param program - The NFT program to get NFT metadata from
|
||||
* @param - tokenAdress - The mint address of the NFT to get the metadata of
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* import { useProgram, useNFT } from "@thirdweb-dev/react/solana";
|
||||
*
|
||||
* export default function Component() {
|
||||
* const { program } = useProgram("{{program_address}}");
|
||||
* const { data: metadata, isLoading } = useNFT(program, mintAddress);
|
||||
*
|
||||
* return (
|
||||
* <pre>{JSON.stringify(metadata)}</pre>
|
||||
* )
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function useNFT(
|
||||
program: RequiredParam<NFTCollection | NFTDrop>,
|
||||
tokenAddress: RequiredParam<string>,
|
||||
|
||||
@@ -18,6 +18,26 @@ export function nftGetAllQuery(
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the metadata for every NFT on an NFT program
|
||||
* @param program - The NFT program to get NFTs metadata from
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* import { useProgram, useNFTs } from "@thirdweb-dev/react/solana";
|
||||
*
|
||||
* export default function Component() {
|
||||
* const { program } = useProgram("{{program_address}}");
|
||||
* const { data: metadata, isLoading } = useNFTs(program);
|
||||
*
|
||||
* return (
|
||||
* <pre>{JSON.stringify(metadata)}</pre>
|
||||
* )
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function useNFTs(program: RequiredParam<NFTCollection | NFTDrop>) {
|
||||
return useQuery(nftGetAllQuery(program));
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { createSOLProgramQueryKey } from "../../../core/query-utils/query-key";
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import type { NFTCollection } from "@thirdweb-dev/sdk/solana";
|
||||
import type { NFTCollection, NFTDrop } from "@thirdweb-dev/sdk/solana";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
export type TransferNFTMutationParams = {
|
||||
@@ -9,7 +9,36 @@ export type TransferNFTMutationParams = {
|
||||
tokenAddress: string;
|
||||
};
|
||||
|
||||
export function useTransferNFT(program: RequiredParam<NFTCollection>) {
|
||||
/**
|
||||
* Transfer NFTs from the connected wallet to another wallet
|
||||
* @param program - The NFT program instance to transfer NFTs on
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* import { useProgram, useTransferNFT } from "@thirdweb-dev/react/solana";
|
||||
*
|
||||
* export default function Component() {
|
||||
* const { program } = useProgram("{{program_address}}");
|
||||
* const { mutateAsync: transfer, isLoading, error } = useTransferNFT(program);
|
||||
*
|
||||
* return (
|
||||
* <button
|
||||
* onClick={() => transfer({
|
||||
* receiverAddress: "{{wallet_address}}",
|
||||
* tokenAddress: "..."
|
||||
* })}
|
||||
* >
|
||||
* Transfer
|
||||
* </button>
|
||||
* )
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function useTransferNFT(
|
||||
program: RequiredParam<NFTCollection | NFTDrop>,
|
||||
) {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation(
|
||||
async ({ tokenAddress, receiverAddress }: TransferNFTMutationParams) => {
|
||||
|
||||
@@ -5,7 +5,12 @@ import {
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import { useSDK } from "../../providers/base";
|
||||
import { programAccountTypeQuery } from "./useProgramAccountType";
|
||||
import { QueryClient, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import {
|
||||
QueryClient,
|
||||
useQuery,
|
||||
useQueryClient,
|
||||
UseQueryResult,
|
||||
} from "@tanstack/react-query";
|
||||
import type {
|
||||
NFTCollection,
|
||||
NFTDrop,
|
||||
@@ -67,13 +72,53 @@ export function programQuery<TProgramType extends ProgramType>(
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an SDK instance to interact with any program
|
||||
* @param address - the address of the program to get an interface for
|
||||
* @param type - optionally, pass in the program type to get static typing
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* import { useProgram } from "@thirdweb-dev/react/solana";
|
||||
*
|
||||
* export default function Component() {
|
||||
* const { program } = useProgram("{{program_address}}").program;
|
||||
*
|
||||
* // Now you can use the program in the rest of the component
|
||||
*
|
||||
* // For example, we can make a transaction
|
||||
* async function functionCall() {
|
||||
* await program.call("mint", ...);
|
||||
* }
|
||||
*
|
||||
* ...
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function useProgram<TProgramType extends ProgramType>(
|
||||
address: RequiredParam<string>,
|
||||
type?: TProgramType,
|
||||
) {
|
||||
const queryClient = useQueryClient();
|
||||
const sdk = useSDK();
|
||||
return useQuery(programQuery(queryClient, sdk, address, type));
|
||||
const queryResult = useQuery(programQuery(queryClient, sdk, address, type));
|
||||
|
||||
return { ...queryResult, program: queryResult.data } as UseQueryResult<
|
||||
Readonly<{
|
||||
"nft-collection": NFTCollection;
|
||||
"nft-drop": NFTDrop;
|
||||
token: Token;
|
||||
}>[TProgramType],
|
||||
unknown
|
||||
> & {
|
||||
program: Readonly<{
|
||||
"nft-collection": NFTCollection;
|
||||
"nft-drop": NFTDrop;
|
||||
token: Token;
|
||||
}>[TProgramType];
|
||||
};
|
||||
}
|
||||
|
||||
export type UseProgramResult = ReturnType<typeof useProgram>;
|
||||
|
||||
@@ -19,7 +19,7 @@ export function programAccountTypeQuery(
|
||||
invariant(sdk, "sdk is required");
|
||||
invariant(address, "Address is required");
|
||||
|
||||
return await sdk.registry.getAccountType(address);
|
||||
return await sdk.registry.getProgramType(address);
|
||||
},
|
||||
enabled: !!sdk && !!network && !!address,
|
||||
// this cannot change as it is unique by address & network
|
||||
@@ -28,6 +28,9 @@ export function programAccountTypeQuery(
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export function useProgramAccountType(address: RequiredParam<string>) {
|
||||
const sdk = useSDK();
|
||||
return useQuery(programAccountTypeQuery(sdk, address));
|
||||
|
||||
@@ -18,6 +18,9 @@ export function programMetadataQuery(
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export function useProgramMetadata(
|
||||
program: RequiredParam<UseProgramResult["data"]>,
|
||||
) {
|
||||
|
||||
@@ -5,6 +5,28 @@ import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import type { Token } from "@thirdweb-dev/sdk/solana";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
/**
|
||||
* Mint tokens on your token program
|
||||
* @param program - The program instance of the program to mint on
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* import { useProgram, useMintToken } from "@thirdweb-dev/react/solana";
|
||||
*
|
||||
* export default function Component() {
|
||||
* const { program } = useProgram("{{program_address}}");
|
||||
* const { mutateAsync: mint, isLoading, error } = useMintToken(program);
|
||||
*
|
||||
* return (
|
||||
* <button onClick={() => mint({ to: "{{wallet_address}}", amount: 1 })}>
|
||||
* Mint
|
||||
* </button>
|
||||
* )
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function useMintToken(program: RequiredParam<Token>) {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation(
|
||||
|
||||
@@ -23,6 +23,27 @@ export function tokenBalanceQuery(
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the token balance of a specified wallet
|
||||
* @param program - The token program to get the balance on
|
||||
* @param walletAddress - The address of the wallet to get the balance of
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* import { useProgram, useTokenBalance } from "@thirdweb-dev/react/solana";
|
||||
*
|
||||
* export default function Component() {
|
||||
* const { program } = useProgram("{{program_address}}");
|
||||
* const { data: balance, isLoading } = useTokenBalance(program, "{{wallet_address}}");
|
||||
*
|
||||
* return (
|
||||
* <p>{balance}</p>
|
||||
* )
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function useTokenBalance(
|
||||
program: RequiredParam<Token>,
|
||||
walletAddress: RequiredParam<string>,
|
||||
|
||||
@@ -16,6 +16,26 @@ export function tokenSupplyQuery(program: RequiredParam<Token>) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the total circulating supply of a token
|
||||
* @param program - The token program to get the supply of
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* import { useProgram, useMintToken } from "@thirdweb-dev/react/solana";
|
||||
*
|
||||
* export default function Component() {
|
||||
* const { program } = useProgram("{{program_address}}");
|
||||
* const { data: totalSupply, isLoading } = useTokenSupply(program);
|
||||
*
|
||||
* return (
|
||||
* <p>{totalSupply}</p>
|
||||
* )
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function useTokenSupply(program: RequiredParam<Token>) {
|
||||
return useQuery(tokenSupplyQuery(program));
|
||||
}
|
||||
|
||||
@@ -9,6 +9,28 @@ export type TransferTokenMutationParams = {
|
||||
receiverAddress: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Transfer tokens from the connected wallet to another wallet
|
||||
* @param program - The program instance of the program to mint on
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* import { useProgram, useTransferToken } from "@thirdweb-dev/react/solana";
|
||||
*
|
||||
* export default function Component() {
|
||||
* const { program } = useProgram("{{program_address}}");
|
||||
* const { mutateAsync: transfer, isLoading, error } = useTransferToken(program);
|
||||
*
|
||||
* return (
|
||||
* <button onClick={() => transfer({ to: "{{wallet_address}}", amount: 1 })}>
|
||||
* Transfer
|
||||
* </button>
|
||||
* )
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function useTransferToken(program: RequiredParam<Token>) {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation(
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
import { createSOLQueryKeyWithNetwork } from "../../../core/query-utils/query-key";
|
||||
import { RequiredParam } from "../../../core/types/shared";
|
||||
import { useSDK } from "../../providers/base";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { ThirdwebSDK } from "@thirdweb-dev/sdk/solana";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
export function balanceQuery(sdk: RequiredParam<ThirdwebSDK>) {
|
||||
const address = sdk?.wallet?.getAddress();
|
||||
const network = sdk?.network;
|
||||
|
||||
return {
|
||||
queryKey: createSOLQueryKeyWithNetwork(
|
||||
["wallet-balance", { address }] as const,
|
||||
network,
|
||||
),
|
||||
|
||||
queryFn: () => {
|
||||
invariant(sdk, "sdk is required");
|
||||
|
||||
return sdk.wallet.getBalance();
|
||||
},
|
||||
enabled: !!sdk && !!address && !!network,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the currently connected wallet balance
|
||||
*
|
||||
* @returns the balace of the connected wallet
|
||||
*/
|
||||
export function useBalance() {
|
||||
const sdk = useSDK();
|
||||
return useQuery(balanceQuery(sdk));
|
||||
}
|
||||
@@ -15,15 +15,24 @@ export * from "./hooks/nft/useNFTs";
|
||||
export * from "./hooks/nft/useMintNFT";
|
||||
export * from "./hooks/nft/useNFT";
|
||||
export * from "./hooks/nft/useTransferNFT";
|
||||
export * from "./hooks/nft/useBurnNFT";
|
||||
|
||||
// NFT Drop
|
||||
export * from "./hooks/nft/drop/useLazyMintNFT";
|
||||
export * from "./hooks/nft/drop/useLazyMint";
|
||||
export * from "./hooks/nft/drop/useClaimedSupply";
|
||||
export * from "./hooks/nft/drop/useUnclaimedSupply";
|
||||
export * from "./hooks/nft/drop/useClaimNFT";
|
||||
export * from "./hooks/nft/drop/useClaimConditions";
|
||||
export * from "./hooks/nft/drop/useSetClaimConditions";
|
||||
|
||||
// Token
|
||||
export * from "./hooks/token/useTokenSupply";
|
||||
export * from "./hooks/token/useTokenBalance";
|
||||
export * from "./hooks/token/useMintToken";
|
||||
export * from "./hooks/token/useTransferToken";
|
||||
|
||||
// Auth
|
||||
export * from "./hooks/auth";
|
||||
|
||||
//Wallet
|
||||
export * from "./hooks/wallet/useBalance";
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user