Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
068db44603 | ||
|
|
dd7d0fca2d | ||
|
|
526176c471 | ||
|
|
09120c923c | ||
|
|
d1f8e95162 | ||
|
|
6573556d0e | ||
|
|
fc62b91ee5 | ||
|
|
08e9cd206b | ||
|
|
fb0f12ae28 | ||
|
|
c710fc1c62 | ||
|
|
f41ee6fb1c | ||
|
|
513c332ed0 | ||
|
|
693f349db2 | ||
|
|
63ad0050f0 | ||
|
|
dcdb0dcb83 | ||
|
|
b3b9edca29 | ||
|
|
1fbbc2d27d | ||
|
|
4b98e487d4 | ||
|
|
95380eaed4 | ||
|
|
1f3c64d361 | ||
|
|
bb1666b92b | ||
|
|
0f12d1f903 | ||
|
|
74941603a9 | ||
|
|
4fda12aa2d | ||
|
|
e684d05e22 | ||
|
|
335744ff6d | ||
|
|
7bc40f6223 | ||
|
|
8291742ad9 | ||
|
|
fb964ecb85 | ||
|
|
7dba9f782e | ||
|
|
79f91ee2d9 | ||
|
|
2df8de0e2a | ||
|
|
ce4608bff4 | ||
|
|
125c836d88 | ||
|
|
ec36b13a30 | ||
|
|
52b1a0fcac | ||
|
|
a6c36724eb | ||
|
|
6abb845971 | ||
|
|
dc38a243c2 | ||
|
|
03a03a196d | ||
|
|
931270479e | ||
|
|
6f4c5cd746 | ||
|
|
d3c8626a5a | ||
|
|
ffb1bb0a60 | ||
|
|
9bd01de5f9 | ||
|
|
f5caf6a350 | ||
|
|
46672a490a | ||
|
|
f35fbec1be | ||
|
|
824051eb28 | ||
|
|
fde77a7e19 | ||
|
|
2ec4811f15 | ||
|
|
15fe4779f4 | ||
|
|
6d3d76cff8 | ||
|
|
04f2f7b8ff |
@@ -10,7 +10,7 @@ runs:
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 20
|
||||
registry-url: "https://registry.npmjs.org"
|
||||
cache: "pnpm"
|
||||
|
||||
|
||||
@@ -29,7 +29,6 @@ You can see a quick outline of each of the projects within this repo below, each
|
||||
| [/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> |
|
||||
|
||||
## How to contribute
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ jobs:
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 20
|
||||
check-latest: true
|
||||
|
||||
- uses: pnpm/action-setup@v2
|
||||
@@ -81,7 +81,7 @@ jobs:
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 20
|
||||
check-latest: true
|
||||
|
||||
- uses: pnpm/action-setup@v2
|
||||
@@ -100,7 +100,7 @@ jobs:
|
||||
- name: Upload coverage reports to Codecov
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
files: ./packages/sdk/coverage/evm/lcov.info,./packages/sdk/coverage/solana/lcov.info,
|
||||
files: ./packages/sdk/coverage/evm/lcov.info
|
||||
|
||||
e2e:
|
||||
timeout-minutes: 15
|
||||
@@ -111,7 +111,7 @@ jobs:
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 20
|
||||
check-latest: true
|
||||
|
||||
- uses: pnpm/action-setup@v2
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
name: Release Next
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- ".changeset/**"
|
||||
- "packages/**"
|
||||
branches:
|
||||
- next
|
||||
|
||||
env:
|
||||
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
||||
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
||||
jobs:
|
||||
release:
|
||||
name: Release
|
||||
timeout-minutes: 30
|
||||
runs-on: ubuntu-latest-16
|
||||
steps:
|
||||
- name: Checkout branch
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install
|
||||
uses: ./.github/composite-actions/install
|
||||
|
||||
- name: Build
|
||||
run: pnpm build
|
||||
|
||||
- name: Create @next release
|
||||
run: |
|
||||
git checkout next
|
||||
pnpm version-packages:next
|
||||
pnpm release:next
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
+5
-5
@@ -7,11 +7,11 @@
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
"engines": {
|
||||
"node": ">=16.7.0"
|
||||
"node": ">=18.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"preinstall": "npx only-allow pnpm",
|
||||
"test": "turbo run test test:evm test:solana --filter=./packages/*",
|
||||
"test": "turbo run test --filter=./packages/*",
|
||||
"e2e": "turbo run e2e",
|
||||
"build": "turbo run build --filter=./packages/*",
|
||||
"build:release": "turbo run build --force --filter=./packages/*",
|
||||
@@ -26,12 +26,14 @@
|
||||
"release": "node ./scripts/pre-release.mjs && changeset publish",
|
||||
"version-packages:nightly": "node scripts/pre-nightly.mjs && changeset version --snapshot nightly",
|
||||
"release:nightly": "node ./scripts/pre-release.mjs && changeset publish --tag nightly",
|
||||
"version-packages:next": "node scripts/pre-nightly.mjs && changeset version --snapshot next",
|
||||
"release:next": "node ./scripts/pre-release.mjs && changeset publish --tag next",
|
||||
"push": "turbo run push --filter=./packages/*",
|
||||
"hotlink-init": "node ./scripts/hotlink/hotlink-init.mjs",
|
||||
"hotlink-revert": "node ./scripts/hotlink/hotlink-revert.mjs",
|
||||
"explain:major": "node ./scripts/changeset-explain-major.mjs"
|
||||
},
|
||||
"packageManager": "pnpm@8.6.12",
|
||||
"packageManager": "pnpm@8.9.0",
|
||||
"dependencies": {
|
||||
"@changesets/changelog-github": "^0.4.8",
|
||||
"@changesets/cli": "^2.26.2",
|
||||
@@ -54,10 +56,8 @@
|
||||
},
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
"cross-fetch@>=3.0.0 <3.1.5": ">=3.1.5",
|
||||
"got@<11.8.5": ">=11.8.5",
|
||||
"glob-parent@<5.1.2": ">=5.1.2",
|
||||
"node-fetch@<2.6.7": ">=2.6.7",
|
||||
"nth-check@<2.0.1": ">=2.0.1",
|
||||
"socket.io-parser@>=4.0.4 <4.2.3": ">=4.2.3",
|
||||
"fast-xml-parser@<4.2.4": ">=4.2.4",
|
||||
|
||||
@@ -1,5 +1,63 @@
|
||||
# @thirdweb-dev/auth
|
||||
|
||||
## 4.0.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @thirdweb-dev/wallets@2.0.3
|
||||
|
||||
## 4.0.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`74941603`](https://github.com/thirdweb-dev/js/commit/74941603a96456da46a47147f67c98235ac55022), [`4b98e487`](https://github.com/thirdweb-dev/js/commit/4b98e487d4b47225d7095e5444dc5e7608db48a3), [`dcdb0dcb`](https://github.com/thirdweb-dev/js/commit/dcdb0dcb838168a22c8335738852316dfb6e6fc9), [`b3b9edca`](https://github.com/thirdweb-dev/js/commit/b3b9edca29e7d4053b14270a61caa89c34fecf9e)]:
|
||||
- @thirdweb-dev/wallets@2.0.2
|
||||
|
||||
## 4.0.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`e684d05e`](https://github.com/thirdweb-dev/js/commit/e684d05e222458f02c8158eb9385d68c879dd946)]:
|
||||
- @thirdweb-dev/wallets@2.0.1
|
||||
|
||||
## 4.0.0
|
||||
|
||||
### Major Changes
|
||||
|
||||
- [#1630](https://github.com/thirdweb-dev/js/pull/1630) [`ce4608bf`](https://github.com/thirdweb-dev/js/commit/ce4608bff4783caf164ad6e21b42a827b89badf8) Thanks [@jnsdls](https://github.com/jnsdls)! - **Dropped Support for Solana**:
|
||||
|
||||
- We've decided to drop support for Solana across our SDKs.
|
||||
- Starting with this version of our SDKs all previous solana related functionality will be removed.
|
||||
- Previous versions of our SDKs will continue to work with Solana. However, we will not be providing any further updates or bug fixes for Solana.
|
||||
- You can read a detailed explanation of our decision [on our blog](https://blog.thirdweb.com/discontinuing-solana-support/).
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`ce4608bf`](https://github.com/thirdweb-dev/js/commit/ce4608bff4783caf164ad6e21b42a827b89badf8), [`ce4608bf`](https://github.com/thirdweb-dev/js/commit/ce4608bff4783caf164ad6e21b42a827b89badf8)]:
|
||||
- @thirdweb-dev/wallets@2.0.0
|
||||
|
||||
## 3.2.48
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @thirdweb-dev/wallets@1.3.5
|
||||
|
||||
## 3.2.47
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`9bd01de5`](https://github.com/thirdweb-dev/js/commit/9bd01de5f9c388e758fba9af7899dc4a9c5a0101)]:
|
||||
- @thirdweb-dev/wallets@1.3.4
|
||||
|
||||
## 3.2.46
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`6d3d76cf`](https://github.com/thirdweb-dev/js/commit/6d3d76cff8018015faa191a1f8bd4f34506a6650), [`04f2f7b8`](https://github.com/thirdweb-dev/js/commit/04f2f7b8ff5f19345d868fc515a24ccd6ffd0ab9)]:
|
||||
- @thirdweb-dev/wallets@1.3.3
|
||||
|
||||
## 3.2.45
|
||||
|
||||
### Patch Changes
|
||||
@@ -582,7 +640,7 @@
|
||||
|
||||
## How to upgrade
|
||||
|
||||
The `ThirdwebAuth` constructor now takes the `domain` in the constructor, and takes a more generic `wallet` interface as input. The `wallet` can be imported from the `@thirdweb-dev/wallets` package, or for more simpler use cases, from the `@thirdweb-dev/auth/evm` and `@thirdweb-dev/auth/solana` entrypoints.
|
||||
The `ThirdwebAuth` constructor now takes the `domain` in the constructor, and takes a more generic `wallet` interface as input. The `wallet` can be imported from the `@thirdweb-dev/wallets` package, or for more simpler use cases, from the `@thirdweb-dev/auth/evm` entrypoint.
|
||||
|
||||
```js
|
||||
import { PrivateKeyWallet } from "@thirdweb-dev/auth/evm";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/auth",
|
||||
"version": "3.2.45",
|
||||
"version": "4.0.3",
|
||||
"main": "dist/thirdweb-dev-auth.cjs.js",
|
||||
"module": "dist/thirdweb-dev-auth.esm.js",
|
||||
"browser": {
|
||||
@@ -28,13 +28,6 @@
|
||||
},
|
||||
"default": "./next/dist/thirdweb-dev-auth-next.cjs.js"
|
||||
},
|
||||
"./solana": {
|
||||
"module": {
|
||||
"browser": "./solana/dist/thirdweb-dev-auth-solana.browser.esm.js",
|
||||
"default": "./solana/dist/thirdweb-dev-auth-solana.esm.js"
|
||||
},
|
||||
"default": "./solana/dist/thirdweb-dev-auth-solana.cjs.js"
|
||||
},
|
||||
"./express": {
|
||||
"module": {
|
||||
"browser": "./express/dist/thirdweb-dev-auth-express.browser.esm.js",
|
||||
@@ -70,8 +63,7 @@
|
||||
"express/index.ts",
|
||||
"next/index.ts",
|
||||
"next-auth/index.ts",
|
||||
"evm/index.ts",
|
||||
"solana/index.ts"
|
||||
"evm/index.ts"
|
||||
],
|
||||
"exports": {
|
||||
"envConditions": [
|
||||
@@ -87,7 +79,6 @@
|
||||
"@microsoft/api-extractor": "^7.36.3",
|
||||
"@microsoft/tsdoc": "^0.14.1",
|
||||
"@preconstruct/cli": "2.7.0",
|
||||
"@solana/web3.js": "^1.62.0",
|
||||
"@swc-node/register": "^1.6.6",
|
||||
"@swc/core": "^1.3.71",
|
||||
"@thirdweb-dev/tsconfig": "workspace:*",
|
||||
@@ -96,7 +87,7 @@
|
||||
"@types/cookie-parser": "^1.4.3",
|
||||
"@types/express": "^4.17.13",
|
||||
"@types/mocha": "^10.0.0",
|
||||
"@types/uuid": "^9.0.2",
|
||||
"@types/uuid": "^9.0.5",
|
||||
"@typescript-eslint/eslint-plugin": "^6.2.0",
|
||||
"@typescript-eslint/parser": "^6.2.0",
|
||||
"chai": "^4.3.6",
|
||||
@@ -117,7 +108,6 @@
|
||||
"typescript": "^5.1.6"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@solana/web3.js": "^1.73.0",
|
||||
"cookie-parser": "^1.4.6",
|
||||
"ethers": "^5",
|
||||
"express": "^4",
|
||||
@@ -125,9 +115,6 @@
|
||||
"next-auth": "^4"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@solana/web3.js": {
|
||||
"optional": true
|
||||
},
|
||||
"cookie-parser": {
|
||||
"optional": true
|
||||
},
|
||||
@@ -147,7 +134,7 @@
|
||||
"dependencies": {
|
||||
"@thirdweb-dev/wallets": "workspace:*",
|
||||
"cookie": "^0.5.0",
|
||||
"uuid": "^9.0.0",
|
||||
"zod": "^3.20.2"
|
||||
"uuid": "^9.0.1",
|
||||
"zod": "^3.22.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"main": "dist/thirdweb-dev-auth-solana.cjs.js",
|
||||
"module": "dist/thirdweb-dev-auth-solana.esm.js",
|
||||
"browser": {
|
||||
"./dist/thirdweb-dev-auth-solana.esm.js": "./dist/thirdweb-dev-auth-solana.browser.esm.js"
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ import { VerifyOptionsSchema } from "../schema/verify";
|
||||
* Create an EIP-4361 & CAIP-122 compliant message to sign based on the login payload
|
||||
*/
|
||||
function createLoginMessage(payload: LoginPayloadData): string {
|
||||
const typeField = payload.type === "evm" ? "Ethereum" : "Solana";
|
||||
const typeField = "Ethereum";
|
||||
const header = `${payload.domain} wants you to sign in with your ${typeField} account:`;
|
||||
let prefix = [header, payload.address].join("\n");
|
||||
prefix = [prefix, payload.statement].join("\n\n");
|
||||
|
||||
@@ -23,10 +23,7 @@ export const RawDateSchema = z.date().transform((i) => {
|
||||
return Math.floor(i.getTime() / 1000);
|
||||
});
|
||||
|
||||
export const AccountTypeSchema = z.union([
|
||||
z.literal("evm"),
|
||||
z.literal("solana"),
|
||||
]);
|
||||
export const AccountTypeSchema = z.literal("evm");
|
||||
|
||||
export type User<TContext extends Json = Json> = {
|
||||
address: string;
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
import { ThirdwebAuth } from "../core";
|
||||
import { LoginPayload, VerifyOptions } from "../core/schema";
|
||||
import { Keypair } from "@solana/web3.js";
|
||||
import { KeypairWallet } from "@thirdweb-dev/wallets/solana/wallets/keypair";
|
||||
|
||||
const authMap = new Map<string, ThirdwebAuth>();
|
||||
let wallet: KeypairWallet;
|
||||
|
||||
export async function verifyLogin(
|
||||
domain: string,
|
||||
payload: LoginPayload,
|
||||
options?: Omit<VerifyOptions, "domain">,
|
||||
) {
|
||||
wallet = wallet || new KeypairWallet(Keypair.generate());
|
||||
let auth: ThirdwebAuth;
|
||||
if (!authMap.has(domain)) {
|
||||
auth = new ThirdwebAuth(wallet, domain);
|
||||
authMap.set(domain, auth);
|
||||
} else {
|
||||
auth = authMap.get(domain) as ThirdwebAuth;
|
||||
}
|
||||
|
||||
try {
|
||||
const address = await auth.verify(payload, options);
|
||||
return { address, error: undefined };
|
||||
} catch (err: any) {
|
||||
return { address: undefined, error: err.message };
|
||||
}
|
||||
}
|
||||
@@ -1,353 +0,0 @@
|
||||
import { ThirdwebAuth } from "../src/core";
|
||||
import { Keypair } from "@solana/web3.js";
|
||||
import { KeypairWallet } from "@thirdweb-dev/wallets/solana/wallets/keypair";
|
||||
import { expect } from "chai";
|
||||
|
||||
describe("Wallet Authentication - Solana", async () => {
|
||||
let adminWallet: any, signerWallet: any, attackerWallet: any;
|
||||
let auth: ThirdwebAuth;
|
||||
|
||||
before(async () => {
|
||||
const [adminSigner, signerSigner, attackerSigner] = [
|
||||
Keypair.generate(),
|
||||
Keypair.generate(),
|
||||
Keypair.generate(),
|
||||
];
|
||||
|
||||
adminWallet = new KeypairWallet(adminSigner);
|
||||
signerWallet = new KeypairWallet(signerSigner);
|
||||
attackerWallet = new KeypairWallet(attackerSigner);
|
||||
|
||||
auth = new ThirdwebAuth(signerWallet, "thirdweb.com");
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
auth.updateWallet(signerWallet);
|
||||
});
|
||||
|
||||
it("Should verify logged in wallet", async () => {
|
||||
const payload = await auth.login();
|
||||
|
||||
auth.updateWallet(adminWallet);
|
||||
const address = await auth.verify(payload);
|
||||
|
||||
expect(address).to.equal(await signerWallet.getAddress());
|
||||
});
|
||||
|
||||
it("Should verify logged in wallet with chain ID and expiration", async () => {
|
||||
const payload = await auth.login({
|
||||
expirationTime: new Date(Date.now() + 1000 * 60 * 5),
|
||||
chainId: "137",
|
||||
});
|
||||
|
||||
auth.updateWallet(adminWallet);
|
||||
const address = await auth.verify(payload, {
|
||||
chainId: "137",
|
||||
});
|
||||
|
||||
expect(address).to.equal(await signerWallet.getAddress());
|
||||
});
|
||||
|
||||
it("Should verify payload with resources", async () => {
|
||||
const payload = await auth.login({
|
||||
resources: ["https://example.com", "https://test.com"],
|
||||
});
|
||||
|
||||
auth.updateWallet(adminWallet);
|
||||
const address = await auth.verify(payload, {
|
||||
resources: ["https://example.com", "https://test.com"],
|
||||
});
|
||||
|
||||
expect(address).to.equal(await signerWallet.getAddress());
|
||||
});
|
||||
|
||||
it("Should reject payload without necessary resources", async () => {
|
||||
const payload = await auth.login({
|
||||
resources: ["https://example.com"],
|
||||
});
|
||||
|
||||
auth.updateWallet(adminWallet);
|
||||
try {
|
||||
await auth.verify(payload, {
|
||||
resources: ["https://example.com", "https://test.com"],
|
||||
});
|
||||
expect.fail();
|
||||
} catch (err: any) {
|
||||
expect(err.message).to.equal(
|
||||
"Login request is missing required resources: https://test.com",
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it("Should verify payload with customized statement", async () => {
|
||||
const payload = await auth.login({
|
||||
statement: "Please sign!",
|
||||
});
|
||||
|
||||
auth.updateWallet(adminWallet);
|
||||
const address = await auth.verify(payload, {
|
||||
statement: "Please sign!",
|
||||
});
|
||||
|
||||
expect(address).to.equal(await signerWallet.getAddress());
|
||||
});
|
||||
|
||||
it("Should reject payload with incorrect statement", async () => {
|
||||
const payload = await auth.login({
|
||||
statement: "Please sign!",
|
||||
});
|
||||
|
||||
auth.updateWallet(adminWallet);
|
||||
try {
|
||||
await auth.verify(payload, {
|
||||
statement: "Please sign again!",
|
||||
});
|
||||
expect.fail();
|
||||
} catch (err: any) {
|
||||
expect(err.message).to.include(
|
||||
"Expected statement 'Please sign again!' does not match statement on payload",
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it("Should reject invalid nonce", async () => {
|
||||
const payload = await auth.login();
|
||||
|
||||
auth.updateWallet(adminWallet);
|
||||
try {
|
||||
await auth.verify(payload, {
|
||||
validateNonce: (nonce: string) => {
|
||||
if (nonce === payload.payload.nonce) {
|
||||
throw new Error();
|
||||
}
|
||||
},
|
||||
});
|
||||
expect.fail();
|
||||
} catch (err: any) {
|
||||
expect(err.message).to.equal("Login request nonce is invalid");
|
||||
}
|
||||
});
|
||||
|
||||
it("Should accept valid nonce", async () => {
|
||||
const payload = await auth.login();
|
||||
|
||||
auth.updateWallet(adminWallet);
|
||||
const address = await auth.verify(payload, {
|
||||
validateNonce: (nonce: string) => {
|
||||
if (nonce !== payload.payload.nonce) {
|
||||
throw new Error();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
expect(address).to.equal(await signerWallet.getAddress());
|
||||
});
|
||||
|
||||
it("Should reject payload with incorrect domain", async () => {
|
||||
const payload = await auth.login();
|
||||
|
||||
auth.updateWallet(adminWallet);
|
||||
try {
|
||||
await auth.verify(payload, { domain: "test.thirdweb.com" });
|
||||
expect.fail();
|
||||
} catch (err: any) {
|
||||
expect(err.message).to.equal(
|
||||
"Expected domain 'test.thirdweb.com' does not match domain on payload 'thirdweb.com'",
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it("Should reject expired login payload", async () => {
|
||||
const payload = await auth.login({
|
||||
expirationTime: new Date(Date.now() - 1000 * 60 * 5),
|
||||
});
|
||||
|
||||
auth.updateWallet(adminWallet);
|
||||
try {
|
||||
await auth.verify(payload);
|
||||
expect.fail();
|
||||
} catch (err: any) {
|
||||
expect(err.message).to.equal("Login request has expired");
|
||||
}
|
||||
});
|
||||
|
||||
it("Should reject payload with incorrect chain ID", async () => {
|
||||
const payload = await auth.login({
|
||||
chainId: "1",
|
||||
});
|
||||
|
||||
auth.updateWallet(adminWallet);
|
||||
try {
|
||||
await auth.verify(payload, {
|
||||
chainId: "137",
|
||||
});
|
||||
expect.fail();
|
||||
} catch (err: any) {
|
||||
expect(err.message).to.equal(
|
||||
"Expected chain ID '137' does not match chain ID on payload '1'",
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it("Should reject payload with incorrect signer", async () => {
|
||||
const payload = await auth.login();
|
||||
payload.payload.address = await attackerWallet.getAddress();
|
||||
|
||||
auth.updateWallet(adminWallet);
|
||||
try {
|
||||
await auth.verify(payload);
|
||||
expect.fail();
|
||||
} catch (err: any) {
|
||||
expect(err.message).to.contain("does not match payload address");
|
||||
}
|
||||
});
|
||||
|
||||
it("Should generate valid authentication token", async () => {
|
||||
const payload = await auth.login();
|
||||
|
||||
auth.updateWallet(adminWallet);
|
||||
const token = await auth.generate(payload);
|
||||
const user = await auth.authenticate(token);
|
||||
|
||||
expect(user.address).to.equal(await signerWallet.getAddress());
|
||||
});
|
||||
|
||||
it("Should reject token with incorrect domain", async () => {
|
||||
const payload = await auth.login();
|
||||
|
||||
auth.updateWallet(adminWallet);
|
||||
const token = await auth.generate(payload);
|
||||
|
||||
try {
|
||||
await auth.authenticate(token, { domain: "test.thirdweb.com" });
|
||||
expect.fail();
|
||||
} catch (err: any) {
|
||||
expect(err.message).to.contain(
|
||||
"Expected token to be for the domain 'test.thirdweb.com', but found token with domain 'thirdweb.com'",
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it("Should reject token before invalid before", async () => {
|
||||
const payload = await auth.login();
|
||||
|
||||
auth.updateWallet(adminWallet);
|
||||
const token = await auth.generate(payload, {
|
||||
invalidBefore: new Date(Date.now() + 1000 * 60 * 5),
|
||||
});
|
||||
|
||||
try {
|
||||
await auth.authenticate(token);
|
||||
expect.fail();
|
||||
} catch (err: any) {
|
||||
expect(err.message).to.contain("This token is invalid before");
|
||||
}
|
||||
});
|
||||
|
||||
it("Should reject expired authentication token", async () => {
|
||||
const payload = await auth.login();
|
||||
|
||||
auth.updateWallet(adminWallet);
|
||||
const token = await auth.generate(payload, {
|
||||
expirationTime: new Date(Date.now() - 1000 * 60 * 5),
|
||||
});
|
||||
|
||||
try {
|
||||
await auth.authenticate(token);
|
||||
expect.fail();
|
||||
} catch (err: any) {
|
||||
expect(err.message).to.contain("This token expired");
|
||||
}
|
||||
});
|
||||
|
||||
it("Should reject if admin address is not connected wallet address", async () => {
|
||||
const payload = await auth.login();
|
||||
|
||||
auth.updateWallet(adminWallet);
|
||||
const token = await auth.generate(payload);
|
||||
|
||||
auth.updateWallet(signerWallet);
|
||||
try {
|
||||
await auth.authenticate(token);
|
||||
expect.fail();
|
||||
} catch (err: any) {
|
||||
expect(err.message).to.contain(
|
||||
`The expected issuer address '${await signerWallet.getAddress()}' did not match the token issuer address '${await adminWallet.getAddress()}'`,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it("Should accept token with valid token ID", async () => {
|
||||
const payload = await auth.login();
|
||||
|
||||
auth.updateWallet(adminWallet);
|
||||
const token = await auth.generate(payload, {
|
||||
tokenId: "test",
|
||||
});
|
||||
|
||||
const user = await auth.authenticate(token, {
|
||||
validateTokenId: (tokenId: string) => {
|
||||
if (tokenId !== "test") {
|
||||
throw new Error();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
expect(user.address).to.equal(await signerWallet.getAddress());
|
||||
});
|
||||
|
||||
it("Should reject token with invalid token ID", async () => {
|
||||
const payload = await auth.login();
|
||||
|
||||
auth.updateWallet(adminWallet);
|
||||
const token = await auth.generate(payload, {
|
||||
tokenId: "test",
|
||||
});
|
||||
|
||||
try {
|
||||
await auth.authenticate(token, {
|
||||
validateTokenId: (tokenId: string) => {
|
||||
if (tokenId !== "invalid") {
|
||||
throw new Error();
|
||||
}
|
||||
},
|
||||
});
|
||||
expect.fail();
|
||||
} catch (err: any) {
|
||||
expect(err.message).to.contain("Token ID is invalid");
|
||||
}
|
||||
});
|
||||
|
||||
it("Should propagate session on token", async () => {
|
||||
const payload = await auth.login();
|
||||
|
||||
auth.updateWallet(adminWallet);
|
||||
const token = await auth.generate(payload, {
|
||||
session: { role: "admin" },
|
||||
});
|
||||
|
||||
const user = await auth.authenticate(token);
|
||||
|
||||
expect(user.address).to.equal(await signerWallet.getAddress());
|
||||
expect(user.session).to.deep.equal({ role: "admin" });
|
||||
});
|
||||
|
||||
it("Should call session callback function", async () => {
|
||||
const payload = await auth.login();
|
||||
|
||||
auth.updateWallet(adminWallet);
|
||||
const token = await auth.generate(payload, {
|
||||
session: (address: string) => {
|
||||
return { address, role: "admin" };
|
||||
},
|
||||
});
|
||||
|
||||
const user = await auth.authenticate(token);
|
||||
|
||||
expect(user.address).to.equal(await signerWallet.getAddress());
|
||||
expect(user.session).to.deep.equal({
|
||||
address: await signerWallet.getAddress(),
|
||||
role: "admin",
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,5 +1,85 @@
|
||||
# thirdweb
|
||||
|
||||
## 0.13.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`526176c4`](https://github.com/thirdweb-dev/js/commit/526176c47108c91d83bcfc5f0ca556274e6462d6), [`d1f8e951`](https://github.com/thirdweb-dev/js/commit/d1f8e951623f1691fdfe3d1e8645970d0a52eb06), [`09120c92`](https://github.com/thirdweb-dev/js/commit/09120c923cca804b9d4f5f779e5a53c97ecc8223), [`6573556d`](https://github.com/thirdweb-dev/js/commit/6573556d0e03efa0d6a157fccb0a1c08dd22d7cd)]:
|
||||
- @thirdweb-dev/sdk@4.0.2
|
||||
- @thirdweb-dev/wallets@2.0.3
|
||||
- @thirdweb-dev/auth@4.0.3
|
||||
|
||||
## 0.13.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`1f3c64d3`](https://github.com/thirdweb-dev/js/commit/1f3c64d3618903b9008cc7b633ea890b508e7800), [`74941603`](https://github.com/thirdweb-dev/js/commit/74941603a96456da46a47147f67c98235ac55022), [`4b98e487`](https://github.com/thirdweb-dev/js/commit/4b98e487d4b47225d7095e5444dc5e7608db48a3), [`693f349d`](https://github.com/thirdweb-dev/js/commit/693f349db2478e1cd0fc82a9ef9882f46832b125), [`dcdb0dcb`](https://github.com/thirdweb-dev/js/commit/dcdb0dcb838168a22c8335738852316dfb6e6fc9), [`0f12d1f9`](https://github.com/thirdweb-dev/js/commit/0f12d1f90320923309f085c372d3a5ed01dd4606), [`b3b9edca`](https://github.com/thirdweb-dev/js/commit/b3b9edca29e7d4053b14270a61caa89c34fecf9e), [`63ad0050`](https://github.com/thirdweb-dev/js/commit/63ad0050f0a24ec15b90933b5664d697618cf2d0)]:
|
||||
- @thirdweb-dev/sdk@4.0.1
|
||||
- @thirdweb-dev/wallets@2.0.2
|
||||
- @thirdweb-dev/auth@4.0.2
|
||||
|
||||
## 0.13.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`e684d05e`](https://github.com/thirdweb-dev/js/commit/e684d05e222458f02c8158eb9385d68c879dd946)]:
|
||||
- @thirdweb-dev/wallets@2.0.1
|
||||
- @thirdweb-dev/auth@4.0.1
|
||||
|
||||
## 0.13.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#1630](https://github.com/thirdweb-dev/js/pull/1630) [`ce4608bf`](https://github.com/thirdweb-dev/js/commit/ce4608bff4783caf164ad6e21b42a827b89badf8) Thanks [@jnsdls](https://github.com/jnsdls)! - **Dropped Support for Solana**:
|
||||
|
||||
- We've decided to drop support for Solana across our SDKs.
|
||||
- Starting with this version of our SDKs all previous solana related functionality will be removed.
|
||||
- Previous versions of our SDKs will continue to work with Solana. However, we will not be providing any further updates or bug fixes for Solana.
|
||||
- You can read a detailed explanation of our decision [on our blog](https://blog.thirdweb.com/discontinuing-solana-support/).
|
||||
|
||||
- [#1630](https://github.com/thirdweb-dev/js/pull/1630) [`ce4608bf`](https://github.com/thirdweb-dev/js/commit/ce4608bff4783caf164ad6e21b42a827b89badf8) Thanks [@jnsdls](https://github.com/jnsdls)! - **Dropped Support for Node 16**:
|
||||
|
||||
- As part of our commitment to maintain up-to-date with the evolving ecosystem and provide the best support for our users, we have made the decision to cease support for Node 16. Starting with this version, our SDKs will no longer be tested against or guaranteed to work with Node.js version 16.
|
||||
- We encourage users to upgrade to a more recent version of Node.js to continue to benefit from the latest features, improvements, and security updates.
|
||||
- If you are unable to upgrade to a more recent version of Node.js, you can continue to use the previous version of our SDKs. However, we will not be providing any further updates or bug fixes for Node 16.
|
||||
- For more information on EOL status of Node 16, see [Node.js Release Cycle](https://nodejs.dev/en/about/releases/).
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`ce4608bf`](https://github.com/thirdweb-dev/js/commit/ce4608bff4783caf164ad6e21b42a827b89badf8), [`ce4608bf`](https://github.com/thirdweb-dev/js/commit/ce4608bff4783caf164ad6e21b42a827b89badf8)]:
|
||||
- @thirdweb-dev/storage@2.0.0
|
||||
- @thirdweb-dev/wallets@2.0.0
|
||||
- @thirdweb-dev/auth@4.0.0
|
||||
- @thirdweb-dev/sdk@4.0.0
|
||||
|
||||
## 0.12.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`ec36b13a`](https://github.com/thirdweb-dev/js/commit/ec36b13a30e0071548df0b7a6eb5299e2e65e4f9), [`6abb8459`](https://github.com/thirdweb-dev/js/commit/6abb8459712e387b6d8b2edf7eb16fb906c05dae), [`a6c36724`](https://github.com/thirdweb-dev/js/commit/a6c36724eb930ee0abbce876bb7847c859c6fb48)]:
|
||||
- @thirdweb-dev/sdk@3.10.67
|
||||
- @thirdweb-dev/wallets@1.3.5
|
||||
- @thirdweb-dev/auth@3.2.48
|
||||
|
||||
## 0.12.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`9bd01de5`](https://github.com/thirdweb-dev/js/commit/9bd01de5f9c388e758fba9af7899dc4a9c5a0101), [`f35fbec1`](https://github.com/thirdweb-dev/js/commit/f35fbec1be14332d06e73b5f44f66975ef311d6c)]:
|
||||
- @thirdweb-dev/wallets@1.3.4
|
||||
- @thirdweb-dev/sdk@3.10.66
|
||||
- @thirdweb-dev/auth@3.2.47
|
||||
|
||||
## 0.12.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`6d3d76cf`](https://github.com/thirdweb-dev/js/commit/6d3d76cff8018015faa191a1f8bd4f34506a6650), [`04f2f7b8`](https://github.com/thirdweb-dev/js/commit/04f2f7b8ff5f19345d868fc515a24ccd6ffd0ab9), [`15fe4779`](https://github.com/thirdweb-dev/js/commit/15fe4779f4b99e51afe214ac3ebb31f611089787)]:
|
||||
- @thirdweb-dev/wallets@1.3.3
|
||||
- @thirdweb-dev/storage@1.2.11
|
||||
- @thirdweb-dev/sdk@3.10.65
|
||||
- @thirdweb-dev/auth@3.2.46
|
||||
|
||||
## 0.12.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -3,7 +3,6 @@ export const CREATE_MESSAGES = {
|
||||
projectName: "What is your project named?",
|
||||
contractName: "What will be the name of your new smart contract?",
|
||||
extensionName: "What will be the name of your new extension?",
|
||||
chain: "Which blockchain do you want to use?",
|
||||
framework: "What framework do you want to use?",
|
||||
language: "What language do you want to use?",
|
||||
contract: "What type of contract do you want to start from?",
|
||||
|
||||
@@ -19,8 +19,6 @@ describe("npx thirdweb create", () => {
|
||||
await pressKey("enter");
|
||||
await waitForText(CREATE_MESSAGES.projectName);
|
||||
await pressKey("enter");
|
||||
await waitForText(CREATE_MESSAGES.chain);
|
||||
await pressKey("enter");
|
||||
await waitForText(CREATE_MESSAGES.framework);
|
||||
// select CRA
|
||||
await pressKey("arrowDown");
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "thirdweb",
|
||||
"main": "dist/cli/index.js",
|
||||
"version": "0.12.7",
|
||||
"version": "0.13.3",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/cli",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=16.0.0"
|
||||
"node": ">=18.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@gmrchk/cli-testing-library": "^0.1.2",
|
||||
@@ -50,7 +50,6 @@
|
||||
"got": "11.8.5",
|
||||
"inquirer": "^8.2.3",
|
||||
"js-yaml": "^4.1.0",
|
||||
"node-fetch": "^3.3.2",
|
||||
"open": "^8.4.0",
|
||||
"prompts": "^2.4.2",
|
||||
"rimraf": "^3.0.2",
|
||||
|
||||
@@ -270,7 +270,6 @@ const main = async () => {
|
||||
"Explicitly tell the CLI to bootstrap the app using pnpm",
|
||||
)
|
||||
.option("--framework [name]", "The preferred framework.")
|
||||
.option("--solana", "Initialize as a Solana project.")
|
||||
.option("--evm", "Initialize as an Ethereum project.")
|
||||
.option(
|
||||
"-t, --template [name]",
|
||||
|
||||
@@ -118,9 +118,6 @@ export async function twCreate(
|
||||
framework = "pwa-vite";
|
||||
}
|
||||
|
||||
if (options.solana) {
|
||||
chain = "solana";
|
||||
}
|
||||
if (options.evm) {
|
||||
chain = "evm";
|
||||
}
|
||||
@@ -251,21 +248,7 @@ export async function twCreate(
|
||||
|
||||
if (!options.template) {
|
||||
if (projectType === "app" && !chain) {
|
||||
const res = await prompts({
|
||||
type: "select",
|
||||
name: "chain",
|
||||
message: CREATE_MESSAGES.chain,
|
||||
choices: [
|
||||
{ title: "EVM", value: "evm" },
|
||||
{ title: "Solana", value: "solana" },
|
||||
],
|
||||
});
|
||||
|
||||
if (res.chain === "solana") {
|
||||
chain = "solana";
|
||||
} else {
|
||||
chain = "evm";
|
||||
}
|
||||
chain = "evm";
|
||||
}
|
||||
|
||||
if (projectType === "app" && !framework) {
|
||||
@@ -273,25 +256,15 @@ export async function twCreate(
|
||||
type: "select",
|
||||
name: "framework",
|
||||
message: CREATE_MESSAGES.framework,
|
||||
choices:
|
||||
chain === "solana"
|
||||
? [
|
||||
{ title: "Next.js", value: "next" },
|
||||
{ title: "Create React App", value: "cra" },
|
||||
{ title: "Node.js", value: "node" },
|
||||
{ title: "Express", value: "express" },
|
||||
// Solana doesn't support Vite just yet:
|
||||
// { title: "Vite", value: "vite" },
|
||||
]
|
||||
: [
|
||||
{ title: "Next.js", value: "next" },
|
||||
{ title: "Create React App", value: "cra" },
|
||||
{ title: "Vite", value: "vite" },
|
||||
{ title: "PWA Vite", value: "pwa-vite" },
|
||||
{ title: "React Native", value: "react-native" },
|
||||
{ title: "Node.js", value: "node" },
|
||||
{ title: "Express", value: "express" },
|
||||
],
|
||||
choices: [
|
||||
{ title: "Next.js", value: "next" },
|
||||
{ title: "Create React App", value: "cra" },
|
||||
{ title: "Vite", value: "vite" },
|
||||
{ title: "PWA Vite", value: "pwa-vite" },
|
||||
{ title: "React Native", value: "react-native" },
|
||||
{ title: "Node.js", value: "node" },
|
||||
{ title: "Express", value: "express" },
|
||||
],
|
||||
});
|
||||
|
||||
if (typeof res.framework === "string") {
|
||||
@@ -512,7 +485,6 @@ export async function twCreate(
|
||||
framework,
|
||||
language,
|
||||
template,
|
||||
chain,
|
||||
});
|
||||
} else {
|
||||
await createContractProject({
|
||||
|
||||
@@ -24,14 +24,12 @@ export async function createApp({
|
||||
framework,
|
||||
language,
|
||||
template,
|
||||
chain,
|
||||
}: {
|
||||
appPath: string;
|
||||
packageManager: PackageManager;
|
||||
framework?: string;
|
||||
language?: string;
|
||||
template?: string;
|
||||
chain?: string;
|
||||
}): Promise<void> {
|
||||
let frameworkPath = "";
|
||||
|
||||
@@ -47,9 +45,7 @@ export async function createApp({
|
||||
process.exit(1);
|
||||
}
|
||||
} else if (framework) {
|
||||
frameworkPath = `${framework}-${language || "javascript"}-${
|
||||
chain === "solana" ? "solana-" : ""
|
||||
}starter`;
|
||||
frameworkPath = `${framework}-${language || "javascript"}-starter`;
|
||||
const found = await hasTemplate(frameworkPath);
|
||||
|
||||
if (!found) {
|
||||
|
||||
@@ -156,7 +156,6 @@ export const getDependenciesForPython = (
|
||||
|
||||
export const getLatestVersion = async (packageName: string): Promise<any> => {
|
||||
try {
|
||||
const fetch = (await import("node-fetch")).default;
|
||||
const url = `https://registry.npmjs.org/${packageName}`;
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) {
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @thirdweb-dev/contracts-js
|
||||
|
||||
## 1.3.14
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1757](https://github.com/thirdweb-dev/js/pull/1757) [`63ad0050`](https://github.com/thirdweb-dev/js/commit/63ad0050f0a24ec15b90933b5664d697618cf2d0) Thanks [@kumaryash90](https://github.com/kumaryash90)! - Update deployment and tests for MarketplaceV3 latest
|
||||
|
||||
## 1.3.13
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/contracts-js",
|
||||
"version": "1.3.13",
|
||||
"version": "1.3.14",
|
||||
"main": "dist/thirdweb-dev-contracts-js.cjs.js",
|
||||
"module": "dist/thirdweb-dev-contracts-js.esm.js",
|
||||
"browser": {
|
||||
@@ -10,7 +10,7 @@
|
||||
"license": "Apache-2.0",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/contracts-js",
|
||||
"dependencies": {
|
||||
"@thirdweb-dev/contracts": "3.10.0"
|
||||
"@thirdweb-dev/contracts": "3.10.2-3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/preset-env": "^7.22.9",
|
||||
|
||||
@@ -1,5 +1,128 @@
|
||||
# @thirdweb-dev/react-core
|
||||
|
||||
## 4.0.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1758](https://github.com/thirdweb-dev/js/pull/1758) [`08e9cd20`](https://github.com/thirdweb-dev/js/commit/08e9cd206bcc37cf1e84a878dc78bc4f38e5092c) Thanks [@kien-ngo](https://github.com/kien-ngo)! - Add pagination to useOwnedNFTs
|
||||
|
||||
- Updated dependencies [[`526176c4`](https://github.com/thirdweb-dev/js/commit/526176c47108c91d83bcfc5f0ca556274e6462d6), [`d1f8e951`](https://github.com/thirdweb-dev/js/commit/d1f8e951623f1691fdfe3d1e8645970d0a52eb06), [`09120c92`](https://github.com/thirdweb-dev/js/commit/09120c923cca804b9d4f5f779e5a53c97ecc8223), [`6573556d`](https://github.com/thirdweb-dev/js/commit/6573556d0e03efa0d6a157fccb0a1c08dd22d7cd)]:
|
||||
- @thirdweb-dev/sdk@4.0.2
|
||||
- @thirdweb-dev/wallets@2.0.3
|
||||
- @thirdweb-dev/auth@4.0.3
|
||||
|
||||
## 4.0.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`1f3c64d3`](https://github.com/thirdweb-dev/js/commit/1f3c64d3618903b9008cc7b633ea890b508e7800), [`74941603`](https://github.com/thirdweb-dev/js/commit/74941603a96456da46a47147f67c98235ac55022), [`4b98e487`](https://github.com/thirdweb-dev/js/commit/4b98e487d4b47225d7095e5444dc5e7608db48a3), [`693f349d`](https://github.com/thirdweb-dev/js/commit/693f349db2478e1cd0fc82a9ef9882f46832b125), [`dcdb0dcb`](https://github.com/thirdweb-dev/js/commit/dcdb0dcb838168a22c8335738852316dfb6e6fc9), [`0f12d1f9`](https://github.com/thirdweb-dev/js/commit/0f12d1f90320923309f085c372d3a5ed01dd4606), [`b3b9edca`](https://github.com/thirdweb-dev/js/commit/b3b9edca29e7d4053b14270a61caa89c34fecf9e), [`63ad0050`](https://github.com/thirdweb-dev/js/commit/63ad0050f0a24ec15b90933b5664d697618cf2d0)]:
|
||||
- @thirdweb-dev/sdk@4.0.1
|
||||
- @thirdweb-dev/wallets@2.0.2
|
||||
- @thirdweb-dev/auth@4.0.2
|
||||
|
||||
## 4.0.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`e684d05e`](https://github.com/thirdweb-dev/js/commit/e684d05e222458f02c8158eb9385d68c879dd946)]:
|
||||
- @thirdweb-dev/wallets@2.0.1
|
||||
- @thirdweb-dev/auth@4.0.1
|
||||
|
||||
## 4.0.0
|
||||
|
||||
### Major Changes
|
||||
|
||||
- [#1630](https://github.com/thirdweb-dev/js/pull/1630) [`ce4608bf`](https://github.com/thirdweb-dev/js/commit/ce4608bff4783caf164ad6e21b42a827b89badf8) Thanks [@jnsdls](https://github.com/jnsdls)! - **Dropped Support for Solana**:
|
||||
|
||||
- We've decided to drop support for Solana across our SDKs.
|
||||
- Starting with this version of our SDKs all previous solana related functionality will be removed.
|
||||
- Previous versions of our SDKs will continue to work with Solana. However, we will not be providing any further updates or bug fixes for Solana.
|
||||
- You can read a detailed explanation of our decision [on our blog](https://blog.thirdweb.com/discontinuing-solana-support/).
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1645](https://github.com/thirdweb-dev/js/pull/1645) [`79f91ee2`](https://github.com/thirdweb-dev/js/commit/79f91ee2d96e3a9591d6104c542496bce11f3c71) Thanks [@MananTank](https://github.com/MananTank)! - `WalletConfig.connectUI`` props updated:
|
||||
|
||||
- `close` and `open` removed - wallet can no longer "close" the Modal
|
||||
- `hide` and `show` added to only allow hiding and showing the Modal
|
||||
- `connected` added - use this instead of `close` when wallet is connected and Modal is safe to close.
|
||||
|
||||
- Updated dependencies [[`ce4608bf`](https://github.com/thirdweb-dev/js/commit/ce4608bff4783caf164ad6e21b42a827b89badf8), [`ce4608bf`](https://github.com/thirdweb-dev/js/commit/ce4608bff4783caf164ad6e21b42a827b89badf8)]:
|
||||
- @thirdweb-dev/storage@2.0.0
|
||||
- @thirdweb-dev/wallets@2.0.0
|
||||
- @thirdweb-dev/auth@4.0.0
|
||||
- @thirdweb-dev/sdk@4.0.0
|
||||
|
||||
## 3.16.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`ec36b13a`](https://github.com/thirdweb-dev/js/commit/ec36b13a30e0071548df0b7a6eb5299e2e65e4f9), [`6abb8459`](https://github.com/thirdweb-dev/js/commit/6abb8459712e387b6d8b2edf7eb16fb906c05dae), [`a6c36724`](https://github.com/thirdweb-dev/js/commit/a6c36724eb930ee0abbce876bb7847c859c6fb48)]:
|
||||
- @thirdweb-dev/sdk@3.10.67
|
||||
- @thirdweb-dev/wallets@1.3.5
|
||||
- @thirdweb-dev/auth@3.2.48
|
||||
|
||||
## 3.16.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1719](https://github.com/thirdweb-dev/js/pull/1719) [`93127047`](https://github.com/thirdweb-dev/js/commit/931270479ef227556a1077357a8c000b08de6e8d) Thanks [@MananTank](https://github.com/MananTank)! - Type refactor for useWallet hook
|
||||
|
||||
- [#1716](https://github.com/thirdweb-dev/js/pull/1716) [`d3c8626a`](https://github.com/thirdweb-dev/js/commit/d3c8626a5a8def882c1592b236048ebe88e85d49) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Better `useWallet()` API to obtain specific wallet instances.
|
||||
|
||||
```
|
||||
const smartWallet = useWallet("smartWallet"); // returns a SmartWallet instance
|
||||
const embeddedWallet = useWallet("embeddedWallet"); // returns a EmbeddedWallet instance
|
||||
```
|
||||
|
||||
- [#1712](https://github.com/thirdweb-dev/js/pull/1712) [`9bd01de5`](https://github.com/thirdweb-dev/js/commit/9bd01de5f9c388e758fba9af7899dc4a9c5a0101) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Add `useCreateSessionKey` and `useRevokeSessionKey` hooks
|
||||
|
||||
```
|
||||
const Component = () => {
|
||||
const {
|
||||
mutate: createSessionKey,
|
||||
isLoading,
|
||||
error,
|
||||
} = useCreateSessionKey();
|
||||
|
||||
if (error) {
|
||||
console.error("failed to create session key", error);
|
||||
}
|
||||
|
||||
return (
|
||||
<button
|
||||
disabled={isLoading}
|
||||
onClick={() => createSessionKey(
|
||||
"0x...",
|
||||
{
|
||||
approvedCallTargets: ["0x..."], // the addresses of contracts that the session key can call
|
||||
nativeTokenLimitPerTransaction: 0.1, // the maximum amount of native token (in ETH) that the session key can spend per transaction
|
||||
startDate: new Date(), // the date when the session key becomes active
|
||||
expirationDate = new Date(Date.now() + 24 * 60 * 60 * 1000); // the date when the session key expires
|
||||
}
|
||||
)}
|
||||
>
|
||||
Create Session Key
|
||||
</button>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
- Updated dependencies [[`9bd01de5`](https://github.com/thirdweb-dev/js/commit/9bd01de5f9c388e758fba9af7899dc4a9c5a0101), [`f35fbec1`](https://github.com/thirdweb-dev/js/commit/f35fbec1be14332d06e73b5f44f66975ef311d6c)]:
|
||||
- @thirdweb-dev/[email protected]
|
||||
- @thirdweb-dev/[email protected]
|
||||
- @thirdweb-dev/[email protected]
|
||||
|
||||
## 3.16.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`6d3d76cf`](https://github.com/thirdweb-dev/js/commit/6d3d76cff8018015faa191a1f8bd4f34506a6650), [`04f2f7b8`](https://github.com/thirdweb-dev/js/commit/04f2f7b8ff5f19345d868fc515a24ccd6ffd0ab9), [`15fe4779`](https://github.com/thirdweb-dev/js/commit/15fe4779f4b99e51afe214ac3ebb31f611089787)]:
|
||||
- @thirdweb-dev/[email protected]
|
||||
- @thirdweb-dev/[email protected]
|
||||
- @thirdweb-dev/[email protected]
|
||||
- @thirdweb-dev/[email protected]
|
||||
|
||||
## 3.16.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,339 +0,0 @@
|
||||
/**
|
||||
* 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-core-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": [],
|
||||
/**
|
||||
* 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-core",
|
||||
"version": "3.16.2",
|
||||
"version": "4.0.3",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-core",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"license": "Apache-2.0",
|
||||
@@ -25,24 +25,15 @@
|
||||
},
|
||||
"default": "./evm/dist/thirdweb-dev-react-core-evm.cjs.js"
|
||||
},
|
||||
"./solana": {
|
||||
"module": {
|
||||
"browser": "./solana/dist/thirdweb-dev-react-core-solana.browser.esm.js",
|
||||
"default": "./solana/dist/thirdweb-dev-react-core-solana.esm.js"
|
||||
},
|
||||
"default": "./solana/dist/thirdweb-dev-react-core-solana.cjs.js"
|
||||
},
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"files": [
|
||||
"dist/",
|
||||
"evm/",
|
||||
"solana/"
|
||||
"evm/"
|
||||
],
|
||||
"preconstruct": {
|
||||
"entrypoints": [
|
||||
"index.ts",
|
||||
"solana/index.ts",
|
||||
"evm/index.ts"
|
||||
],
|
||||
"exports": {
|
||||
@@ -57,10 +48,9 @@
|
||||
"lint": "eslint src/",
|
||||
"fix": "eslint src/ --fix",
|
||||
"clean": "rm -rf dist/",
|
||||
"generate-docs": "pnpm generate-docs:evm && pnpm generate-docs:solana && pnpm generate-snippets",
|
||||
"generate-docs": "pnpm generate-docs:evm && pnpm 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",
|
||||
"generate-snippets": "node ./scripts/generate-snippets-evm.mjs && node ./scripts/generate-feature-snippets-evm.mjs",
|
||||
"build": "tsc && preconstruct build",
|
||||
"push": "yalc push"
|
||||
},
|
||||
@@ -75,8 +65,6 @@
|
||||
"@microsoft/api-extractor": "^7.36.3",
|
||||
"@microsoft/tsdoc": "^0.14.1",
|
||||
"@preconstruct/cli": "2.7.0",
|
||||
"@solana/wallet-adapter-react": "^0.15.19",
|
||||
"@solana/web3.js": "^1.62.0",
|
||||
"@thirdweb-dev/auth": "workspace:*",
|
||||
"@thirdweb-dev/tsconfig": "workspace:*",
|
||||
"@types/js-cookie": "^3.0.3",
|
||||
@@ -87,7 +75,7 @@
|
||||
"eslint": "^8.45.0",
|
||||
"eslint-config-prettier": "^8.9.0",
|
||||
"eslint-config-thirdweb": "workspace:*",
|
||||
"eslint-plugin-better-tree-shaking": "0.0.3",
|
||||
"eslint-plugin-better-tree-shaking": "0.0.4",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"eslint-plugin-inclusive-language": "^2.2.0",
|
||||
"eslint-plugin-prettier": "^5.0.0",
|
||||
@@ -109,17 +97,7 @@
|
||||
"tiny-invariant": "^1.2.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@solana/wallet-adapter-react": "^0.15.19",
|
||||
"@solana/web3.js": "^1.62.0",
|
||||
"ethers": ">=5.5.1",
|
||||
"react": ">=18.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@solana/web3.js": {
|
||||
"optional": true
|
||||
},
|
||||
"@solana/wallet-adapter-react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,135 +0,0 @@
|
||||
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-core.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,7 +0,0 @@
|
||||
{
|
||||
"main": "dist/thirdweb-dev-react-core-solana.cjs.js",
|
||||
"module": "dist/thirdweb-dev-react-core-solana.esm.js",
|
||||
"browser": {
|
||||
"./dist/thirdweb-dev-react-core-solana.esm.js": "./dist/thirdweb-dev-react-core-solana.browser.esm.js"
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,74 @@
|
||||
import { useWalletContext } from "../providers/thirdweb-wallet-provider";
|
||||
import invariant from "tiny-invariant";
|
||||
import type {
|
||||
BloctoWallet,
|
||||
CoinbaseWallet,
|
||||
EmbeddedWallet,
|
||||
FrameWallet,
|
||||
LocalWallet,
|
||||
MagicLink,
|
||||
MetaMaskWallet,
|
||||
PaperWallet,
|
||||
PhantomWallet,
|
||||
RainbowWallet,
|
||||
SafeWallet,
|
||||
SmartWallet,
|
||||
TrustWallet,
|
||||
WalletConnect,
|
||||
walletIds,
|
||||
} from "@thirdweb-dev/wallets";
|
||||
import { WalletInstance } from "../types/wallet";
|
||||
|
||||
export type WalletId = (typeof walletIds)[keyof typeof walletIds];
|
||||
|
||||
type WalletIdToWalletTypeMap = {
|
||||
metamask: MetaMaskWallet;
|
||||
coinbase: CoinbaseWallet;
|
||||
rainbowWallet: RainbowWallet;
|
||||
blocto: BloctoWallet;
|
||||
frame: FrameWallet;
|
||||
localWallet: LocalWallet;
|
||||
magicLink: MagicLink;
|
||||
paper: PaperWallet;
|
||||
smartWallet: SmartWallet;
|
||||
safe: SafeWallet;
|
||||
trust: TrustWallet;
|
||||
embeddedWallet: EmbeddedWallet;
|
||||
walletConnect: WalletConnect;
|
||||
phantom: PhantomWallet;
|
||||
walletConnectV1: WalletConnect;
|
||||
};
|
||||
|
||||
/**
|
||||
* @returns the current active wallet instance
|
||||
*/
|
||||
export function useWallet() {
|
||||
export function useWallet<T extends WalletId>(
|
||||
walletId: T,
|
||||
): WalletIdToWalletTypeMap[T] | undefined;
|
||||
export function useWallet(): WalletInstance | undefined;
|
||||
export function useWallet<T extends WalletId>(walletId?: T) {
|
||||
const context = useWalletContext();
|
||||
invariant(
|
||||
context,
|
||||
"useWallet() hook must be used within a <ThirdwebProvider/>",
|
||||
);
|
||||
return context.activeWallet;
|
||||
|
||||
const activeWallet = context.activeWallet;
|
||||
|
||||
if (!activeWallet) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// if walletId is provided, return the wallet instance only if it matches the walletId
|
||||
if (walletId) {
|
||||
if (activeWallet.walletId === walletId) {
|
||||
return activeWallet as WalletIdToWalletTypeMap[T];
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
return activeWallet;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
import { RequiredParam } from "./required-param";
|
||||
import type { QueryKey } from "@tanstack/react-query";
|
||||
import type { ValidContractInstance } from "@thirdweb-dev/sdk";
|
||||
import type {
|
||||
Network,
|
||||
NFTCollection,
|
||||
NFTDrop,
|
||||
Token,
|
||||
} from "@thirdweb-dev/sdk/solana";
|
||||
|
||||
// we prefix all our query keys with this to avoid possible collisions with user-defined queries that share the same query client
|
||||
const TW_QUERY_KEY_PREFIX = "__tw__";
|
||||
@@ -53,28 +47,3 @@ export function createEVMContractQueryKey<TKey extends QueryKey>(
|
||||
chainId,
|
||||
);
|
||||
}
|
||||
|
||||
// SOL
|
||||
|
||||
export function createSOLQueryKey<TKey extends QueryKey>(key: TKey) {
|
||||
return ensureTWPrefix(["sol", ...key] as const);
|
||||
}
|
||||
|
||||
export function createSOLQueryKeyWithNetwork<TKey extends QueryKey>(
|
||||
key: TKey,
|
||||
network: RequiredParam<Network>,
|
||||
) {
|
||||
return createSOLQueryKey([network, ...key] as const);
|
||||
}
|
||||
|
||||
export function createSOLProgramQueryKey<TKey extends QueryKey>(
|
||||
program: RequiredParam<NFTCollection | NFTDrop | Token>,
|
||||
key: TKey = [] as unknown as TKey,
|
||||
) {
|
||||
const network = program?.network;
|
||||
const address = program?.publicKey.toBase58();
|
||||
return createSOLQueryKeyWithNetwork(
|
||||
["program", address, ...key] as const,
|
||||
network || null,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -43,18 +43,28 @@ export type WalletConfig<I extends WalletInstance = WalletInstance> = {
|
||||
|
||||
/**
|
||||
* If true, this wallet will be tagged as "recommended" in ConnectWallet Modal and will be shown at the top of the list
|
||||
* @default false
|
||||
*/
|
||||
recommended?: boolean;
|
||||
|
||||
/**
|
||||
* If the wallet can sign transactions without user interaction, set this to true.
|
||||
* @default false
|
||||
*/
|
||||
isHeadless?: boolean;
|
||||
};
|
||||
|
||||
export type ConnectUIProps<I extends WalletInstance = WalletInstance> = {
|
||||
/**
|
||||
* close the connect wallet modal
|
||||
* @param reset reset Connect Wallet Modal to initial state, so that if it's opened again, it will start from the wallet-selection screen
|
||||
*
|
||||
* default: `true`
|
||||
* temporarily hide the ConnectModal
|
||||
* This is useful when you want to open another modal and do not want to show the ConnectModal in the background
|
||||
*/
|
||||
close: (reset?: boolean) => void;
|
||||
hide: () => void;
|
||||
|
||||
/**
|
||||
* when the wallet is connected, call this function to indicate that the wallet is connected and it is safe to close the Modal
|
||||
*/
|
||||
connected: () => void;
|
||||
|
||||
/**
|
||||
* indicates whether the connect wallet modal is open or not
|
||||
@@ -62,9 +72,9 @@ export type ConnectUIProps<I extends WalletInstance = WalletInstance> = {
|
||||
isOpen: boolean;
|
||||
|
||||
/**
|
||||
* open the connect wallet modal
|
||||
* show the hidden connect wallet modal again
|
||||
*/
|
||||
open: () => void;
|
||||
show: () => void;
|
||||
|
||||
/**
|
||||
* go back to the wallet selector screen in connect wallet modal
|
||||
|
||||
@@ -1,27 +1,23 @@
|
||||
import type { providers } from "ethers";
|
||||
import {
|
||||
RequiredParam,
|
||||
requiredParamInvariant,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useSDKChainId } from "../useSDK";
|
||||
import {
|
||||
cacheKeys,
|
||||
invalidateContractAndBalances,
|
||||
} from "../../utils/cache-keys";
|
||||
import { cacheKeys } from "../../utils/cache-keys";
|
||||
import { useQueryWithNetwork } from "../query-utils/useQueryWithNetwork";
|
||||
import {
|
||||
useMutation,
|
||||
UseMutationResult,
|
||||
useQueryClient,
|
||||
UseQueryResult,
|
||||
} from "@tanstack/react-query";
|
||||
import type {
|
||||
SignerWithPermissions,
|
||||
PermissionSnapshotInput,
|
||||
SmartContract,
|
||||
SignerPermissionsInput,
|
||||
TransactionResult,
|
||||
} from "@thirdweb-dev/sdk";
|
||||
import invariant from "tiny-invariant";
|
||||
import { WalletAddress } from "../../types";
|
||||
import { useWallet } from "../../../core/hooks/wallet-hooks";
|
||||
|
||||
/** **********************/
|
||||
/** READ HOOKS **/
|
||||
@@ -127,65 +123,180 @@ export function useAccountAdminsAndSigners(
|
||||
/** **********************/
|
||||
/** WRITE HOOKS **/
|
||||
/** **********************/
|
||||
|
||||
export type CreateSessionKeyInput = {
|
||||
keyAddress: string;
|
||||
permissions: SignerPermissionsInput;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the account's entire snapshot of permissions
|
||||
* Create and add a session key for the smart wallet
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* const Component = () => {
|
||||
* const { contract } = useContract("{{contract_address}}");
|
||||
* const {
|
||||
* mutate: setAccountSigners,
|
||||
* mutate: createSessionKey,
|
||||
* isLoading,
|
||||
* error,
|
||||
* } = useSetAccountSigners(contract);
|
||||
* } = useCreateSessionKey();
|
||||
*
|
||||
* if (error) {
|
||||
* console.error("failed to set account signers", error);
|
||||
* console.error("failed to create session key", error);
|
||||
* }
|
||||
*
|
||||
* return (
|
||||
* <button
|
||||
* disabled={isLoading}
|
||||
* onClick={() => setAccountSigners("0x...")}
|
||||
* onClick={() => createSessionKey(
|
||||
* "0x...",
|
||||
* {
|
||||
* approvedCallTargets: ["0x..."], // the addresses of contracts that the session key can call
|
||||
* nativeTokenLimitPerTransaction: 0.1, // the maximum amount of native token (in ETH) that the session key can spend per transaction
|
||||
* startDate: new Date(), // the date when the session key becomes active
|
||||
* expirationDate = new Date(Date.now() + 24 * 60 * 60 * 1000); // the date when the session key expires
|
||||
* }
|
||||
* )}
|
||||
* >
|
||||
* Set Account Signers
|
||||
* Create Session Key
|
||||
* </button>
|
||||
* );
|
||||
* };
|
||||
* ```
|
||||
*
|
||||
* @param contract - an instance of a account contract
|
||||
* @returns a mutation object that can be used to set the account signers
|
||||
* @twfeature Account
|
||||
* @see {@link https://portal.thirdweb.com/react/react.usesetaccountsigners?utm_source=sdk | Documentation}
|
||||
* @beta
|
||||
*/
|
||||
export function useSetAccountSigners(
|
||||
contract: RequiredParam<SmartContract>,
|
||||
): UseMutationResult<
|
||||
{ receipt: providers.TransactionReceipt },
|
||||
export function useCreateSessionKey(): UseMutationResult<
|
||||
TransactionResult,
|
||||
unknown,
|
||||
PermissionSnapshotInput,
|
||||
unknown
|
||||
CreateSessionKeyInput
|
||||
> {
|
||||
const activeChainId = useSDKChainId();
|
||||
const contractAddress = contract?.getAddress();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation(
|
||||
async (permissionsSnapshot: PermissionSnapshotInput) => {
|
||||
requiredParamInvariant(contract, "contract is undefined");
|
||||
|
||||
return contract.account.resetAllPermissions(permissionsSnapshot);
|
||||
},
|
||||
{
|
||||
onSettled: () =>
|
||||
invalidateContractAndBalances(
|
||||
queryClient,
|
||||
contractAddress,
|
||||
activeChainId,
|
||||
),
|
||||
},
|
||||
);
|
||||
const smartWallet = useWallet("smartWallet");
|
||||
return useMutation(async (args: CreateSessionKeyInput) => {
|
||||
requiredParamInvariant(smartWallet, "wallet is not connected");
|
||||
return smartWallet.createSessionKey(args.keyAddress, args.permissions);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Revoke a session key on the smart wallet
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* const Component = () => {
|
||||
* const {
|
||||
* mutate: revokeSessionKey,
|
||||
* isLoading,
|
||||
* error,
|
||||
* } = useRevokeSessionKey();
|
||||
*
|
||||
* if (error) {
|
||||
* console.error("failed to revoke session key", error);
|
||||
* }
|
||||
*
|
||||
* return (
|
||||
* <button
|
||||
* disabled={isLoading}
|
||||
* onClick={() => revokeSessionKey("0x...")}
|
||||
* >
|
||||
* Revoke Session Key
|
||||
* </button>
|
||||
* );
|
||||
* };
|
||||
* ```
|
||||
*
|
||||
* @twfeature Account
|
||||
*/
|
||||
export function useRevokeSessionKey(): UseMutationResult<
|
||||
TransactionResult,
|
||||
unknown,
|
||||
string
|
||||
> {
|
||||
const smartWallet = useWallet("smartWallet");
|
||||
return useMutation(async (keyAddress: string) => {
|
||||
requiredParamInvariant(smartWallet, "wallet is not connected");
|
||||
return smartWallet.revokeSessionKey(keyAddress);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an additional admin on the smart wallet
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* const Component = () => {
|
||||
* const {
|
||||
* mutate: addAdmin,
|
||||
* isLoading,
|
||||
* error,
|
||||
* } = useAddAdmin();
|
||||
*
|
||||
* if (error) {
|
||||
* console.error("failed to add admin", error);
|
||||
* }
|
||||
*
|
||||
* return (
|
||||
* <button
|
||||
* disabled={isLoading}
|
||||
* onClick={() => addAdmin("0x...")}
|
||||
* >
|
||||
* Add admin
|
||||
* </button>
|
||||
* );
|
||||
* };
|
||||
* ```
|
||||
*
|
||||
* @twfeature Account
|
||||
*/
|
||||
export function useAddAdmin(): UseMutationResult<
|
||||
TransactionResult,
|
||||
unknown,
|
||||
string
|
||||
> {
|
||||
const smartWallet = useWallet("smartWallet");
|
||||
return useMutation(async (adminAddress: string) => {
|
||||
requiredParamInvariant(smartWallet, "wallet is not connected");
|
||||
return smartWallet.addAdmin(adminAddress);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an additional admin on the smart wallet
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* const Component = () => {
|
||||
* const {
|
||||
* mutate: removeAdmin,
|
||||
* isLoading,
|
||||
* error,
|
||||
* } = useRemoveAdmin();
|
||||
*
|
||||
* if (error) {
|
||||
* console.error("failed to remove admin", error);
|
||||
* }
|
||||
*
|
||||
* return (
|
||||
* <button
|
||||
* disabled={isLoading}
|
||||
* onClick={() => removeAdmin("0x...")}
|
||||
* >
|
||||
* Remove admin
|
||||
* </button>
|
||||
* );
|
||||
* };
|
||||
* ```
|
||||
*
|
||||
* @twfeature Account
|
||||
*/
|
||||
export function useRemoveAdmin(): UseMutationResult<
|
||||
TransactionResult,
|
||||
unknown,
|
||||
string
|
||||
> {
|
||||
const smartWallet = useWallet("smartWallet");
|
||||
return useMutation(async (adminAddress: string) => {
|
||||
requiredParamInvariant(smartWallet, "wallet is not connected");
|
||||
return smartWallet.removeAdmin(adminAddress);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -225,11 +225,12 @@ export function useTotalCirculatingSupply(
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* const { data: ownedNFTs, isLoading, error } = useOwnedNFTs(contract, "{{wallet_address}}");
|
||||
* const { data: ownedNFTs, isLoading, error } = useOwnedNFTs(contract, "{{wallet_address}}", { start: 0, count: 100 });
|
||||
* ```
|
||||
*
|
||||
* @param contract - an instance of a {@link NFTContract}
|
||||
* @param ownerWalletAddress - the wallet address to get owned tokens for
|
||||
* @param queryParams - query params to pass to the query for pagination
|
||||
* @returns a response object that includes the list of owned tokens
|
||||
* @beta
|
||||
* @twfeature ERC721Enumerable | ERC1155Enumerable | ERC721Supply
|
||||
@@ -238,6 +239,7 @@ export function useTotalCirculatingSupply(
|
||||
export function useOwnedNFTs<TContract extends NFTContract>(
|
||||
contract: RequiredParam<TContract>,
|
||||
ownerWalletAddress: RequiredParam<WalletAddress>,
|
||||
queryParams?: QueryAllParams,
|
||||
) {
|
||||
const contractAddress = contract?.getAddress();
|
||||
const { erc721, erc1155 } = getErcs(contract);
|
||||
@@ -248,10 +250,10 @@ export function useOwnedNFTs<TContract extends NFTContract>(
|
||||
requiredParamInvariant(contract, "No Contract instance provided");
|
||||
invariant(ownerWalletAddress, "No wallet address provided");
|
||||
if (erc721) {
|
||||
return await erc721.getOwned(ownerWalletAddress);
|
||||
return await erc721.getOwned(ownerWalletAddress, queryParams);
|
||||
}
|
||||
if (erc1155) {
|
||||
return await erc1155.getOwned(ownerWalletAddress);
|
||||
return await erc1155.getOwned(ownerWalletAddress, queryParams);
|
||||
}
|
||||
invariant(false, "Unknown NFT type");
|
||||
},
|
||||
|
||||
@@ -205,7 +205,10 @@ export {
|
||||
// account
|
||||
export {
|
||||
useAccountSigners,
|
||||
useSetAccountSigners,
|
||||
useAddAdmin,
|
||||
useRemoveAdmin,
|
||||
useCreateSessionKey,
|
||||
useRevokeSessionKey,
|
||||
useAccountAdmins,
|
||||
useAccountAdminsAndSigners,
|
||||
} from "./hooks/async/account";
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
import { 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;
|
||||
}
|
||||
|
||||
interface ThirdwebAuthContext extends ThirdwebAuthConfig {}
|
||||
|
||||
const ThirdwebAuthContext = /* @__PURE__ */ createContext<
|
||||
ThirdwebAuthContext | undefined
|
||||
>(undefined);
|
||||
|
||||
export const ThirdwebAuthProvider: React.FC<
|
||||
PropsWithChildren<{ value?: ThirdwebAuthConfig }>
|
||||
> = ({ value, children }) => {
|
||||
// Remove trailing slash from URL if present
|
||||
const authContext = useMemo(() => {
|
||||
if (!value) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const context: ThirdwebAuthContext = {
|
||||
...value,
|
||||
authUrl: value.authUrl?.replace(/\/$/, ""),
|
||||
};
|
||||
|
||||
return context;
|
||||
}, [value]);
|
||||
return (
|
||||
<ThirdwebAuthContext.Provider value={authContext}>
|
||||
{children}
|
||||
</ThirdwebAuthContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export function useThirdwebAuthContext() {
|
||||
return useContext(ThirdwebAuthContext);
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
export { useLogin } from "./useLogin";
|
||||
export type { LoginConfig } from "./useLogin";
|
||||
|
||||
export { useLogout } from "./useLogout";
|
||||
|
||||
export type { UserWithData } from "./useUser";
|
||||
export { useUser } from "./useUser";
|
||||
@@ -1,204 +0,0 @@
|
||||
import { ensureTWPrefix } from "../../../core/query-utils/query-key";
|
||||
import { useThirdwebAuthContext } from "../../contexts/thirdweb-auth";
|
||||
import { useSDK } from "../../providers/base";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import type {
|
||||
LoginOptions,
|
||||
LoginPayload,
|
||||
LoginPayloadData,
|
||||
} from "@thirdweb-dev/auth";
|
||||
import { GenericAuthWallet } from "@thirdweb-dev/wallets";
|
||||
import { SignerWallet } from "@thirdweb-dev/wallets/solana/wallets/signer";
|
||||
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() {
|
||||
const queryClient = useQueryClient();
|
||||
const authConfig = useThirdwebAuthContext();
|
||||
const signer = useSDK()?.wallet.getSigner();
|
||||
|
||||
const login = useMutation({
|
||||
mutationFn: async () => {
|
||||
invariant(
|
||||
authConfig,
|
||||
"Please specify an authConfig in the ThirdwebProvider",
|
||||
);
|
||||
invariant(signer, "You need a connected wallet to login.");
|
||||
invariant(
|
||||
authConfig.authUrl,
|
||||
"Please specify an authUrl in the authConfig.",
|
||||
);
|
||||
const wallet = new SignerWallet(signer);
|
||||
const address = await wallet.getAddress();
|
||||
let res = await fetch(`${authConfig.authUrl}/payload`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ address }),
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error(`Failed to get payload with status code ${res.status}`);
|
||||
}
|
||||
|
||||
let payloadData: LoginPayloadData;
|
||||
try {
|
||||
({ payload: payloadData } = await res.json());
|
||||
} catch {
|
||||
throw new Error(`Failed to get payload`);
|
||||
}
|
||||
|
||||
const payload = await doLoginWithPayload(wallet, payloadData);
|
||||
res = await fetch(`${authConfig.authUrl}/login`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ payload }),
|
||||
credentials: "include",
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
const data = await res.json();
|
||||
if (data.error) {
|
||||
throw new Error(data.error);
|
||||
}
|
||||
|
||||
throw new Error(`Login request failed with status code ${res.status}`);
|
||||
}
|
||||
|
||||
queryClient.invalidateQueries(ensureTWPrefix(["user"]));
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
login: () => login.mutateAsync(),
|
||||
isLoading: login.isLoading,
|
||||
};
|
||||
}
|
||||
|
||||
// login function extracted directly from auth
|
||||
const isBrowser = () => typeof window !== "undefined";
|
||||
|
||||
export async function doLoginWithPayload(
|
||||
wallet: GenericAuthWallet,
|
||||
payload: LoginPayloadData,
|
||||
): Promise<LoginPayload> {
|
||||
const message = generateMessage(payload);
|
||||
const signature = await wallet.signMessage(message);
|
||||
|
||||
return {
|
||||
payload,
|
||||
signature,
|
||||
};
|
||||
}
|
||||
|
||||
export async function doLogin(
|
||||
wallet: GenericAuthWallet,
|
||||
options?: LoginOptions,
|
||||
): Promise<LoginPayload> {
|
||||
let chainId: string | undefined = options?.chainId;
|
||||
if (!chainId && wallet.getChainId) {
|
||||
try {
|
||||
chainId = (await wallet.getChainId()).toString();
|
||||
} catch {
|
||||
// ignore error
|
||||
}
|
||||
}
|
||||
|
||||
invariant(options?.domain, "Please specify a domain to login with.");
|
||||
// generate a pseudo-random nonce if none is provided
|
||||
const nonce =
|
||||
options?.nonce || Math.floor(Math.random() * 1000000000).toString();
|
||||
|
||||
const payloadData: LoginPayloadData = {
|
||||
type: wallet.type,
|
||||
domain: options.domain,
|
||||
address: await wallet.getAddress(),
|
||||
statement:
|
||||
options?.statement ||
|
||||
"Please ensure that the domain above matches the URL of the current website.",
|
||||
version: options?.version || "1",
|
||||
uri: options?.uri || (isBrowser() ? window.location.origin : undefined),
|
||||
chain_id: chainId,
|
||||
nonce: options?.nonce || nonce,
|
||||
issued_at: new Date().toISOString(),
|
||||
expiration_time: new Date(
|
||||
options?.expirationTime || Date.now() + 1000 * 60 * 5,
|
||||
).toISOString(),
|
||||
invalid_before: new Date(
|
||||
options?.invalidBefore || Date.now(),
|
||||
).toISOString(),
|
||||
resources: options?.resources,
|
||||
};
|
||||
|
||||
return doLoginWithPayload(wallet, payloadData);
|
||||
}
|
||||
|
||||
// generate straight from auth
|
||||
function generateMessage(payload: LoginPayloadData): string {
|
||||
const typeField = payload.type === "evm" ? "Ethereum" : "Solana";
|
||||
const header = `${payload.domain} wants you to sign in with your ${typeField} account:`;
|
||||
let prefix = [header, payload.address].join("\n");
|
||||
prefix = [prefix, payload.statement].join("\n\n");
|
||||
if (payload.statement) {
|
||||
prefix += "\n";
|
||||
}
|
||||
|
||||
const suffixArray = [];
|
||||
if (payload.uri) {
|
||||
const uriField = `URI: ${payload.uri}`;
|
||||
suffixArray.push(uriField);
|
||||
}
|
||||
|
||||
const versionField = `Version: ${payload.version}`;
|
||||
suffixArray.push(versionField);
|
||||
|
||||
if (payload.chain_id) {
|
||||
const chainField = `Chain ID: ` + payload.chain_id || "1";
|
||||
suffixArray.push(chainField);
|
||||
}
|
||||
|
||||
const nonceField = `Nonce: ${payload.nonce}`;
|
||||
suffixArray.push(nonceField);
|
||||
|
||||
const issuedAtField = `Issued At: ${payload.issued_at}`;
|
||||
suffixArray.push(issuedAtField);
|
||||
|
||||
const expiryField = `Expiration Time: ${payload.expiration_time}`;
|
||||
suffixArray.push(expiryField);
|
||||
|
||||
if (payload.invalid_before) {
|
||||
const invalidBeforeField = `Not Before: ${payload.invalid_before}`;
|
||||
suffixArray.push(invalidBeforeField);
|
||||
}
|
||||
|
||||
if (payload.resources) {
|
||||
suffixArray.push(
|
||||
[`Resources:`, ...payload.resources.map((x) => `- ${x}`)].join("\n"),
|
||||
);
|
||||
}
|
||||
|
||||
const suffix = suffixArray.join("\n");
|
||||
return [prefix, suffix].join("\n");
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
import { ensureTWPrefix } from "../../../core/query-utils/query-key";
|
||||
import { useThirdwebAuthContext } from "../../contexts/thirdweb-auth";
|
||||
import { useMutation, 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 = useThirdwebAuthContext();
|
||||
|
||||
const logout = useMutation({
|
||||
mutationFn: async () => {
|
||||
invariant(
|
||||
authConfig,
|
||||
"Please specify an authConfig in the ThirdwebProvider",
|
||||
);
|
||||
invariant(
|
||||
authConfig.authUrl,
|
||||
"Please specify an authUrl in the authConfig.",
|
||||
);
|
||||
|
||||
await fetch(`${authConfig.authUrl}/logout`, {
|
||||
method: "POST",
|
||||
});
|
||||
|
||||
queryClient.invalidateQueries(ensureTWPrefix(["user"]));
|
||||
},
|
||||
});
|
||||
|
||||
return { logout: logout.mutateAsync, isLoading: logout.isLoading };
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
import { ensureTWPrefix } from "../../../core/query-utils/query-key";
|
||||
import { useThirdwebAuthContext } from "../../contexts/thirdweb-auth";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import type { Json, User } from "@thirdweb-dev/auth";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
export interface UserWithData<
|
||||
TData extends Json = Json,
|
||||
TContext extends Json = Json,
|
||||
> extends User<TContext> {
|
||||
data?: TData;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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<
|
||||
TData extends Json = Json,
|
||||
TContext extends Json = Json,
|
||||
>() {
|
||||
const authConfig = useThirdwebAuthContext();
|
||||
|
||||
const { data: user, isLoading } = useQuery(
|
||||
ensureTWPrefix(["user"]),
|
||||
async () => {
|
||||
invariant(
|
||||
authConfig,
|
||||
"Please specify an authConfig in the ThirdwebProvider",
|
||||
);
|
||||
invariant(
|
||||
authConfig.authUrl,
|
||||
"Please specify an authUrl in the authConfig.",
|
||||
);
|
||||
|
||||
// We include credentials, so we can getUser even if API is on different URL
|
||||
const res = await fetch(`${authConfig.authUrl}/user`, {
|
||||
credentials: "include",
|
||||
});
|
||||
|
||||
return (await res.json()) as UserWithData<TData, TContext>;
|
||||
},
|
||||
{
|
||||
enabled: !!authConfig,
|
||||
},
|
||||
);
|
||||
|
||||
return { user, isLoggedIn: !!user, isLoading };
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
import { createSOLProgramQueryKey } from "../../../../core/query-utils/query-key";
|
||||
import { RequiredParam } from "../../../../core/query-utils/required-param";
|
||||
import { MintNFTParams } from "../../../types";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
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: mintNFT, isLoading, error } = useMintNFT(program);
|
||||
*
|
||||
* return (
|
||||
* <button onClick={() => mintNFT({ metadata: { name: "First NFT" } })}>
|
||||
* Mint
|
||||
* </button>
|
||||
* )
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function useMintNFT(program: RequiredParam<NFTCollection>) {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation(
|
||||
async (data: MintNFTParams) => {
|
||||
invariant(program, "program is required");
|
||||
if (!data.to) {
|
||||
return await program.mint(data.metadata);
|
||||
}
|
||||
return await program.mintTo(data.to, data.metadata);
|
||||
},
|
||||
{
|
||||
onSettled: () =>
|
||||
queryClient.invalidateQueries(createSOLProgramQueryKey(program)),
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
import { createSOLProgramQueryKey } from "../../../../core/query-utils/query-key";
|
||||
import {
|
||||
requiredParamInvariant,
|
||||
RequiredParam,
|
||||
} from "../../../../core/query-utils/required-param";
|
||||
import { MintNFTSupplyParams } from "../../../types";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import type { NFTCollection } from "@thirdweb-dev/sdk/solana";
|
||||
|
||||
/**
|
||||
* Mint additional supply for an NFT on your NFT program
|
||||
* @param program - The NFT program to mint additional NFTs to
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* import { useProgram, useMintNFTSupply } from "@thirdweb-dev/react/solana";
|
||||
*
|
||||
* export default function Component() {
|
||||
* const { program } = useProgram("{{program_address}}");
|
||||
* const { mutateAsync: mintSupply, isLoading, error } = useMintNFTSupply(program);
|
||||
*
|
||||
* return (
|
||||
* <button onClick={() => mintSupply({ nftAddress: "111...", amount: 10 })}>
|
||||
* Mint Additional Supply
|
||||
* </button>
|
||||
* )
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function useMintNFTSupply(program: RequiredParam<NFTCollection>) {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation(
|
||||
async (data: MintNFTSupplyParams) => {
|
||||
requiredParamInvariant(program, "program is required");
|
||||
if (!data.to) {
|
||||
return await program.mintAdditionalSupply(data.nftAddress, data.amount);
|
||||
}
|
||||
return await program.mintAdditionalSupplyTo(
|
||||
data.to,
|
||||
data.nftAddress,
|
||||
data.amount,
|
||||
);
|
||||
},
|
||||
{
|
||||
onSettled: () =>
|
||||
queryClient.invalidateQueries(createSOLProgramQueryKey(program)),
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
import { createSOLProgramQueryKey } from "../../../../core/query-utils/query-key";
|
||||
import { RequiredParam } from "../../../../core/query-utils/required-param";
|
||||
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,45 +0,0 @@
|
||||
import { createSOLProgramQueryKey } from "../../../../core/query-utils/query-key";
|
||||
import { RequiredParam } from "../../../../core/query-utils/required-param";
|
||||
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 (data: ClaimNFTParams) => {
|
||||
invariant(program, "program is required");
|
||||
if (!data.to) {
|
||||
return await program.claim(data.amount);
|
||||
}
|
||||
return await program.claimTo(data.to, data.amount);
|
||||
},
|
||||
{
|
||||
onSettled: () =>
|
||||
queryClient.invalidateQueries(createSOLProgramQueryKey(program)),
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
import { createSOLProgramQueryKey } from "../../../../core/query-utils/query-key";
|
||||
import {
|
||||
requiredParamInvariant,
|
||||
RequiredParam,
|
||||
} from "../../../../core/query-utils/required-param";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import type { NFTDrop } from "@thirdweb-dev/sdk/solana";
|
||||
|
||||
export function dropTotalClaimedSupplyQuery(program: RequiredParam<NFTDrop>) {
|
||||
return {
|
||||
queryKey: createSOLProgramQueryKey(program, [
|
||||
"totalClaimedSupply",
|
||||
] as const),
|
||||
|
||||
queryFn: async () => {
|
||||
requiredParamInvariant(program, "program is required");
|
||||
|
||||
return await program.totalClaimedSupply();
|
||||
},
|
||||
enabled: !!program,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 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));
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
import { createSOLProgramQueryKey } from "../../../../core/query-utils/query-key";
|
||||
import {
|
||||
requiredParamInvariant,
|
||||
RequiredParam,
|
||||
} from "../../../../core/query-utils/required-param";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import { NFTMetadataInput, UploadProgressEvent } from "@thirdweb-dev/sdk";
|
||||
import type { NFTDrop } from "@thirdweb-dev/sdk/solana";
|
||||
|
||||
/**
|
||||
* 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[] }) => {
|
||||
requiredParamInvariant(program, "program is required");
|
||||
let options;
|
||||
if (onProgress) {
|
||||
options = {
|
||||
onProgress,
|
||||
};
|
||||
}
|
||||
return await program.lazyMint(data.metadatas, options);
|
||||
},
|
||||
{
|
||||
onSettled: () =>
|
||||
queryClient.invalidateQueries(createSOLProgramQueryKey(program)),
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
import { createSOLProgramQueryKey } from "../../../../core/query-utils/query-key";
|
||||
import { RequiredParam } from "../../../../core/query-utils/required-param";
|
||||
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)),
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
import { createSOLProgramQueryKey } from "../../../../core/query-utils/query-key";
|
||||
import {
|
||||
requiredParamInvariant,
|
||||
RequiredParam,
|
||||
} from "../../../../core/query-utils/required-param";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import type { NFTDrop } from "@thirdweb-dev/sdk/solana";
|
||||
|
||||
export function dropUnclaimedSupplyQuery(program: RequiredParam<NFTDrop>) {
|
||||
return {
|
||||
queryKey: createSOLProgramQueryKey(program, [
|
||||
"totalUnclaimedSupply",
|
||||
] as const),
|
||||
|
||||
queryFn: async () => {
|
||||
requiredParamInvariant(program, "program is required");
|
||||
|
||||
return await program.totalUnclaimedSupply();
|
||||
},
|
||||
enabled: !!program,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 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));
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
import { createSOLProgramQueryKey } from "../../../core/query-utils/query-key";
|
||||
import {
|
||||
requiredParamInvariant,
|
||||
RequiredParam,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import type { NFTCollection, NFTDrop } from "@thirdweb-dev/sdk/solana";
|
||||
|
||||
/**
|
||||
* 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) => {
|
||||
requiredParamInvariant(program, "program is required");
|
||||
return await program.burn(nftAddress);
|
||||
},
|
||||
{
|
||||
onSettled: () =>
|
||||
queryClient.invalidateQueries(createSOLProgramQueryKey(program)),
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
import { createSOLProgramQueryKey } from "../../../core/query-utils/query-key";
|
||||
import {
|
||||
requiredParamInvariant,
|
||||
RequiredParam,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { NFTCollection, NFTDrop } from "@thirdweb-dev/sdk/solana";
|
||||
|
||||
export function nftCreatorsQuery(
|
||||
program: RequiredParam<NFTCollection | NFTDrop>,
|
||||
) {
|
||||
return {
|
||||
queryKey: createSOLProgramQueryKey(program, ["creators"] as const),
|
||||
|
||||
queryFn: async () => {
|
||||
requiredParamInvariant(program, "program is required");
|
||||
return await program.getCreators();
|
||||
},
|
||||
enabled: !!program,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the creators for an NFT program
|
||||
* @param program - The NFT program to get the creators for
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* import { useProgram, useCreators } from "@thirdweb-dev/react/solana";
|
||||
*
|
||||
* export default function Component() {
|
||||
* const { program } = useProgram("{{program_address}}");
|
||||
* const { data: creators, isLoading } = useCreators(program);
|
||||
*
|
||||
* return (
|
||||
* <pre>{JSON.stringify(creators)}</pre>
|
||||
* )
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function useCreators(program: RequiredParam<NFTCollection | NFTDrop>) {
|
||||
return useQuery(nftCreatorsQuery(program));
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
import { createSOLProgramQueryKey } from "../../../core/query-utils/query-key";
|
||||
import {
|
||||
requiredParamInvariant,
|
||||
RequiredParam,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import type { NFTCollection, NFTDrop } from "@thirdweb-dev/sdk/solana";
|
||||
|
||||
export function nftGetOneQuery(
|
||||
program: RequiredParam<NFTCollection | NFTDrop>,
|
||||
tokenAddress: RequiredParam<string>,
|
||||
) {
|
||||
return {
|
||||
queryKey: createSOLProgramQueryKey(program, [
|
||||
"get",
|
||||
{ tokenAddress },
|
||||
] as const),
|
||||
|
||||
queryFn: async () => {
|
||||
requiredParamInvariant(program, "program is required");
|
||||
requiredParamInvariant(tokenAddress, "tokenAddress is required");
|
||||
return await program.get(tokenAddress);
|
||||
},
|
||||
enabled: !!program && !!tokenAddress,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the metadata for a minted NFT
|
||||
* @param program - The NFT program to get NFT metadata from
|
||||
* @param tokenAddress - 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>,
|
||||
) {
|
||||
return useQuery(nftGetOneQuery(program, tokenAddress));
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
import { createSOLProgramQueryKey } from "../../../core/query-utils/query-key";
|
||||
import {
|
||||
requiredParamInvariant,
|
||||
RequiredParam,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { QueryAllParams } from "@thirdweb-dev/sdk";
|
||||
import type { NFTCollection, NFTDrop } from "@thirdweb-dev/sdk/solana";
|
||||
|
||||
export function nftGetAllQuery(
|
||||
program: RequiredParam<NFTCollection | NFTDrop>,
|
||||
queryParams?: QueryAllParams,
|
||||
) {
|
||||
return {
|
||||
queryKey: createSOLProgramQueryKey(program, [
|
||||
"getAll",
|
||||
queryParams,
|
||||
] as const),
|
||||
|
||||
queryFn: async () => {
|
||||
requiredParamInvariant(program, "program is required");
|
||||
return program.getAll(queryParams);
|
||||
},
|
||||
enabled: !!program,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 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>,
|
||||
queryParams?: QueryAllParams,
|
||||
) {
|
||||
return useQuery(nftGetAllQuery(program, queryParams));
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
import { createSOLProgramQueryKey } from "../../../core/query-utils/query-key";
|
||||
import {
|
||||
requiredParamInvariant,
|
||||
RequiredParam,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { NFTCollection, NFTDrop } from "@thirdweb-dev/sdk/solana";
|
||||
|
||||
export function nftRoyaltyQuery(
|
||||
program: RequiredParam<NFTCollection | NFTDrop>,
|
||||
) {
|
||||
return {
|
||||
queryKey: createSOLProgramQueryKey(program, ["royalty"] as const),
|
||||
|
||||
queryFn: async () => {
|
||||
requiredParamInvariant(program, "program is required");
|
||||
return await program.getRoyalty();
|
||||
},
|
||||
enabled: !!program,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the royalty for an NFT program
|
||||
* @param program - The NFT program to get the royalty for
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* import { useProgram, useRoyalty } from "@thirdweb-dev/react/solana";
|
||||
*
|
||||
* export default function Component() {
|
||||
* const { program } = useProgram("{{program_address}}");
|
||||
* const { data: royalty, isLoading } = useRoyaltySettings(program);
|
||||
*
|
||||
* return (
|
||||
* <p>{royalty}</p>
|
||||
* )
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function useRoyaltySettings(
|
||||
program: RequiredParam<NFTCollection | NFTDrop>,
|
||||
) {
|
||||
return useQuery(nftRoyaltyQuery(program));
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
import { createSOLProgramQueryKey } from "../../../core/query-utils/query-key";
|
||||
import {
|
||||
requiredParamInvariant,
|
||||
RequiredParam,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import type { NFTCollection, NFTDrop } from "@thirdweb-dev/sdk/solana";
|
||||
|
||||
export function nftTotalSupplyQuery(
|
||||
program: RequiredParam<NFTCollection | NFTDrop>,
|
||||
) {
|
||||
return {
|
||||
queryKey: createSOLProgramQueryKey(program, ["supply"] as const),
|
||||
|
||||
queryFn: async () => {
|
||||
requiredParamInvariant(program, "program is required");
|
||||
return program.totalSupply();
|
||||
},
|
||||
enabled: !!program,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the total supply of NFTs on the program
|
||||
* @param program - The NFT program to get the total supply of
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* import { useProgram, useTotalSupply } from "@thirdweb-dev/react/solana";
|
||||
*
|
||||
* export default function Component() {
|
||||
* const { program } = useProgram("{{program_address}}");
|
||||
* const { data: supply, isLoading } = useTotalSupply(program);
|
||||
*
|
||||
* return (
|
||||
* <pre>{JSON.stringify(supply)}</pre>
|
||||
* )
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function useTotalSupply(
|
||||
program: RequiredParam<NFTCollection | NFTDrop>,
|
||||
) {
|
||||
return useQuery(nftTotalSupplyQuery(program));
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
import { createSOLProgramQueryKey } from "../../../core/query-utils/query-key";
|
||||
import {
|
||||
requiredParamInvariant,
|
||||
RequiredParam,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import type { NFTCollection, NFTDrop } from "@thirdweb-dev/sdk/solana";
|
||||
|
||||
export type TransferNFTMutationParams = {
|
||||
receiverAddress: string;
|
||||
tokenAddress: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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) => {
|
||||
requiredParamInvariant(program, "program is required");
|
||||
return await program.transfer(receiverAddress, tokenAddress);
|
||||
},
|
||||
{
|
||||
onSettled: () =>
|
||||
queryClient.invalidateQueries(createSOLProgramQueryKey(program)),
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
import { createSOLProgramQueryKey } from "../../../core/query-utils/query-key";
|
||||
import {
|
||||
requiredParamInvariant,
|
||||
RequiredParam,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import type {
|
||||
NFTCollection,
|
||||
NFTDrop,
|
||||
UpdateCreatorInput,
|
||||
} from "@thirdweb-dev/sdk/solana";
|
||||
|
||||
/**
|
||||
* Update the creators for an NFT program
|
||||
* @param program - The NFT program instance to update the creators for
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* import { useProgram, useUpdateCreators } from "@thirdweb-dev/react/solana";
|
||||
*
|
||||
* export default function Component() {
|
||||
* const { program } = useProgram("{{program_address}}");
|
||||
* const { mutateAsync: updateCreators, isLoading, error } = useUpdateCreators(program);
|
||||
*
|
||||
* return (
|
||||
* <button
|
||||
* onClick={() => updateCreators([{ address: "0x...", share: 10 }])}
|
||||
* >
|
||||
* Update Creators
|
||||
* </button>
|
||||
* )
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function useUpdateCreators(
|
||||
program: RequiredParam<NFTCollection | NFTDrop>,
|
||||
) {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation(
|
||||
async ({ creators, updateAll }: UpdateCreatorInput) => {
|
||||
requiredParamInvariant(program, "program is required");
|
||||
return await program.updateCreators(creators, updateAll);
|
||||
},
|
||||
{
|
||||
onSettled: () =>
|
||||
queryClient.invalidateQueries(createSOLProgramQueryKey(program)),
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
import { createSOLProgramQueryKey } from "../../../core/query-utils/query-key";
|
||||
import {
|
||||
requiredParamInvariant,
|
||||
RequiredParam,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import type {
|
||||
NFTCollection,
|
||||
NFTDrop,
|
||||
UpdateRoyaltySettingsInput,
|
||||
} from "@thirdweb-dev/sdk/solana";
|
||||
|
||||
/**
|
||||
* Update the royalty for an NFT program
|
||||
* @param program - The NFT program instance to update the royalty for
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* import { useProgram, useUpdateRoyaltySettings } from "@thirdweb-dev/react/solana";
|
||||
*
|
||||
* export default function Component() {
|
||||
* const { program } = useProgram("{{program_address}}");
|
||||
* const { mutateAsync: updateRoyalties, isLoading, error } = useUpdateRoyaltySettings(program);
|
||||
*
|
||||
* return (
|
||||
* <button
|
||||
* onClick={() => updateRoyalties(300)}
|
||||
* >
|
||||
* Update Royalties
|
||||
* </button>
|
||||
* )
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function useUpdateRoyaltySettings(
|
||||
program: RequiredParam<NFTCollection | NFTDrop>,
|
||||
) {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation(
|
||||
async ({ sellerFeeBasisPoints, updateAll }: UpdateRoyaltySettingsInput) => {
|
||||
requiredParamInvariant(program, "program is required");
|
||||
return await program.updateRoyalty(sellerFeeBasisPoints, updateAll);
|
||||
},
|
||||
{
|
||||
onSettled: () =>
|
||||
queryClient.invalidateQueries(createSOLProgramQueryKey(program)),
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
import {
|
||||
createSOLQueryKeyWithNetwork,
|
||||
neverPersist,
|
||||
} from "../../../core/query-utils/query-key";
|
||||
import {
|
||||
requiredParamInvariant,
|
||||
RequiredParam,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useSDK } from "../../providers/base";
|
||||
import { programAccountTypeQuery } from "./useProgramAccountType";
|
||||
import {
|
||||
QueryClient,
|
||||
useQuery,
|
||||
useQueryClient,
|
||||
UseQueryResult,
|
||||
} from "@tanstack/react-query";
|
||||
import type {
|
||||
NFTCollection,
|
||||
NFTDrop,
|
||||
ThirdwebSDK,
|
||||
Token,
|
||||
} from "@thirdweb-dev/sdk/solana";
|
||||
|
||||
type ProgramMap = Readonly<{
|
||||
"nft-collection": NFTCollection;
|
||||
"nft-drop": NFTDrop;
|
||||
token: Token;
|
||||
}>;
|
||||
|
||||
type ProgramType = keyof ProgramMap;
|
||||
|
||||
export function programQuery<TProgramType extends ProgramType>(
|
||||
queryClient: QueryClient,
|
||||
sdk: RequiredParam<ThirdwebSDK>,
|
||||
address: RequiredParam<string>,
|
||||
type?: TProgramType,
|
||||
) {
|
||||
const network = sdk?.network;
|
||||
return {
|
||||
queryKey: neverPersist(
|
||||
createSOLQueryKeyWithNetwork(
|
||||
["program-instance", { address, type }] as const,
|
||||
network || null,
|
||||
),
|
||||
),
|
||||
queryFn: (async () => {
|
||||
requiredParamInvariant(sdk, "sdk is required");
|
||||
requiredParamInvariant(address, "Address is required");
|
||||
|
||||
// if the type is not passed in explicitly then we'll try to resolve it
|
||||
if (!type) {
|
||||
// why do we call `fetchQuery` here instead of calling the sdk directly?
|
||||
// while we can never persist the program itself to the cache we can persist the type!
|
||||
// (and this will be triggered by fetching the query on the queryClient)
|
||||
type = await queryClient.fetchQuery(
|
||||
programAccountTypeQuery(sdk, address),
|
||||
);
|
||||
}
|
||||
switch (type) {
|
||||
case "nft-collection":
|
||||
return await sdk.getNFTCollection(address);
|
||||
case "nft-drop":
|
||||
return await sdk.getNFTDrop(address);
|
||||
case "token":
|
||||
return await sdk.getToken(address);
|
||||
default:
|
||||
throw new Error("Unknown account type");
|
||||
}
|
||||
// this is the magic that makes the type inference work
|
||||
}) as () => Promise<ProgramMap[TProgramType]>,
|
||||
enabled: !!sdk && !!network && !!address,
|
||||
// this cannot change as it is unique by address & network
|
||||
cacheTime: Infinity,
|
||||
staleTime: Infinity,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
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>;
|
||||
@@ -1,39 +0,0 @@
|
||||
import { createSOLQueryKeyWithNetwork } from "../../../core/query-utils/query-key";
|
||||
import {
|
||||
requiredParamInvariant,
|
||||
RequiredParam,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useSDK } from "../../providers/base";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import type { ThirdwebSDK } from "@thirdweb-dev/sdk/solana";
|
||||
|
||||
export function programAccountTypeQuery(
|
||||
sdk: RequiredParam<ThirdwebSDK>,
|
||||
address: RequiredParam<string>,
|
||||
) {
|
||||
const network = sdk?.network;
|
||||
return {
|
||||
queryKey: createSOLQueryKeyWithNetwork(
|
||||
["program", address, "type"] as const,
|
||||
network || null,
|
||||
),
|
||||
queryFn: async () => {
|
||||
requiredParamInvariant(sdk, "sdk is required");
|
||||
requiredParamInvariant(address, "Address is required");
|
||||
|
||||
return await sdk.registry.getProgramType(address);
|
||||
},
|
||||
enabled: !!sdk && !!network && !!address,
|
||||
// this cannot change as it is unique by address & network
|
||||
cacheTime: Infinity,
|
||||
staleTime: Infinity,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export function useProgramAccountType(address: RequiredParam<string>) {
|
||||
const sdk = useSDK();
|
||||
return useQuery(programAccountTypeQuery(sdk, address));
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
import { createSOLProgramQueryKey } from "../../../core/query-utils/query-key";
|
||||
import { RequiredParam } from "../../../core/query-utils/required-param";
|
||||
import { UseProgramResult } from "./useProgram";
|
||||
import { useQuery, UseQueryResult } from "@tanstack/react-query";
|
||||
import { NFTMetadata } from "@thirdweb-dev/sdk";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
export function programMetadataQuery(
|
||||
program: RequiredParam<UseProgramResult["program"]>,
|
||||
): {
|
||||
queryKey: ReturnType<typeof createSOLProgramQueryKey>;
|
||||
queryFn(): Promise<NFTMetadata>;
|
||||
enabled: boolean;
|
||||
} {
|
||||
return {
|
||||
queryKey: createSOLProgramQueryKey(program || null, ["metadata"] as const),
|
||||
queryFn: async () => {
|
||||
invariant(program, "sdk is required");
|
||||
|
||||
return (await program.getMetadata()) as NFTMetadata;
|
||||
},
|
||||
enabled: !!program,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export function useProgramMetadata(
|
||||
program: RequiredParam<UseProgramResult["data"]>,
|
||||
): UseQueryResult<NFTMetadata> {
|
||||
return useQuery(programMetadataQuery(program));
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
import { createSOLProgramQueryKey } from "../../../core/query-utils/query-key";
|
||||
import {
|
||||
requiredParamInvariant,
|
||||
RequiredParam,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import type { TokenParams } from "../../../evm";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import type { Token } from "@thirdweb-dev/sdk/solana";
|
||||
|
||||
/**
|
||||
* 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(
|
||||
async (params: TokenParams) => {
|
||||
requiredParamInvariant(program, "program is required");
|
||||
// TODO switch this to use mintTo once that is exposed
|
||||
return await program.mint(params.amount);
|
||||
},
|
||||
{
|
||||
onSettled: () =>
|
||||
queryClient.invalidateQueries(createSOLProgramQueryKey(program)),
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
import { createSOLProgramQueryKey } from "../../../core/query-utils/query-key";
|
||||
import {
|
||||
requiredParamInvariant,
|
||||
RequiredParam,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { Token } from "@thirdweb-dev/sdk/solana";
|
||||
|
||||
export function tokenBalanceQuery(
|
||||
program: RequiredParam<Token>,
|
||||
walletAddress: RequiredParam<string>,
|
||||
) {
|
||||
return {
|
||||
queryKey: createSOLProgramQueryKey(program, [
|
||||
"balanceOf",
|
||||
{ walletAddress },
|
||||
] as const),
|
||||
queryFn: async () => {
|
||||
requiredParamInvariant(program, "program is required");
|
||||
requiredParamInvariant(walletAddress, "Wallet address is required");
|
||||
return await program.balanceOf(walletAddress);
|
||||
},
|
||||
enabled: !!program && !!walletAddress,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 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>,
|
||||
) {
|
||||
return useQuery(tokenBalanceQuery(program, walletAddress));
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
import { createSOLProgramQueryKey } from "../../../core/query-utils/query-key";
|
||||
import { RequiredParam } from "../../../core/query-utils/required-param";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { Token } from "@thirdweb-dev/sdk/solana";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
export function tokenSupplyQuery(program: RequiredParam<Token>) {
|
||||
return {
|
||||
queryKey: createSOLProgramQueryKey(program, ["totalSupply"] as const),
|
||||
queryFn: async () => {
|
||||
invariant(program, "program is required");
|
||||
|
||||
return await program.totalSupply();
|
||||
},
|
||||
enabled: !!program,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 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));
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
import { createSOLProgramQueryKey } from "../../../core/query-utils/query-key";
|
||||
import {
|
||||
requiredParamInvariant,
|
||||
RequiredParam,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import type { Amount } from "@thirdweb-dev/sdk";
|
||||
import type { Token } from "@thirdweb-dev/sdk/solana";
|
||||
|
||||
export type TransferTokenMutationParams = {
|
||||
amount: Amount;
|
||||
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(
|
||||
async ({ amount, receiverAddress }: TransferTokenMutationParams) => {
|
||||
requiredParamInvariant(program, "program is required");
|
||||
return await program.transfer(receiverAddress, amount);
|
||||
},
|
||||
{
|
||||
onSettled: () =>
|
||||
queryClient.invalidateQueries(createSOLProgramQueryKey(program)),
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
import { createSOLQueryKeyWithNetwork } from "../../../core/query-utils/query-key";
|
||||
import { RequiredParam } from "../../../core/query-utils/required-param";
|
||||
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 balance of the connected wallet
|
||||
*/
|
||||
export function useBalance() {
|
||||
const sdk = useSDK();
|
||||
return useQuery(balanceQuery(sdk));
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
// Providers
|
||||
export { ThirdwebSDKProvider, useSDK } from "./providers/base";
|
||||
|
||||
/**
|
||||
* Hooks
|
||||
*/
|
||||
// Program
|
||||
export { programQuery, useProgram } from "./hooks/program/useProgram";
|
||||
export type { UseProgramResult } from "./hooks/program/useProgram";
|
||||
|
||||
export {
|
||||
programMetadataQuery,
|
||||
useProgramMetadata,
|
||||
} from "./hooks/program/useProgramMetadata";
|
||||
|
||||
export {
|
||||
programAccountTypeQuery,
|
||||
useProgramAccountType,
|
||||
} from "./hooks/program/useProgramAccountType";
|
||||
|
||||
// NFT Shared
|
||||
export { nftGetAllQuery, useNFTs } from "./hooks/nft/useNFTs";
|
||||
export { useTransferNFT } from "./hooks/nft/useTransferNFT";
|
||||
export type { TransferNFTMutationParams } from "./hooks/nft/useTransferNFT";
|
||||
|
||||
export { useBurnNFT } from "./hooks/nft/useBurnNFT";
|
||||
export {
|
||||
nftRoyaltyQuery,
|
||||
useRoyaltySettings,
|
||||
} from "./hooks/nft/useRoyaltySettings";
|
||||
export { useUpdateRoyaltySettings } from "./hooks/nft/useUpdateRoyaltySettings";
|
||||
export { nftCreatorsQuery, useCreators } from "./hooks/nft/useCreators";
|
||||
export { useUpdateCreators } from "./hooks/nft/useUpdateCreators";
|
||||
export {
|
||||
nftTotalSupplyQuery,
|
||||
useTotalSupply,
|
||||
} from "./hooks/nft/useTotalSupply";
|
||||
|
||||
// NFT Collection
|
||||
export { useMintNFT } from "./hooks/nft/collection/useMintNFT";
|
||||
export { useMintNFTSupply } from "./hooks/nft/collection/useMintNFTSupply";
|
||||
|
||||
// NFT Drop
|
||||
export { useLazyMint } from "./hooks/nft/drop/useLazyMint";
|
||||
export {
|
||||
dropTotalClaimedSupplyQuery,
|
||||
useDropTotalClaimedSupply,
|
||||
} from "./hooks/nft/drop/useClaimedSupply";
|
||||
export {
|
||||
dropUnclaimedSupplyQuery,
|
||||
useDropUnclaimedSupply,
|
||||
} from "./hooks/nft/drop/useUnclaimedSupply";
|
||||
export { useClaimNFT } from "./hooks/nft/drop/useClaimNFT";
|
||||
export {
|
||||
claimConditionsQuery,
|
||||
useClaimConditions,
|
||||
} from "./hooks/nft/drop/useClaimConditions";
|
||||
export { useSetClaimConditions } from "./hooks/nft/drop/useSetClaimConditions";
|
||||
|
||||
// Token
|
||||
export { tokenSupplyQuery, useTokenSupply } from "./hooks/token/useTokenSupply";
|
||||
export {
|
||||
tokenBalanceQuery,
|
||||
useTokenBalance,
|
||||
} from "./hooks/token/useTokenBalance";
|
||||
export { useMintToken } from "./hooks/token/useMintToken";
|
||||
export type { TransferTokenMutationParams } from "./hooks/token/useTransferToken";
|
||||
export { useTransferToken } from "./hooks/token/useTransferToken";
|
||||
|
||||
// Auth
|
||||
export { useLogin, useLogout, useUser } from "./hooks/auth";
|
||||
export type { UserWithData, LoginConfig } from "./hooks/auth";
|
||||
|
||||
//Wallet
|
||||
export { balanceQuery, useBalance } from "./hooks/wallet/useBalance";
|
||||
|
||||
//Contexts
|
||||
export type { ThirdwebAuthConfig } from "./contexts/thirdweb-auth";
|
||||
export {
|
||||
ThirdwebAuthProvider,
|
||||
useThirdwebAuthContext,
|
||||
} from "./contexts/thirdweb-auth";
|
||||
|
||||
// Utilities and Others
|
||||
export { shouldNeverPersistQuery } from "../core/query-utils/query-key";
|
||||
export type { RequiredParam } from "../core/query-utils/required-param";
|
||||
@@ -1,115 +0,0 @@
|
||||
import {
|
||||
QueryClientProviderProps,
|
||||
QueryClientProviderWithDefault,
|
||||
} from "../../core/providers/query-client";
|
||||
import { RequiredParam } from "../../core/query-utils/required-param";
|
||||
import { ComponentWithChildren } from "../../core/types/component";
|
||||
import {
|
||||
ThirdwebAuthConfig,
|
||||
ThirdwebAuthProvider,
|
||||
} from "../contexts/thirdweb-auth";
|
||||
import type { WalletContextState } from "@solana/wallet-adapter-react";
|
||||
import { Network, ThirdwebSDK } from "@thirdweb-dev/sdk/solana";
|
||||
import { createContext, useContext, useEffect, useMemo, useState } from "react";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
interface ThirdwebSDKProviderProps extends QueryClientProviderProps {
|
||||
network: RequiredParam<Network>;
|
||||
wallet?: WalletContextState;
|
||||
authConfig?: ThirdwebAuthConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives access to the ThirdwebSDK instance and other useful hooks to the rest of the app.
|
||||
* Requires to be wrapped with a ConnectionProvider and a WalletProvider from @solana/wallet-adapter-react.
|
||||
* @example
|
||||
* ```tsx
|
||||
* import { useWallet } from "@solana/wallet-adapter-react";
|
||||
* import { ThirdwebProvider } from "@thirdweb-dev/react/solana";
|
||||
*
|
||||
* const ThirdwebApp = () => {
|
||||
* const wallet = useWallet();
|
||||
* return (
|
||||
* <ThirdwebSDKProvider network={"devnet"} wallet={wallet}>
|
||||
* <YourApp />
|
||||
* </ThirdwebSDKProvider>
|
||||
* )};
|
||||
* ```
|
||||
*/
|
||||
export const ThirdwebSDKProvider: ComponentWithChildren<
|
||||
ThirdwebSDKProviderProps
|
||||
> = ({ children, network, queryClient, wallet, authConfig }) => {
|
||||
const [sdk, setSDK] = useState<ThirdwebSDK | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (network) {
|
||||
const _sdk = ThirdwebSDK.fromNetwork(network);
|
||||
if (wallet && wallet.publicKey) {
|
||||
_sdk.wallet.connect(wallet);
|
||||
}
|
||||
(_sdk as any)._network = network;
|
||||
setSDK(_sdk);
|
||||
} else {
|
||||
setSDK(null);
|
||||
}
|
||||
// disabled wallet on purpose because we handle that below
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [network]);
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
wallet &&
|
||||
wallet.publicKey &&
|
||||
sdk &&
|
||||
(sdk as any)._network === network
|
||||
) {
|
||||
sdk.wallet.connect(wallet);
|
||||
return;
|
||||
}
|
||||
}, [network, sdk, wallet]);
|
||||
|
||||
const ctxValue = useMemo(
|
||||
() =>
|
||||
({
|
||||
sdk,
|
||||
desiredNetwork: network || "unknown",
|
||||
_inProvider: true,
|
||||
}) as const,
|
||||
[sdk, network],
|
||||
);
|
||||
|
||||
return (
|
||||
<QueryClientProviderWithDefault queryClient={queryClient}>
|
||||
<ThirdwebAuthProvider value={authConfig}>
|
||||
<ThirdwebSDKContext.Provider value={ctxValue}>
|
||||
{children}
|
||||
</ThirdwebSDKContext.Provider>
|
||||
</ThirdwebAuthProvider>
|
||||
</QueryClientProviderWithDefault>
|
||||
);
|
||||
};
|
||||
|
||||
interface ThirdwebSDKContext {
|
||||
sdk: ThirdwebSDK | null;
|
||||
desiredNetwork: string;
|
||||
_inProvider?: true;
|
||||
}
|
||||
const ThirdwebSDKContext = /* @__PURE__ */ createContext<ThirdwebSDKContext>({
|
||||
sdk: null,
|
||||
desiredNetwork: "unknown",
|
||||
});
|
||||
|
||||
export function useSDK() {
|
||||
const ctxValue = useContext(ThirdwebSDKContext);
|
||||
invariant(
|
||||
ctxValue._inProvider,
|
||||
"useSDK must be used within a ThirdwebSDKProvider",
|
||||
);
|
||||
if (
|
||||
!ctxValue.sdk ||
|
||||
(ctxValue.sdk as any)._network !== ctxValue.desiredNetwork
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
return ctxValue.sdk;
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
import { Amount, NFTMetadataOrUri } from "@thirdweb-dev/sdk";
|
||||
|
||||
/**
|
||||
* The params for the {@link useMintNFT} hook mutation.
|
||||
*
|
||||
* @beta
|
||||
*/
|
||||
export type MintNFTParams = {
|
||||
to?: string;
|
||||
metadata: NFTMetadataOrUri;
|
||||
amount?: Amount;
|
||||
};
|
||||
|
||||
/**
|
||||
* The params for the {@link useClaimNFT} hook mutation.
|
||||
*
|
||||
* @beta
|
||||
*/
|
||||
export type ClaimNFTParams = {
|
||||
to?: string;
|
||||
amount: Amount;
|
||||
};
|
||||
|
||||
/**
|
||||
* The params to pass to {@link useMintNFTSupply} hook mutation
|
||||
* @beta
|
||||
*/
|
||||
export type MintNFTSupplyParams = {
|
||||
to?: string;
|
||||
nftAddress: string;
|
||||
amount: Amount;
|
||||
};
|
||||
@@ -1,5 +1,19 @@
|
||||
# @thirdweb-dev/react-native-compat
|
||||
|
||||
## 0.3.8
|
||||
|
||||
## 0.3.7
|
||||
|
||||
## 0.3.6
|
||||
|
||||
## 0.3.5
|
||||
|
||||
## 0.3.4
|
||||
|
||||
## 0.3.3
|
||||
|
||||
## 0.3.2
|
||||
|
||||
## 0.3.1
|
||||
|
||||
## 0.3.0
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/react-native-compat",
|
||||
"description": "Shims for Thirdweb in React Native Projects",
|
||||
"version": "0.3.1",
|
||||
"version": "0.3.8",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-native-compat",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -1,5 +1,111 @@
|
||||
# @thirdweb-dev/react-native
|
||||
|
||||
## 0.3.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1724](https://github.com/thirdweb-dev/js/pull/1724) [`fc62b91e`](https://github.com/thirdweb-dev/js/commit/fc62b91ee55b0adba01298f33b21352004d1b71d) Thanks [@iketw](https://github.com/iketw)! - Adds Google sign in to embeddedWallet in React Native
|
||||
|
||||
You need to add the `react-native-inappbrowser-reborn` package to your app, then you can do:
|
||||
|
||||
```javascript
|
||||
<ThirdwebProvider
|
||||
activeChain={activeChain}
|
||||
clientId={"your-client-id"}
|
||||
supportedWallets={[
|
||||
embeddedWallet({
|
||||
// if this is true AND oauthOptions is not set we set it to false internally
|
||||
email: true,
|
||||
// if this is set we enable Sign in with Google
|
||||
oauthOptions: {
|
||||
redirectUrl: "test15app://",
|
||||
providers: ["google"],
|
||||
},
|
||||
}),
|
||||
]}
|
||||
>
|
||||
<App />
|
||||
</ThirdwebProvider>
|
||||
```
|
||||
|
||||
- Updated dependencies [[`526176c4`](https://github.com/thirdweb-dev/js/commit/526176c47108c91d83bcfc5f0ca556274e6462d6), [`d1f8e951`](https://github.com/thirdweb-dev/js/commit/d1f8e951623f1691fdfe3d1e8645970d0a52eb06), [`09120c92`](https://github.com/thirdweb-dev/js/commit/09120c923cca804b9d4f5f779e5a53c97ecc8223), [`08e9cd20`](https://github.com/thirdweb-dev/js/commit/08e9cd206bcc37cf1e84a878dc78bc4f38e5092c), [`6573556d`](https://github.com/thirdweb-dev/js/commit/6573556d0e03efa0d6a157fccb0a1c08dd22d7cd)]:
|
||||
- @thirdweb-dev/[email protected]
|
||||
- @thirdweb-dev/[email protected]
|
||||
- @thirdweb-dev/[email protected]
|
||||
|
||||
## 0.3.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1754](https://github.com/thirdweb-dev/js/pull/1754) [`dcdb0dcb`](https://github.com/thirdweb-dev/js/commit/dcdb0dcb838168a22c8335738852316dfb6e6fc9) Thanks [@iketw](https://github.com/iketw)! - Fix typos in SmartWallet api
|
||||
|
||||
- [#1760](https://github.com/thirdweb-dev/js/pull/1760) [`f41ee6fb`](https://github.com/thirdweb-dev/js/commit/f41ee6fb1cc3b1e58cc273fa45087d4c92ff97d1) Thanks [@iketw](https://github.com/iketw)! - Correctly pass theme via ConnectWallet
|
||||
|
||||
- [#1753](https://github.com/thirdweb-dev/js/pull/1753) [`b3b9edca`](https://github.com/thirdweb-dev/js/commit/b3b9edca29e7d4053b14270a61caa89c34fecf9e) Thanks [@iketw](https://github.com/iketw)! - Minor bug and UI fix for connecting an external app to a smart wallet
|
||||
|
||||
- [#1759](https://github.com/thirdweb-dev/js/pull/1759) [`513c332e`](https://github.com/thirdweb-dev/js/commit/513c332ed02df4ac316076cc03178a4702b12110) Thanks [@iketw](https://github.com/iketw)! - Fixes bug when passing only one wallet as a supportedWallet. The selectUI component must be displayed.
|
||||
|
||||
- Updated dependencies [[`1f3c64d3`](https://github.com/thirdweb-dev/js/commit/1f3c64d3618903b9008cc7b633ea890b508e7800), [`74941603`](https://github.com/thirdweb-dev/js/commit/74941603a96456da46a47147f67c98235ac55022), [`4b98e487`](https://github.com/thirdweb-dev/js/commit/4b98e487d4b47225d7095e5444dc5e7608db48a3), [`693f349d`](https://github.com/thirdweb-dev/js/commit/693f349db2478e1cd0fc82a9ef9882f46832b125), [`dcdb0dcb`](https://github.com/thirdweb-dev/js/commit/dcdb0dcb838168a22c8335738852316dfb6e6fc9), [`0f12d1f9`](https://github.com/thirdweb-dev/js/commit/0f12d1f90320923309f085c372d3a5ed01dd4606), [`b3b9edca`](https://github.com/thirdweb-dev/js/commit/b3b9edca29e7d4053b14270a61caa89c34fecf9e), [`63ad0050`](https://github.com/thirdweb-dev/js/commit/63ad0050f0a24ec15b90933b5664d697618cf2d0)]:
|
||||
- @thirdweb-dev/[email protected]
|
||||
- @thirdweb-dev/[email protected]
|
||||
- @thirdweb-dev/[email protected]
|
||||
|
||||
## 0.3.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`e684d05e`](https://github.com/thirdweb-dev/js/commit/e684d05e222458f02c8158eb9385d68c879dd946)]:
|
||||
- @thirdweb-dev/[email protected]
|
||||
- @thirdweb-dev/[email protected]
|
||||
|
||||
## 0.3.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1645](https://github.com/thirdweb-dev/js/pull/1645) [`79f91ee2`](https://github.com/thirdweb-dev/js/commit/79f91ee2d96e3a9591d6104c542496bce11f3c71) Thanks [@MananTank](https://github.com/MananTank)! - `WalletConfig.connectUI`` props updated:
|
||||
|
||||
- `close` and `open` removed - wallet can no longer "close" the Modal
|
||||
- `hide` and `show` added to only allow hiding and showing the Modal
|
||||
- `connected` added - use this instead of `close` when wallet is connected and Modal is safe to close.
|
||||
|
||||
- Updated dependencies [[`ce4608bf`](https://github.com/thirdweb-dev/js/commit/ce4608bff4783caf164ad6e21b42a827b89badf8), [`79f91ee2`](https://github.com/thirdweb-dev/js/commit/79f91ee2d96e3a9591d6104c542496bce11f3c71), [`ce4608bf`](https://github.com/thirdweb-dev/js/commit/ce4608bff4783caf164ad6e21b42a827b89badf8)]:
|
||||
- @thirdweb-dev/[email protected]
|
||||
- @thirdweb-dev/[email protected]
|
||||
- @thirdweb-dev/[email protected]
|
||||
- @thirdweb-dev/[email protected]
|
||||
|
||||
## 0.3.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`ec36b13a`](https://github.com/thirdweb-dev/js/commit/ec36b13a30e0071548df0b7a6eb5299e2e65e4f9), [`6abb8459`](https://github.com/thirdweb-dev/js/commit/6abb8459712e387b6d8b2edf7eb16fb906c05dae), [`a6c36724`](https://github.com/thirdweb-dev/js/commit/a6c36724eb930ee0abbce876bb7847c859c6fb48)]:
|
||||
- @thirdweb-dev/[email protected]
|
||||
- @thirdweb-dev/[email protected]
|
||||
- @thirdweb-dev/[email protected]
|
||||
|
||||
## 0.3.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1715](https://github.com/thirdweb-dev/js/pull/1715) [`f5caf6a3`](https://github.com/thirdweb-dev/js/commit/f5caf6a3502905666ae57f3304bb9074e09c9366) Thanks [@iketw](https://github.com/iketw)! - Fix encryption/decryption bug in embeddedWallet for React Native
|
||||
|
||||
- [#1709](https://github.com/thirdweb-dev/js/pull/1709) [`6f4c5cd7`](https://github.com/thirdweb-dev/js/commit/6f4c5cd746caf07f057e272aec9f204ba5905cd3) Thanks [@ElasticBottle](https://github.com/ElasticBottle)! - feat(react-native): update iteration count for embedded-wallet for better speed and future updates
|
||||
|
||||
- Updated dependencies [[`9bd01de5`](https://github.com/thirdweb-dev/js/commit/9bd01de5f9c388e758fba9af7899dc4a9c5a0101), [`93127047`](https://github.com/thirdweb-dev/js/commit/931270479ef227556a1077357a8c000b08de6e8d), [`d3c8626a`](https://github.com/thirdweb-dev/js/commit/d3c8626a5a8def882c1592b236048ebe88e85d49), [`f35fbec1`](https://github.com/thirdweb-dev/js/commit/f35fbec1be14332d06e73b5f44f66975ef311d6c), [`9bd01de5`](https://github.com/thirdweb-dev/js/commit/9bd01de5f9c388e758fba9af7899dc4a9c5a0101)]:
|
||||
- @thirdweb-dev/[email protected]
|
||||
- @thirdweb-dev/[email protected]
|
||||
- @thirdweb-dev/[email protected]
|
||||
|
||||
## 0.3.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`6d3d76cf`](https://github.com/thirdweb-dev/js/commit/6d3d76cff8018015faa191a1f8bd4f34506a6650), [`04f2f7b8`](https://github.com/thirdweb-dev/js/commit/04f2f7b8ff5f19345d868fc515a24ccd6ffd0ab9), [`15fe4779`](https://github.com/thirdweb-dev/js/commit/15fe4779f4b99e51afe214ac3ebb31f611089787)]:
|
||||
- @thirdweb-dev/[email protected]
|
||||
- @thirdweb-dev/[email protected]
|
||||
- @thirdweb-dev/[email protected]
|
||||
- @thirdweb-dev/[email protected]
|
||||
|
||||
## 0.3.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/react-native",
|
||||
"version": "0.3.1",
|
||||
"version": "0.3.8",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-native",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"license": "Apache-2.0",
|
||||
@@ -89,7 +89,8 @@
|
||||
"amazon-cognito-identity-js": "^6.3.3",
|
||||
"react-native-quick-base64": "^2.0.7",
|
||||
"react-native-quick-crypto": "^0.6.1",
|
||||
"react-native-aes-gcm-crypto": "^0.2.2"
|
||||
"react-native-aes-gcm-crypto": "^0.2.2",
|
||||
"react-native-inappbrowser-reborn": "^3.7.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"ethers": ">=5.5.1 <6",
|
||||
|
||||
@@ -10,3 +10,4 @@ export * from "./right-arrow";
|
||||
export * from "./wallet";
|
||||
export * from "./money";
|
||||
export * from "./switch";
|
||||
export * from "./svgs";
|
||||
|
||||
@@ -1,3 +1,23 @@
|
||||
export const GOOGLE_ICON = `<svg height={height} viewBox="0 0 24 24" width={width}>
|
||||
<path
|
||||
d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"
|
||||
fill="#4285F4"
|
||||
/>
|
||||
<path
|
||||
d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"
|
||||
fill="#34A853"
|
||||
/>
|
||||
<path
|
||||
d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"
|
||||
fill="#FBBC05"
|
||||
/>
|
||||
<path
|
||||
d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"
|
||||
fill="#EA4335"
|
||||
/>
|
||||
<path d="M1 1h22v22H1z" fill="none" />
|
||||
</svg>`;
|
||||
|
||||
export const EMAIL_WALLET_ICON = `<svg width="48" height="48" viewBox="0 0 48 48" fill="none">
|
||||
<g clip-path="url(#clip0_3589_8649)">
|
||||
<rect width="48" height="48" rx="8" fill="url(#paint0_linear_3589_8649)"/>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useWallet } from "@thirdweb-dev/react-core";
|
||||
import { IWalletConnectReceiver } from "@thirdweb-dev/wallets";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import Box from "../base/Box";
|
||||
import BaseButton from "../base/BaseButton";
|
||||
import DisconnectIcon from "../../assets/disconnect";
|
||||
@@ -21,6 +21,7 @@ const ConnectAppField = () => {
|
||||
const [appMeta, setAppMeta] = useState<{ name: string; iconUrl: string }>();
|
||||
const wallet = useWallet();
|
||||
const [showQRCodeScan, setShowQRCodeScan] = useState(false);
|
||||
const wcUriRef = useRef<string | undefined>();
|
||||
|
||||
const getAppMeta = useCallback(() => {
|
||||
if (wallet && "isWCReceiverEnabled" in wallet) {
|
||||
@@ -80,9 +81,10 @@ const ConnectAppField = () => {
|
||||
};
|
||||
|
||||
const onQRCodeScan = (data: string) => {
|
||||
if (wcUri !== data && data.startsWith("wc:")) {
|
||||
if (wcUriRef.current !== data && data.startsWith("wc:")) {
|
||||
setWCUri(data);
|
||||
setShowQRCodeScan(false);
|
||||
wcUriRef.current = data;
|
||||
|
||||
onWCPress(data);
|
||||
}
|
||||
@@ -102,6 +104,9 @@ const ConnectAppField = () => {
|
||||
if (uriToUse?.startsWith("wc:")) {
|
||||
(wallet as unknown as IWalletConnectReceiver).connectApp(uriToUse);
|
||||
}
|
||||
|
||||
setWCUri(undefined);
|
||||
wcUriRef.current = undefined;
|
||||
};
|
||||
|
||||
const onScanQRPress = () => {
|
||||
@@ -124,9 +129,11 @@ const ConnectAppField = () => {
|
||||
value: wcUri,
|
||||
placeholder: "wc://...",
|
||||
placeholderTextColor: theme.colors.textSecondary,
|
||||
numberOfLines: 1,
|
||||
}}
|
||||
containerProps={{
|
||||
flex: 1,
|
||||
pl: "xxs",
|
||||
}}
|
||||
/>
|
||||
<BaseButton
|
||||
@@ -164,12 +171,12 @@ const ConnectAppField = () => {
|
||||
>
|
||||
<>
|
||||
{appMeta?.iconUrl ? (
|
||||
<WalletIcon size={32} iconUri={appMeta.iconUrl} />
|
||||
<WalletIcon size={24} iconUri={appMeta.iconUrl} />
|
||||
) : (
|
||||
<WalletConnectIcon width={16} height={16} />
|
||||
<WalletConnectIcon width={24} height={24} />
|
||||
)}
|
||||
<View style={styles.exportWalletInfo}>
|
||||
<Text variant="bodySmall">
|
||||
<Text variant="bodySmall" numberOfLines={1}>
|
||||
{appMeta ? appMeta.name : "Connect app"}
|
||||
</Text>
|
||||
</View>
|
||||
@@ -215,8 +222,9 @@ const styles = StyleSheet.create({
|
||||
justifyContent: "flex-start",
|
||||
alignItems: "flex-start",
|
||||
alignContent: "center",
|
||||
flexDirection: "column",
|
||||
flexDirection: "row",
|
||||
marginLeft: 8,
|
||||
marginRight: 8,
|
||||
},
|
||||
exportWallet: {
|
||||
display: "flex",
|
||||
|
||||
+7
-3
@@ -238,7 +238,8 @@ export const ConnectWalletDetailsModal = ({
|
||||
) : null}
|
||||
</BaseButton>
|
||||
) : null}
|
||||
{activeWallet?.walletId === EmbeddedWallet.id ? (
|
||||
{activeWallet?.walletId === EmbeddedWallet.id &&
|
||||
(activeWallet as EmbeddedWallet).getEmail() ? (
|
||||
<Box flexDirection="row" alignItems="center" mt="md">
|
||||
<ActiveDot width={10} height={10} />
|
||||
<Text variant="bodySmallSecondary" ml="xxs">
|
||||
@@ -246,7 +247,11 @@ export const ConnectWalletDetailsModal = ({
|
||||
</Text>
|
||||
</Box>
|
||||
) : null}
|
||||
<Box flexDirection="row" justifyContent="space-evenly" mt="md">
|
||||
<Box
|
||||
flexDirection="row"
|
||||
justifyContent="space-evenly"
|
||||
marginVertical="md"
|
||||
>
|
||||
<SendButton supportedTokens={supportedTokens} />
|
||||
<ReceiveButton />
|
||||
</Box>
|
||||
@@ -330,7 +335,6 @@ const styles = StyleSheet.create({
|
||||
alignContent: "flex-start",
|
||||
alignItems: "flex-start",
|
||||
justifyContent: "flex-start",
|
||||
marginTop: 24,
|
||||
marginBottom: 8,
|
||||
},
|
||||
});
|
||||
|
||||
+2
-2
@@ -12,9 +12,9 @@ import { useEffect, useState } from "react";
|
||||
import { useSmartWallet } from "../../providers/context-provider";
|
||||
import RightArrowIcon from "../../assets/right-arrow";
|
||||
import ConnectAppField from "./ConnectAppField";
|
||||
import { useAppTheme } from "../../styles/hooks";
|
||||
import DisconnectIcon from "../../assets/disconnect";
|
||||
import { IconTextButton } from "../base/IconTextButton";
|
||||
import { useGlobalTheme } from "../../providers/ui-context-provider";
|
||||
|
||||
export const SmartWalletAdditionalActions = ({
|
||||
onExportPress,
|
||||
@@ -26,7 +26,7 @@ export const SmartWalletAdditionalActions = ({
|
||||
const [smartWalletAddress, setSmartWalletAddress] = useState<string>("");
|
||||
const [showSmartWallet, setShowSmartWallet] = useState(false);
|
||||
const activeWallet = useWallet();
|
||||
const theme = useAppTheme();
|
||||
const theme = useGlobalTheme();
|
||||
|
||||
const wallet = showSmartWallet
|
||||
? smartWallet
|
||||
|
||||
+8
-2
@@ -1,7 +1,6 @@
|
||||
import { AddressDisplay } from "../base/AddressDisplay";
|
||||
import BaseButton from "../base/BaseButton";
|
||||
import Text from "../base/Text";
|
||||
import { WalletIcon } from "../base/WalletIcon";
|
||||
import { useENS, useWallet } from "@thirdweb-dev/react-core";
|
||||
import { StyleSheet } from "react-native";
|
||||
import { LocalWallet, walletIds } from "@thirdweb-dev/wallets";
|
||||
@@ -11,6 +10,7 @@ import { useMemo, useState } from "react";
|
||||
import { TextBalance } from "../base/TextBalance";
|
||||
import { SupportedTokens } from "../SendFunds/defaultTokens";
|
||||
import { SMART_WALLET_ICON } from "../../assets/svgs";
|
||||
import { ImageSvgUri } from "../base";
|
||||
|
||||
export type ConnectWalletDetailsProps = {
|
||||
address?: string;
|
||||
@@ -90,7 +90,13 @@ export const WalletDetailsButton = ({
|
||||
alignContent="center"
|
||||
justifyContent="flex-start"
|
||||
>
|
||||
<WalletIcon size={32} iconUri={avatarUrl || walletIconUrl} />
|
||||
<Box borderRadius="lg" overflow="hidden">
|
||||
<ImageSvgUri
|
||||
width={32}
|
||||
height={32}
|
||||
imageUrl={avatarUrl || walletIconUrl}
|
||||
/>
|
||||
</Box>
|
||||
<Box ml="md" justifyContent="center" alignItems="flex-start">
|
||||
{activeWallet?.walletId === LocalWallet.id ? (
|
||||
<Text variant="bodySmall" color="red">
|
||||
|
||||
+2
-2
@@ -1,5 +1,4 @@
|
||||
import { Icon } from "../../assets/icon";
|
||||
import { useAppTheme } from "../../styles/hooks";
|
||||
import { AddressDisplay } from "../base/AddressDisplay";
|
||||
import BaseButton from "../base/BaseButton";
|
||||
import { WalletIcon } from "../base/WalletIcon";
|
||||
@@ -13,6 +12,7 @@ import { TextBalance } from "../base/TextBalance";
|
||||
import { walletIds } from "@thirdweb-dev/wallets";
|
||||
import { SMART_WALLET_ICON } from "../../assets/svgs";
|
||||
import Text from "../base/Text";
|
||||
import { useGlobalTheme } from "../../providers/ui-context-provider";
|
||||
|
||||
interface WalletDetailsModalHeaderProps {
|
||||
address?: string;
|
||||
@@ -28,7 +28,7 @@ export const WalletDetailsModalHeader = ({
|
||||
onAddressCopied,
|
||||
tokenAddress,
|
||||
}: WalletDetailsModalHeaderProps) => {
|
||||
const theme = useAppTheme();
|
||||
const theme = useGlobalTheme();
|
||||
const activeWallet = useWallet();
|
||||
const [showLoading, setShowLoading] = useState(false);
|
||||
const ensQuery = useENS();
|
||||
|
||||
+3
-5
@@ -5,11 +5,11 @@ import { ReactNode, useState } from "react";
|
||||
import Box from "../../base/Box";
|
||||
import Text from "../../base/Text";
|
||||
import ThirdwebLogo from "../../../assets/thirdweb-logo";
|
||||
import { useAppTheme } from "../../../styles/hooks";
|
||||
import { ChooseWalletContent } from "./ChooseWalletContent";
|
||||
import { BaseButton, ImageSvgUri, WalletButton } from "../../base";
|
||||
import { ActivityIndicator, Linking } from "react-native";
|
||||
import { useTheme } from "@shopify/restyle";
|
||||
import { useGlobalTheme } from "../../../providers/ui-context-provider";
|
||||
|
||||
export type ChooseWalletProps = {
|
||||
headerText?: ReactNode | string;
|
||||
@@ -34,7 +34,7 @@ export function ChooseWallet({
|
||||
termsOfServiceUrl,
|
||||
privacyPolicyUrl,
|
||||
}: ChooseWalletProps) {
|
||||
const theme = useAppTheme();
|
||||
const theme = useGlobalTheme();
|
||||
const themeLightDark = useTheme();
|
||||
const [isConnecting, setIsConnecting] = useState(false);
|
||||
const [isConnectAWalletEnabled, setIsConnectAWalletEnabled] = useState(false);
|
||||
@@ -261,9 +261,7 @@ export function ChooseWallet({
|
||||
) : null}
|
||||
{showToSPrivacyPolicy ? (
|
||||
<Box
|
||||
mt="md"
|
||||
pt="md"
|
||||
height={50}
|
||||
mt="sm"
|
||||
marginHorizontal={!isConnectAWalletEnabled ? "xl" : "none"}
|
||||
alignItems="center"
|
||||
>
|
||||
|
||||
@@ -2,9 +2,11 @@ import { ActivityIndicator, StyleSheet } from "react-native";
|
||||
import { BaseButton, Text } from "../base";
|
||||
import { useConnectionStatus, useWallets } from "@thirdweb-dev/react-core";
|
||||
import { useState, useEffect } from "react";
|
||||
import { useModalState } from "../../providers/ui-context-provider";
|
||||
import {
|
||||
useGlobalTheme,
|
||||
useModalState,
|
||||
} from "../../providers/ui-context-provider";
|
||||
import { ThemeProvider, ThemeProviderProps } from "../../styles/ThemeProvider";
|
||||
import { useAppTheme } from "../../styles/hooks";
|
||||
|
||||
export type ConnectWalletButtonProps = {
|
||||
theme?: ThemeProviderProps["theme"];
|
||||
@@ -43,7 +45,7 @@ export const ConnectWalletButton = ({
|
||||
buttonTitle,
|
||||
theme,
|
||||
}: ConnectWalletButtonProps) => {
|
||||
const appTheme = useAppTheme();
|
||||
const appTheme = useGlobalTheme();
|
||||
const connectionStatus = useConnectionStatus();
|
||||
const isWalletConnecting = connectionStatus === "connecting";
|
||||
|
||||
|
||||
@@ -5,14 +5,16 @@ import { WalletConfig, useConnect, useWallets } from "@thirdweb-dev/react-core";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { walletIds } from "@thirdweb-dev/wallets";
|
||||
import { useColorScheme } from "react-native";
|
||||
import { useModalState } from "../../providers/ui-context-provider";
|
||||
import {
|
||||
useGlobalTheme,
|
||||
useModalState,
|
||||
} from "../../providers/ui-context-provider";
|
||||
import {
|
||||
CLOSE_MODAL_STATE,
|
||||
ConnectWalletFlowModal,
|
||||
} from "../../utils/modalTypes";
|
||||
import Box from "../base/Box";
|
||||
import { ThemeProvider } from "../../styles/ThemeProvider";
|
||||
import { useAppTheme } from "../../styles/hooks";
|
||||
|
||||
export const ConnectWalletFlow = () => {
|
||||
const { modalState, setModalState } = useModalState();
|
||||
@@ -30,7 +32,7 @@ export const ConnectWalletFlow = () => {
|
||||
const [selectionData, setSelectionData] = useState<any>();
|
||||
const supportedWallets = useWallets();
|
||||
const theme = useColorScheme();
|
||||
const appTheme = useAppTheme();
|
||||
const appTheme = useGlobalTheme();
|
||||
const connect = useConnect();
|
||||
|
||||
const onClose = useCallback(
|
||||
@@ -60,8 +62,8 @@ export const ConnectWalletFlow = () => {
|
||||
|
||||
const onChooseWallet = useCallback(
|
||||
(wallet: WalletConfig, data?: any) => {
|
||||
setActiveWallet(wallet);
|
||||
setSelectionData(data);
|
||||
setActiveWallet(wallet);
|
||||
|
||||
// If the wallet has no custom connect UI, then connect it
|
||||
if (!wallet.connectUI) {
|
||||
@@ -74,13 +76,19 @@ export const ConnectWalletFlow = () => {
|
||||
useEffect(() => {
|
||||
// case when only one wallet is passed in supportedWallets
|
||||
if (walletConfig) {
|
||||
if (walletConfig.connectUI) {
|
||||
// if there's a connection UI, then show it
|
||||
setActiveWallet(walletConfig);
|
||||
} else {
|
||||
// if there's no connection UI, then connect the wallet
|
||||
onChooseWallet(walletConfig);
|
||||
// if there's a selection UI, then continue with the flow
|
||||
if (walletConfig.selectUI) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (walletConfig.connectUI) {
|
||||
// if there's a connection UI and no selection UI, then show it
|
||||
setActiveWallet(walletConfig);
|
||||
return;
|
||||
}
|
||||
|
||||
// if there's no connection UI or selectionUI, then automatically select it
|
||||
onChooseWallet(walletConfig);
|
||||
}
|
||||
}, [onChooseWallet, walletConfig]);
|
||||
|
||||
@@ -108,9 +116,10 @@ export const ConnectWalletFlow = () => {
|
||||
modalSize="compact"
|
||||
theme={theme || "dark"}
|
||||
goBack={onBackPress}
|
||||
close={handleClose}
|
||||
connected={handleClose}
|
||||
isOpen={modalVisible}
|
||||
open={onOpenModal}
|
||||
show={onOpenModal}
|
||||
hide={() => {}}
|
||||
walletConfig={activeWallet}
|
||||
supportedWallets={supportedWallets}
|
||||
selectionData={selectionData}
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ export function ConnectingWallet({
|
||||
subHeaderText={subHeaderText}
|
||||
onClose={onClose}
|
||||
/>
|
||||
<WalletLoadingThumbnail imageSize={100}>
|
||||
<WalletLoadingThumbnail imageSize={85}>
|
||||
<ImageSvgUri height={80} width={80} imageUrl={wallet.meta.iconURL} />
|
||||
</WalletLoadingThumbnail>
|
||||
<View style={styles.connectingContainer}>
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
import { Icon } from "../../../assets/icon";
|
||||
import { useAppTheme } from "../../../styles/hooks";
|
||||
import { useGlobalTheme } from "../../../providers/ui-context-provider";
|
||||
import Text from "../../base/Text";
|
||||
import { FlexAlignType, StyleSheet, View } from "react-native";
|
||||
|
||||
@@ -20,7 +20,7 @@ export const ConnectWalletHeader = ({
|
||||
onClose,
|
||||
onBackPress,
|
||||
}: ConnectWalletHeaderProps) => {
|
||||
const theme = useAppTheme();
|
||||
const theme = useGlobalTheme();
|
||||
return (
|
||||
<>
|
||||
<View style={styles.header}>
|
||||
|
||||
@@ -20,7 +20,7 @@ type LocalWalletFlowUIProps = ConnectUIProps<LocalWallet> & {
|
||||
|
||||
export function LocalWalletFlow({
|
||||
goBack,
|
||||
close,
|
||||
connected,
|
||||
walletConfig,
|
||||
onConnected,
|
||||
}: LocalWalletFlowUIProps) {
|
||||
@@ -61,7 +61,7 @@ export function LocalWalletFlow({
|
||||
headerText="Guest Wallet"
|
||||
alignHeader="flex-start"
|
||||
subHeaderText={""}
|
||||
onClose={close}
|
||||
onClose={connected}
|
||||
/>
|
||||
<View style={styles.connectingContainer}>
|
||||
<BaseButton
|
||||
|
||||
+2
-2
@@ -16,7 +16,7 @@ import * as FileSystem from "expo-file-system";
|
||||
import { TWModal } from "../base/modal/TWModal";
|
||||
import { localWallet } from "../../wallets/wallets/local-wallet";
|
||||
import { TextInput } from "../base";
|
||||
import { useAppTheme } from "../../styles/hooks";
|
||||
import { useGlobalTheme } from "../../providers/ui-context-provider";
|
||||
|
||||
export type LocalWalletImportModalProps = {
|
||||
isVisible: boolean;
|
||||
@@ -37,7 +37,7 @@ export const LocalWalletImportModal = ({
|
||||
const [error, setError] = useState<string | undefined>();
|
||||
const [isImporting, setIsImporting] = useState<boolean>(false);
|
||||
const createWalletInstance = useCreateWalletInstance();
|
||||
const theme = useAppTheme();
|
||||
const theme = useGlobalTheme();
|
||||
|
||||
const createLocalWalletFromJsonFile = async () => {
|
||||
if (!jsonFile || !password) {
|
||||
|
||||
+8
-8
@@ -15,16 +15,16 @@ import WalletLoadingThumbnail from "../../../wallets/wallets/wallet-connect/Wall
|
||||
import ImageSvgUri from "../../base/ImageSvgUri";
|
||||
import Box from "../../base/Box";
|
||||
import { ConnectWalletHeader } from "../ConnectingWallet/ConnectingWalletHeader";
|
||||
import { useAppTheme } from "../../../styles/hooks";
|
||||
import { useGlobalTheme } from "../../../providers/ui-context-provider";
|
||||
|
||||
export const SmartWalletFlow = ({
|
||||
close,
|
||||
connected,
|
||||
goBack,
|
||||
walletConfig,
|
||||
personalWalletConfig,
|
||||
...props
|
||||
}: ConnectUIProps<SmartWallet> & { personalWalletConfig: WalletConfig }) => {
|
||||
const theme = useAppTheme();
|
||||
const theme = useGlobalTheme();
|
||||
const [connectedPersonalWallet, setConnectedPersonalWallet] =
|
||||
useState<WalletInstance>();
|
||||
const [personalWalletChainId, setPersonalWalletChaindId] = useState<
|
||||
@@ -49,12 +49,12 @@ export const SmartWalletFlow = ({
|
||||
await connect(walletConfig, {
|
||||
personalWallet: personalWallet,
|
||||
});
|
||||
close();
|
||||
connected();
|
||||
} else {
|
||||
setPersonalWalletChaindId(eoaWalletChainId);
|
||||
}
|
||||
},
|
||||
[close, connect, targetChain.chainId, walletConfig],
|
||||
[connected, connect, targetChain.chainId, walletConfig],
|
||||
);
|
||||
|
||||
const connectPersonalWallet = useCallback(
|
||||
@@ -82,7 +82,7 @@ export const SmartWalletFlow = ({
|
||||
const onConnectingClosePress = () => {
|
||||
connectedPersonalWallet?.disconnect();
|
||||
reset();
|
||||
close();
|
||||
connected();
|
||||
};
|
||||
|
||||
const onConnectingBackPress = () => {
|
||||
@@ -119,7 +119,7 @@ export const SmartWalletFlow = ({
|
||||
{PersonalWalletConfigUI && !connectedPersonalWallet ? (
|
||||
<PersonalWalletConfigUI
|
||||
{...props}
|
||||
close={close}
|
||||
connected={connected}
|
||||
goBack={goBack}
|
||||
walletConfig={personalWalletConfig}
|
||||
onLocallyConnected={onPersonalWalletConnected}
|
||||
@@ -131,7 +131,7 @@ export const SmartWalletFlow = ({
|
||||
onBackPress={onConnectingBackPress}
|
||||
onClose={onConnectingClosePress}
|
||||
/>
|
||||
<WalletLoadingThumbnail imageSize={100}>
|
||||
<WalletLoadingThumbnail imageSize={85}>
|
||||
<ImageSvgUri
|
||||
height={80}
|
||||
width={80}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { useModalState } from "../providers/ui-context-provider";
|
||||
import {
|
||||
useGlobalTheme,
|
||||
useModalState,
|
||||
} from "../providers/ui-context-provider";
|
||||
import { ConnectWalletFlow } from "./ConnectWalletFlow/ConnectWalletFlow";
|
||||
import { Dimensions, StyleSheet, View } from "react-native";
|
||||
import { useMemo } from "react";
|
||||
@@ -7,13 +10,13 @@ import { SessionRequestModal } from "./ConnectWalletDetails/SessionRequestModal"
|
||||
import { SessionProposalModal } from "./ConnectWalletDetails/SessionProposalModal";
|
||||
import { TWModal } from "./base/modal/TWModal";
|
||||
import Box from "./base/Box";
|
||||
import { useAppTheme } from "../styles/hooks";
|
||||
// import { useAppTheme } from "../styles/hooks";
|
||||
|
||||
const MODAL_HEIGHT = Dimensions.get("window").height * 0.6;
|
||||
const MODAL_HEIGHT = Dimensions.get("window").height * 0.7;
|
||||
const DEVICE_WIDTH = Dimensions.get("window").width;
|
||||
|
||||
export const MainModal = () => {
|
||||
const theme = useAppTheme();
|
||||
const theme = useGlobalTheme();
|
||||
const { modalState } = useModalState();
|
||||
|
||||
const { isOpen, isSheet } = modalState;
|
||||
|
||||
@@ -3,14 +3,14 @@ import Box from "./base/Box";
|
||||
import { useState } from "react";
|
||||
import EyeClosed from "../assets/eye-closed";
|
||||
import EyeOpened from "../assets/eye-opened";
|
||||
import { useAppTheme } from "../styles/hooks";
|
||||
import { useGlobalTheme } from "../providers/ui-context-provider";
|
||||
|
||||
export const PasswordInput = ({
|
||||
onChangeText,
|
||||
}: {
|
||||
onChangeText: TextInput["props"]["onChangeText"];
|
||||
}) => {
|
||||
const theme = useAppTheme();
|
||||
const theme = useGlobalTheme();
|
||||
const [showPassword, setShowPassword] = useState(false);
|
||||
|
||||
const onPressEyeIcon = () => {
|
||||
|
||||
@@ -2,7 +2,6 @@ import React, { useEffect, useState } from "react";
|
||||
import { IconTextButton } from "./base/IconTextButton";
|
||||
import { useAddress } from "@thirdweb-dev/react-core";
|
||||
import { Dimensions, KeyboardAvoidingView } from "react-native";
|
||||
import { useAppTheme } from "../styles/hooks";
|
||||
import {
|
||||
TWModal,
|
||||
Box,
|
||||
@@ -15,9 +14,10 @@ import {
|
||||
import DownloadIcon from "../assets/download";
|
||||
import CopyIcon from "../assets/copy";
|
||||
import QRCode from "react-native-qrcode-svg";
|
||||
import { useGlobalTheme } from "../providers/ui-context-provider";
|
||||
|
||||
export const ReceiveButton = () => {
|
||||
const theme = useAppTheme();
|
||||
const theme = useGlobalTheme();
|
||||
const [isModalVisible, setIsModalVisible] = useState(false);
|
||||
|
||||
const onClose = () => {
|
||||
@@ -60,7 +60,7 @@ export const ReceiveFundsModal = ({
|
||||
isVisible,
|
||||
onClose,
|
||||
}: ReceiveFundsModalProps) => {
|
||||
const theme = useAppTheme();
|
||||
const theme = useGlobalTheme();
|
||||
const address = useAddress();
|
||||
const [addressCopied, setAddressCopied] = useState(false);
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { useAppTheme } from "../../styles/hooks";
|
||||
import React, { useEffect, useMemo, useState } from "react";
|
||||
import SendIcon from "../../assets/send";
|
||||
import {
|
||||
@@ -30,13 +29,14 @@ import { utils } from "ethers";
|
||||
import LoadingTextAnimation from "../base/LoadingTextAnimation";
|
||||
import CheckIcon from "../../assets/check";
|
||||
import { TokenSelector } from "./TokenSelector";
|
||||
import { useGlobalTheme } from "../../providers/ui-context-provider";
|
||||
|
||||
export const SendButton = ({
|
||||
supportedTokens,
|
||||
}: {
|
||||
supportedTokens: SupportedTokens;
|
||||
}) => {
|
||||
const theme = useAppTheme();
|
||||
const theme = useGlobalTheme();
|
||||
const [isModalVisible, setIsModalVisible] = useState(false);
|
||||
|
||||
const onClose = () => {
|
||||
@@ -139,12 +139,12 @@ const SendFundsForm = ({
|
||||
onTokenSelectorPress: () => void;
|
||||
token?: TokenInfo;
|
||||
}) => {
|
||||
const theme = useAppTheme();
|
||||
const theme = useGlobalTheme();
|
||||
const chain = useChain();
|
||||
const wallet = useWallet();
|
||||
const chainId = useChainId();
|
||||
const [receiverAddress, setReceiverAddress] = useState("");
|
||||
const [amount, setAmount] = useState("");
|
||||
const [amount, setAmount] = useState("0");
|
||||
const [showIcon, setShowIcon] = useState(false);
|
||||
const tokenAddress = token?.address;
|
||||
|
||||
@@ -313,6 +313,7 @@ const SendFundsForm = ({
|
||||
editable={!sendTokenMutation.isLoading}
|
||||
returnKeyType={"done"}
|
||||
keyboardType="numeric"
|
||||
value={amount}
|
||||
clearTextOnFocus={false}
|
||||
style={{
|
||||
color: theme.colors.textPrimary,
|
||||
@@ -322,8 +323,6 @@ const SendFundsForm = ({
|
||||
paddingHorizontal: 16,
|
||||
}}
|
||||
onChangeText={setAmount}
|
||||
placeholder="0"
|
||||
placeholderTextColor={theme.colors.textPrimary}
|
||||
autoCapitalize="none"
|
||||
autoCorrect={false}
|
||||
/>
|
||||
@@ -348,11 +347,18 @@ const SendFundsForm = ({
|
||||
}}
|
||||
>
|
||||
{sendTokenMutation.isLoading ? (
|
||||
<ActivityIndicator size="small" color={theme.colors.textPrimary} />
|
||||
<ActivityIndicator
|
||||
size="small"
|
||||
color={theme.colors.accentButtonTextColor}
|
||||
/>
|
||||
) : showIcon ? (
|
||||
<CheckIcon width={20} height={13} color={theme.colors.textPrimary} />
|
||||
<CheckIcon
|
||||
width={20}
|
||||
height={13}
|
||||
color={theme.colors.accentButtonTextColor}
|
||||
/>
|
||||
) : (
|
||||
<Text variant="bodySmall" mr="sm">
|
||||
<Text variant="bodySmall" color="accentButtonTextColor" mr="sm">
|
||||
Send
|
||||
</Text>
|
||||
)}
|
||||
|
||||
@@ -15,10 +15,10 @@ import {
|
||||
ScrollView,
|
||||
TextInput,
|
||||
} from "react-native";
|
||||
import { useAppTheme } from "../../styles/hooks";
|
||||
import { SelectTokenButton } from "./SelectTokenButton";
|
||||
import CloseIcon from "../../assets/close";
|
||||
import Text from "../base/Text";
|
||||
import { useGlobalTheme } from "../../providers/ui-context-provider";
|
||||
|
||||
export function useToken(tokenAddress: string): {
|
||||
isLoading: boolean;
|
||||
@@ -82,7 +82,7 @@ export function TokenSelector(props: {
|
||||
onBack: () => void;
|
||||
supportedTokens: SupportedTokens;
|
||||
}) {
|
||||
const theme = useAppTheme();
|
||||
const theme = useGlobalTheme();
|
||||
const [input, setInput] = useState("");
|
||||
const chainId = useChainId();
|
||||
const nativeTokenInfo = useNativeToken();
|
||||
|
||||
@@ -35,7 +35,7 @@ const ImageSvgUri = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<Box style={{ width: width, height: height }}>
|
||||
<Box width={width} height={height}>
|
||||
{error ? (
|
||||
<SvgUri width={width} height={height} uri={resolvedImageUrl} />
|
||||
) : (
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { useCallback, useEffect, useRef } from "react";
|
||||
import { View, Animated, Easing, StyleSheet } from "react-native";
|
||||
import { baseTheme } from "../../styles/theme";
|
||||
import { useAppTheme } from "../../styles/hooks";
|
||||
import { useGlobalTheme } from "../../providers/ui-context-provider";
|
||||
|
||||
type LoadingTextAnimationProps = {
|
||||
text: string;
|
||||
@@ -13,7 +13,7 @@ const LoadingTextAnimation = ({
|
||||
textVariant,
|
||||
}: LoadingTextAnimationProps) => {
|
||||
const fadeAnim = useRef(new Animated.Value(0)).current;
|
||||
const theme = useAppTheme();
|
||||
const theme = useGlobalTheme();
|
||||
|
||||
const fadeInOut = useCallback(() => {
|
||||
Animated.loop(
|
||||
|
||||
@@ -14,8 +14,8 @@ import { useSwitchChain, useSupportedChains } from "@thirdweb-dev/react-core";
|
||||
import Box from "./Box";
|
||||
import { ModalHeaderTextClose } from "./modal/ModalHeaderTextClose";
|
||||
import { TWModal } from "./modal/TWModal";
|
||||
import { useAppTheme } from "../../styles/hooks";
|
||||
import { Chain } from "@thirdweb-dev/chains";
|
||||
import { useGlobalTheme } from "../../providers/ui-context-provider";
|
||||
|
||||
type NetworkButtonProps = {
|
||||
chain?: Chain;
|
||||
@@ -35,7 +35,7 @@ export const NetworkButton = ({
|
||||
padding,
|
||||
...props
|
||||
}: NetworkButtonProps) => {
|
||||
const theme = useAppTheme();
|
||||
const theme = useGlobalTheme();
|
||||
const [isModalVisible, setIsModalVisible] = useState(false);
|
||||
const [switchError, setSwitchError] = useState<string | undefined>();
|
||||
const [isSwitching, setIsSwitching] = useState(false);
|
||||
@@ -72,6 +72,7 @@ export const NetworkButton = ({
|
||||
<>
|
||||
<BaseButton
|
||||
p={padding || "sm"}
|
||||
paddingVertical="xs"
|
||||
borderRadius="md"
|
||||
borderWidth={0.5}
|
||||
flexDirection="row"
|
||||
@@ -82,13 +83,8 @@ export const NetworkButton = ({
|
||||
{...props}
|
||||
>
|
||||
<Box flexDirection="row" alignItems="center">
|
||||
<ChainIcon chainIconUrl={chain?.icon?.url} size={32} />
|
||||
<Box
|
||||
ml="md"
|
||||
alignItems="flex-start"
|
||||
justifyContent="center"
|
||||
height={36}
|
||||
>
|
||||
<ChainIcon chainIconUrl={chain?.icon?.url} size={28} />
|
||||
<Box ml="md" alignItems="flex-start" justifyContent="center">
|
||||
<Text variant="bodyLarge">{chain?.name || "Unknown Network"}</Text>
|
||||
{isSwitching ? (
|
||||
<Box flexDirection="row" alignItems="center">
|
||||
|
||||
@@ -2,7 +2,7 @@ import { ReactElement, useEffect, useRef } from "react";
|
||||
import { Theme } from "../../styles/theme";
|
||||
import Text from "./Text";
|
||||
import { Animated, StyleSheet } from "react-native";
|
||||
import { useAppTheme } from "../../styles/hooks";
|
||||
import { useGlobalTheme } from "../../providers/ui-context-provider";
|
||||
|
||||
export const TOAST_HEIGHT = 45;
|
||||
|
||||
@@ -19,7 +19,7 @@ export function Toast({
|
||||
backgroundColor,
|
||||
translateY = TOAST_HEIGHT,
|
||||
}: ToastProps) {
|
||||
const theme = useAppTheme();
|
||||
const theme = useGlobalTheme();
|
||||
|
||||
const translateYRef = useRef(new Animated.Value(translateY)).current;
|
||||
|
||||
|
||||
@@ -4,20 +4,27 @@ import ImageSvgUri from "./ImageSvgUri";
|
||||
import { Label } from "./Label";
|
||||
import Text from "./Text";
|
||||
import Box from "./Box";
|
||||
import { Palette } from "../../styles/colors";
|
||||
|
||||
type WalletButtonProps = {
|
||||
onPress?: () => void;
|
||||
walletIconUrl: string;
|
||||
name: string;
|
||||
nameColor?: keyof Palette;
|
||||
labelText?: string;
|
||||
recommended?: boolean;
|
||||
iconWidth?: number;
|
||||
iconHeight?: number;
|
||||
} & React.ComponentProps<typeof BaseButton>;
|
||||
|
||||
export const WalletButton = ({
|
||||
iconWidth = 48,
|
||||
iconHeight = 48,
|
||||
mb,
|
||||
onPress,
|
||||
walletIconUrl,
|
||||
name,
|
||||
nameColor = "textPrimary",
|
||||
labelText,
|
||||
recommended,
|
||||
...props
|
||||
@@ -36,9 +43,15 @@ export const WalletButton = ({
|
||||
{...props}
|
||||
>
|
||||
<Box flexDirection="row" justifyContent="flex-start" alignItems="center">
|
||||
<ImageSvgUri imageUrl={walletIconUrl} width={48} height={48} />
|
||||
<ImageSvgUri
|
||||
imageUrl={walletIconUrl}
|
||||
width={iconWidth}
|
||||
height={iconHeight}
|
||||
/>
|
||||
<Box ml="sm" alignItems="flex-start">
|
||||
<Text variant="bodyLarge">{name}</Text>
|
||||
<Text variant="bodyLarge" color={nameColor}>
|
||||
{name}
|
||||
</Text>
|
||||
{recommended ? <Text variant="link">Recommended</Text> : null}
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useAppTheme } from "../../styles/hooks";
|
||||
import { useGlobalTheme } from "../../providers/ui-context-provider";
|
||||
import BaseButton from "./BaseButton";
|
||||
import Box from "./Box";
|
||||
import ImageSvgUri from "./ImageSvgUri";
|
||||
@@ -17,7 +17,7 @@ export const WalletButtonSquare = ({
|
||||
name,
|
||||
size,
|
||||
}: WalletButtonSquareProps) => {
|
||||
const theme = useAppTheme();
|
||||
const theme = useGlobalTheme();
|
||||
|
||||
const marginVertical = theme.spacing.xs;
|
||||
return (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useGlobalTheme } from "../../../providers/ui-context-provider";
|
||||
import Text from "../Text";
|
||||
import { TouchableOpacity, StyleSheet, ActivityIndicator } from "react-native";
|
||||
import { useAppTheme } from "../../../styles/hooks";
|
||||
|
||||
export const ModalFooter = ({
|
||||
footer,
|
||||
@@ -11,7 +11,7 @@ export const ModalFooter = ({
|
||||
isLoading?: boolean;
|
||||
onPress?: () => void;
|
||||
}) => {
|
||||
const theme = useAppTheme();
|
||||
const theme = useGlobalTheme();
|
||||
|
||||
return (
|
||||
<TouchableOpacity style={styles.footer} onPress={onPress}>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { View } from "react-native";
|
||||
import { Icon } from "../../../assets/icon";
|
||||
import { useAppTheme } from "../../../styles/hooks";
|
||||
import Box from "../Box";
|
||||
import Text from "../Text";
|
||||
import { ReactNode } from "react";
|
||||
import { useGlobalTheme } from "../../../providers/ui-context-provider";
|
||||
|
||||
interface ModalHeaderTextCloseProps {
|
||||
onClose?: () => void;
|
||||
@@ -19,7 +19,7 @@ export const ModalHeaderTextClose = ({
|
||||
onBackPress,
|
||||
...props
|
||||
}: ModalHeaderTextCloseProps & React.ComponentProps<typeof Box>) => {
|
||||
const theme = useAppTheme();
|
||||
const theme = useGlobalTheme();
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -78,7 +78,7 @@ export const useGlobalTheme = (theme?: ThemeProviderProps["theme"]): Theme => {
|
||||
const appTheme = useTheme();
|
||||
|
||||
const resultTheme = useMemo(() => {
|
||||
const resp = getThemeObj(theme) || getThemeObj(context.theme) || appTheme;
|
||||
const resp = getThemeObj(context.theme) || getThemeObj(theme) || appTheme;
|
||||
return resp;
|
||||
}, [theme, context, appTheme]);
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user