Compare commits
53
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b4847dd134 | ||
|
|
cf82c3b58c | ||
|
|
a17326634e | ||
|
|
70c4a119d6 | ||
|
|
f0443bd989 | ||
|
|
73462ef108 | ||
|
|
27c225a512 | ||
|
|
cb1c9937fa | ||
|
|
588b210601 | ||
|
|
7e483ec97f | ||
|
|
c902901cff | ||
|
|
205018f6e1 | ||
|
|
269e68c0a1 | ||
|
|
2888efc065 | ||
|
|
c753641570 | ||
|
|
4b0e63dcc0 | ||
|
|
6979810de5 | ||
|
|
4c37af49aa | ||
|
|
7858632429 | ||
|
|
0647f12498 | ||
|
|
3e1c4045e7 | ||
|
|
3ba8ba4288 | ||
|
|
dfd120a3a9 | ||
|
|
262edc6a46 | ||
|
|
4f79053ec3 | ||
|
|
2a91113a76 | ||
|
|
b103872daf | ||
|
|
7f54012ec6 | ||
|
|
df36e27f32 | ||
|
|
8c0dc9c880 | ||
|
|
074a3eb01c | ||
|
|
a5d0be939a | ||
|
|
5ec0f064d2 | ||
|
|
becbb63736 | ||
|
|
5ee700e804 | ||
|
|
67b145b94d | ||
|
|
c0a6d2f182 | ||
|
|
fd9816556f | ||
|
|
2a3cd62dc9 | ||
|
|
c9bf4f05c1 | ||
|
|
9f5adc5c5c | ||
|
|
d01e6396d1 | ||
|
|
2283d21027 | ||
|
|
ab36d84f1c | ||
|
|
a9f2ff73c9 | ||
|
|
9a7b2098ee | ||
|
|
2b96f71e19 | ||
|
|
3b6b0746b3 | ||
|
|
b0ec1d8083 | ||
|
|
0af916e42e | ||
|
|
fbde927a0c | ||
|
|
952009cd73 | ||
|
|
580e77b170 |
@@ -0,0 +1,13 @@
|
||||
## Problem solved
|
||||
|
||||
Short description of the bug fixed or feature added
|
||||
|
||||
## Changes made
|
||||
|
||||
- [ ] Public API changes: list the public API changes made if any
|
||||
- [ ] Internal API changes: explain the internal logic changes
|
||||
|
||||
## How to test
|
||||
|
||||
- [ ] Automated tests: link to unit test file
|
||||
- [ ] Manual tests: step by step instructions on how to test
|
||||
@@ -17,6 +17,7 @@ concurrency:
|
||||
env:
|
||||
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
||||
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
|
||||
TW_SECRET_KEY: ${{ secrets.TW_SECRET_KEY }}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
+1
-1
@@ -31,7 +31,7 @@
|
||||
"hotlink-revert": "node ./scripts/hotlink/hotlink-revert.mjs",
|
||||
"explain:major": "node ./scripts/changeset-explain-major.mjs"
|
||||
},
|
||||
"packageManager": "pnpm@8.1.0",
|
||||
"packageManager": "pnpm@8.6.12",
|
||||
"dependencies": {
|
||||
"@changesets/changelog-github": "^0.4.8",
|
||||
"@changesets/cli": "^2.26.2",
|
||||
|
||||
@@ -1,5 +1,56 @@
|
||||
# @thirdweb-dev/auth
|
||||
|
||||
## 3.2.29
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`73462ef1`](https://github.com/thirdweb-dev/js/commit/73462ef10800aeeb5976634e2bc6fb5d3e8501e4), [`70c4a119`](https://github.com/thirdweb-dev/js/commit/70c4a119d691a37ec999d9f6087902d532cc82ed)]:
|
||||
- @thirdweb-dev/wallets@1.1.12
|
||||
|
||||
## 3.2.28
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`4b0e63dc`](https://github.com/thirdweb-dev/js/commit/4b0e63dcc0ca871ce9cef76f8a41ff290316741c)]:
|
||||
- @thirdweb-dev/wallets@1.1.11
|
||||
|
||||
## 3.2.27
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1392](https://github.com/thirdweb-dev/js/pull/1392) [`dfd120a3`](https://github.com/thirdweb-dev/js/commit/dfd120a3a9d1582c8b174265c92bf43dbbaf5c86) Thanks [@adam-maj](https://github.com/adam-maj)! - Expose functions from auth and update useAuth
|
||||
|
||||
- Updated dependencies []:
|
||||
- @thirdweb-dev/wallets@1.1.10
|
||||
|
||||
## 3.2.26
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @thirdweb-dev/wallets@1.1.9
|
||||
|
||||
## 3.2.25
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`a9f2ff73`](https://github.com/thirdweb-dev/js/commit/a9f2ff73c9f83f05c3e2d3c53b23b2843e8a2576), [`fd981655`](https://github.com/thirdweb-dev/js/commit/fd9816556fe595b0c764e34dbcf15b0ad1677edb)]:
|
||||
- @thirdweb-dev/wallets@1.1.8
|
||||
|
||||
## 3.2.24
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`3b6b0746`](https://github.com/thirdweb-dev/js/commit/3b6b0746b3fc792f4c5092814a7abfabcbc9801e), [`b0ec1d80`](https://github.com/thirdweb-dev/js/commit/b0ec1d80839efccad11b50afbf2216c2c132cf7e)]:
|
||||
- @thirdweb-dev/wallets@1.1.7
|
||||
|
||||
## 3.2.23
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`fbde927a`](https://github.com/thirdweb-dev/js/commit/fbde927a0cb36a6269e045d8e577536f23164ef7)]:
|
||||
- @thirdweb-dev/wallets@1.1.6
|
||||
|
||||
## 3.2.22
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/auth",
|
||||
"version": "3.2.22",
|
||||
"version": "3.2.29",
|
||||
"main": "dist/thirdweb-dev-auth.cjs.js",
|
||||
"module": "dist/thirdweb-dev-auth.esm.js",
|
||||
"browser": {
|
||||
|
||||
+73
-423
@@ -1,28 +1,28 @@
|
||||
import {
|
||||
THIRDWEB_AUTH_DEFAULT_LOGIN_PAYLOAD_DURATION_IN_SECONDS,
|
||||
THIRDWEB_AUTH_DEFAULT_TOKEN_DURATION_IN_SECONDS,
|
||||
} from "../constants";
|
||||
authenticateJWT,
|
||||
generateJWT,
|
||||
parseJWT,
|
||||
refreshJWT,
|
||||
} from "./functions/jwt";
|
||||
import {
|
||||
LoginOptions,
|
||||
LoginPayload,
|
||||
GenerateOptions,
|
||||
LoginPayloadData,
|
||||
LoginPayloadDataSchema,
|
||||
AuthenticationPayloadDataSchema,
|
||||
AuthenticationPayloadData,
|
||||
VerifyOptionsSchema,
|
||||
VerifyOptions,
|
||||
GenerateOptionsSchema,
|
||||
AuthenticateOptionsSchema,
|
||||
AuthenticateOptions,
|
||||
User,
|
||||
Json,
|
||||
LoginOptionsSchema,
|
||||
AuthenticationPayload,
|
||||
AuthenticationPayloadDataInput,
|
||||
} from "./schema";
|
||||
import { isBrowser } from "./utils";
|
||||
buildAndSignLoginPayload,
|
||||
buildLoginPayload,
|
||||
signLoginPayload,
|
||||
verifyLoginPayload,
|
||||
} from "./functions/login";
|
||||
import type { GenericAuthWallet } from "@thirdweb-dev/wallets";
|
||||
import { Json, User } from "./schema/common";
|
||||
import {
|
||||
LoginOptionsWithOptionalDomain,
|
||||
LoginPayload,
|
||||
LoginPayloadData,
|
||||
} from "./schema/login";
|
||||
import { VerifyOptionsWithOptionalDomain } from "./schema/verify";
|
||||
import { GenerateOptionsWithOptionalDomain } from "./schema/generate";
|
||||
import {
|
||||
AuthenticateOptionsWithOptionalDomain,
|
||||
AuthenticationPayload,
|
||||
} from "./schema/authenticate";
|
||||
|
||||
export class ThirdwebAuth {
|
||||
private domain: string;
|
||||
@@ -37,432 +37,82 @@ export class ThirdwebAuth {
|
||||
this.wallet = wallet;
|
||||
}
|
||||
|
||||
public async payload(options?: LoginOptions): Promise<LoginPayloadData> {
|
||||
const parsedOptions = LoginOptionsSchema.parse(options);
|
||||
|
||||
let chainId: string | undefined = parsedOptions?.chainId;
|
||||
if (!chainId && this.wallet.getChainId) {
|
||||
try {
|
||||
chainId = (await this.wallet.getChainId()).toString();
|
||||
} catch {
|
||||
// ignore error
|
||||
}
|
||||
}
|
||||
|
||||
return LoginPayloadDataSchema.parse({
|
||||
type: this.wallet.type,
|
||||
domain: parsedOptions?.domain || this.domain,
|
||||
address: parsedOptions?.address || (await this.wallet.getAddress()),
|
||||
statement: parsedOptions?.statement,
|
||||
version: parsedOptions?.version,
|
||||
uri: parsedOptions?.uri,
|
||||
chain_id: chainId,
|
||||
nonce: parsedOptions?.nonce,
|
||||
expiration_time:
|
||||
parsedOptions?.expirationTime ||
|
||||
new Date(
|
||||
Date.now() +
|
||||
1000 * THIRDWEB_AUTH_DEFAULT_LOGIN_PAYLOAD_DURATION_IN_SECONDS,
|
||||
),
|
||||
invalid_before:
|
||||
parsedOptions?.invalidBefore ||
|
||||
new Date(
|
||||
Date.now() -
|
||||
1000 * THIRDWEB_AUTH_DEFAULT_LOGIN_PAYLOAD_DURATION_IN_SECONDS,
|
||||
),
|
||||
resources: parsedOptions?.resources,
|
||||
public async payload(
|
||||
options?: LoginOptionsWithOptionalDomain,
|
||||
): Promise<LoginPayloadData> {
|
||||
return buildLoginPayload({
|
||||
wallet: this.wallet,
|
||||
options: this.formatOptions(options),
|
||||
});
|
||||
}
|
||||
|
||||
public async loginWithPayload(
|
||||
payload: LoginPayloadData,
|
||||
): Promise<LoginPayload> {
|
||||
const message = this.generateMessage(payload);
|
||||
const signature = await this.wallet.signMessage(message);
|
||||
|
||||
return {
|
||||
payload,
|
||||
signature,
|
||||
};
|
||||
return signLoginPayload({ wallet: this.wallet, payload });
|
||||
}
|
||||
|
||||
public async login(options?: LoginOptions): Promise<LoginPayload> {
|
||||
const payloadData = await this.payload(options);
|
||||
return await this.loginWithPayload(payloadData);
|
||||
public async login(
|
||||
options?: LoginOptionsWithOptionalDomain,
|
||||
): Promise<LoginPayload> {
|
||||
return buildAndSignLoginPayload({
|
||||
wallet: this.wallet,
|
||||
options: this.formatOptions(options),
|
||||
});
|
||||
}
|
||||
|
||||
public async verify(
|
||||
payload: LoginPayload,
|
||||
options?: VerifyOptions,
|
||||
options?: VerifyOptionsWithOptionalDomain,
|
||||
): Promise<string> {
|
||||
const parsedOptions = VerifyOptionsSchema.parse(options);
|
||||
|
||||
if (payload.payload.type !== this.wallet.type) {
|
||||
throw new Error(
|
||||
`Expected chain type '${this.wallet.type}' does not match chain type on payload '${payload.payload.type}'`,
|
||||
);
|
||||
}
|
||||
|
||||
// Check that the intended domain matches the domain of the payload
|
||||
const domain = parsedOptions?.domain || this.domain;
|
||||
if (payload.payload.domain !== domain) {
|
||||
throw new Error(
|
||||
`Expected domain '${domain}' does not match domain on payload '${payload.payload.domain}'`,
|
||||
);
|
||||
}
|
||||
|
||||
// Check that the payload statement matches the expected statement
|
||||
if (parsedOptions?.statement) {
|
||||
if (payload.payload.statement !== parsedOptions.statement) {
|
||||
throw new Error(
|
||||
`Expected statement '${parsedOptions.statement}' does not match statement on payload '${payload.payload.statement}'`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the intended URI matches the URI of the payload
|
||||
if (parsedOptions?.uri) {
|
||||
if (payload.payload.uri !== parsedOptions.uri) {
|
||||
throw new Error(
|
||||
`Expected URI '${parsedOptions.uri}' does not match URI on payload '${payload.payload.uri}'`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the intended version matches the version of the payload
|
||||
if (parsedOptions?.version) {
|
||||
if (payload.payload.version !== parsedOptions.version) {
|
||||
throw new Error(
|
||||
`Expected version '${parsedOptions.version}' does not match version on payload '${payload.payload.version}'`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the intended chain ID matches the chain ID of the payload
|
||||
if (parsedOptions?.chainId) {
|
||||
if (payload.payload.chain_id !== parsedOptions.chainId) {
|
||||
throw new Error(
|
||||
`Expected chain ID '${parsedOptions.chainId}' does not match chain ID on payload '${payload.payload.chain_id}'`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the payload nonce is valid
|
||||
if (parsedOptions?.validateNonce !== undefined) {
|
||||
try {
|
||||
await parsedOptions.validateNonce(payload.payload.nonce);
|
||||
} catch (err) {
|
||||
throw new Error(`Login request nonce is invalid`);
|
||||
}
|
||||
}
|
||||
|
||||
// Check that it isn't before the invalid before time
|
||||
const currentTime = new Date();
|
||||
if (currentTime < new Date(payload.payload.invalid_before)) {
|
||||
throw new Error(`Login request is not yet valid`);
|
||||
}
|
||||
|
||||
// Check that the payload hasn't expired
|
||||
if (currentTime > new Date(payload.payload.expiration_time)) {
|
||||
throw new Error(`Login request has expired`);
|
||||
}
|
||||
|
||||
// Check that the specified resources are present on the payload
|
||||
if (parsedOptions?.resources) {
|
||||
const missingResources = parsedOptions.resources.filter(
|
||||
(resource) => !payload.payload.resources?.includes(resource),
|
||||
);
|
||||
if (missingResources.length > 0) {
|
||||
throw new Error(
|
||||
`Login request is missing required resources: ${missingResources.join(
|
||||
", ",
|
||||
)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the signing address is the claimed wallet address
|
||||
const message = this.generateMessage(payload.payload);
|
||||
const chainId =
|
||||
this.wallet.type === "evm" && payload.payload.chain_id
|
||||
? parseInt(payload.payload.chain_id)
|
||||
: undefined;
|
||||
const verified = await this.verifySignature(
|
||||
message,
|
||||
payload.signature,
|
||||
payload.payload.address,
|
||||
chainId,
|
||||
);
|
||||
if (!verified) {
|
||||
throw new Error(
|
||||
`Signer address does not match payload address '${payload.payload.address.toLowerCase()}'`,
|
||||
);
|
||||
}
|
||||
|
||||
return payload.payload.address;
|
||||
return verifyLoginPayload({
|
||||
wallet: this.wallet,
|
||||
payload,
|
||||
options: this.formatOptions(options),
|
||||
});
|
||||
}
|
||||
|
||||
public async generate(
|
||||
payload: LoginPayload,
|
||||
options?: GenerateOptions,
|
||||
options?: GenerateOptionsWithOptionalDomain,
|
||||
): Promise<string> {
|
||||
if (isBrowser()) {
|
||||
throw new Error(
|
||||
"Authentication tokens should not be generated in the browser, as they must be signed by a server-side admin wallet.",
|
||||
);
|
||||
}
|
||||
|
||||
const parsedOptions = GenerateOptionsSchema.parse(options);
|
||||
|
||||
const domain = parsedOptions?.domain || this.domain;
|
||||
const userAddress = await this.verify(payload, {
|
||||
domain,
|
||||
...parsedOptions?.verifyOptions,
|
||||
});
|
||||
|
||||
let session: Json | undefined = undefined;
|
||||
if (typeof parsedOptions?.session === "function") {
|
||||
const sessionTrigger = (await parsedOptions.session(userAddress)) as Json;
|
||||
if (sessionTrigger) {
|
||||
session = sessionTrigger;
|
||||
}
|
||||
} else {
|
||||
session = parsedOptions?.session;
|
||||
}
|
||||
|
||||
const adminAddress = await this.wallet.getAddress();
|
||||
return this.createToken({
|
||||
iss: adminAddress,
|
||||
sub: userAddress,
|
||||
aud: domain,
|
||||
nbf: parsedOptions?.invalidBefore || new Date(),
|
||||
exp:
|
||||
parsedOptions?.expirationTime ||
|
||||
new Date(
|
||||
Date.now() + 1000 * THIRDWEB_AUTH_DEFAULT_TOKEN_DURATION_IN_SECONDS,
|
||||
),
|
||||
iat: new Date(),
|
||||
jti: parsedOptions?.tokenId,
|
||||
ctx: session,
|
||||
});
|
||||
}
|
||||
|
||||
public async refresh(token: string, expirationTime?: Date): Promise<string> {
|
||||
const { payload } = this.parseToken(token);
|
||||
return this.createToken({
|
||||
iss: payload.iss,
|
||||
sub: payload.sub,
|
||||
aud: payload.aud,
|
||||
nbf: new Date(),
|
||||
exp:
|
||||
expirationTime ||
|
||||
new Date(
|
||||
Date.now() + 1000 * THIRDWEB_AUTH_DEFAULT_TOKEN_DURATION_IN_SECONDS,
|
||||
),
|
||||
iat: new Date(),
|
||||
ctx: payload.ctx,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate With Token
|
||||
* @remarks Server-side function that authenticates the provided JWT token. This function verifies that
|
||||
* the provided authentication token is valid and returns the address of the authenticated wallet.
|
||||
*
|
||||
* @param domain - The domain of the server-side application doing authentication
|
||||
* @param token - The authentication token being used
|
||||
* @returns The address of the authenticated wallet
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* const domain = "example.com";
|
||||
* const loginPayload = await sdk.auth.login(domain);
|
||||
* const token = await sdk.auth.generateAuthToken(domain, loginPayload);
|
||||
*
|
||||
* // Authenticate the token and get the address of authenticating users wallet
|
||||
* const address = sdk.auth.authenticate(domain, token);
|
||||
* ```
|
||||
*/
|
||||
public async authenticate<TSession extends Json = Json>(
|
||||
token: string,
|
||||
options?: AuthenticateOptions,
|
||||
): Promise<User<TSession>> {
|
||||
if (isBrowser()) {
|
||||
throw new Error(
|
||||
"Should not authenticate tokens in the browser, as they must be verified by the server-side admin wallet.",
|
||||
);
|
||||
}
|
||||
|
||||
const parsedOptions = AuthenticateOptionsSchema.parse(options);
|
||||
const domain = parsedOptions?.domain || this.domain;
|
||||
|
||||
const { payload, signature } = this.parseToken(token);
|
||||
|
||||
// Check that the payload unique ID is valid
|
||||
if (parsedOptions?.validateTokenId !== undefined) {
|
||||
try {
|
||||
await parsedOptions.validateTokenId(payload.jti);
|
||||
} catch (err) {
|
||||
throw new Error(`Token ID is invalid`);
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the token audience matches the domain
|
||||
if (payload.aud !== domain) {
|
||||
throw new Error(
|
||||
`Expected token to be for the domain '${domain}', but found token with domain '${payload.aud}'`,
|
||||
);
|
||||
}
|
||||
|
||||
// Check that the token is past the invalid before time
|
||||
const currentTime = Math.floor(new Date().getTime() / 1000);
|
||||
if (currentTime < payload.nbf) {
|
||||
throw new Error(
|
||||
`This token is invalid before epoch time '${payload.nbf}', current epoch time is '${currentTime}'`,
|
||||
);
|
||||
}
|
||||
|
||||
// Check that the token hasn't expired
|
||||
if (currentTime > payload.exp) {
|
||||
throw new Error(
|
||||
`This token expired at epoch time '${payload.exp}', current epoch time is '${currentTime}'`,
|
||||
);
|
||||
}
|
||||
|
||||
// Check that the connected wallet matches the token issuer
|
||||
const connectedAddress = await this.wallet.getAddress();
|
||||
if (connectedAddress.toLowerCase() !== payload.iss.toLowerCase()) {
|
||||
throw new Error(
|
||||
`Expected the connected wallet address '${connectedAddress}' to match the token issuer address '${payload.iss}'`,
|
||||
);
|
||||
}
|
||||
|
||||
let chainId: number | undefined = undefined;
|
||||
if (this.wallet.getChainId) {
|
||||
try {
|
||||
chainId = await this.wallet.getChainId();
|
||||
} catch {
|
||||
// ignore error
|
||||
}
|
||||
}
|
||||
|
||||
const verified = await this.verifySignature(
|
||||
JSON.stringify(payload),
|
||||
signature,
|
||||
connectedAddress,
|
||||
chainId,
|
||||
);
|
||||
if (!verified) {
|
||||
throw new Error(
|
||||
`The connected wallet address '${connectedAddress}' did not sign the token`,
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
address: payload.sub,
|
||||
session: payload.ctx as TSession | undefined,
|
||||
};
|
||||
}
|
||||
|
||||
public parseToken(token: string): AuthenticationPayload {
|
||||
const encodedPayload = token.split(".")[1];
|
||||
const encodedSignature = token.split(".")[2];
|
||||
const payload: AuthenticationPayloadData = JSON.parse(
|
||||
Buffer.from(encodedPayload, "base64").toString(),
|
||||
);
|
||||
const signature = Buffer.from(encodedSignature, "base64").toString();
|
||||
|
||||
return {
|
||||
return generateJWT({
|
||||
wallet: this.wallet,
|
||||
payload,
|
||||
signature,
|
||||
};
|
||||
options: this.formatOptions(options),
|
||||
});
|
||||
}
|
||||
|
||||
private async createToken(
|
||||
payload: AuthenticationPayloadDataInput,
|
||||
): Promise<string> {
|
||||
const payloadData = AuthenticationPayloadDataSchema.parse(payload);
|
||||
|
||||
const message = JSON.stringify(payloadData);
|
||||
const signature = await this.wallet.signMessage(message);
|
||||
|
||||
// Header used for JWT token specifying hash algorithm
|
||||
const header = {
|
||||
// Specify ECDSA with SHA-256 for hashing algorithm
|
||||
alg: "ES256",
|
||||
typ: "JWT",
|
||||
};
|
||||
|
||||
const encodedHeader = Buffer.from(JSON.stringify(header)).toString(
|
||||
"base64",
|
||||
);
|
||||
const encodedData = Buffer.from(JSON.stringify(payloadData))
|
||||
.toString("base64")
|
||||
.replace(/=/g, "");
|
||||
const encodedSignature = Buffer.from(signature).toString("base64");
|
||||
|
||||
// Generate a JWT token with base64 encoded header, payload, and signature
|
||||
const token = `${encodedHeader}.${encodedData}.${encodedSignature}`;
|
||||
|
||||
return token;
|
||||
public async refresh(jwt: string, expirationTime?: Date): Promise<string> {
|
||||
return refreshJWT({
|
||||
wallet: this.wallet,
|
||||
jwt,
|
||||
options: { expirationTime },
|
||||
});
|
||||
}
|
||||
|
||||
private async verifySignature(
|
||||
message: string,
|
||||
signature: string,
|
||||
address: string,
|
||||
chainId?: number,
|
||||
) {
|
||||
return this.wallet.verifySignature(message, signature, address, chainId);
|
||||
public async authenticate<TSession extends Json = Json>(
|
||||
jwt: string,
|
||||
options?: AuthenticateOptionsWithOptionalDomain,
|
||||
): Promise<User<TSession>> {
|
||||
return authenticateJWT({
|
||||
wallet: this.wallet,
|
||||
jwt,
|
||||
options: this.formatOptions(options),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a EIP-4361 & CAIP-122 compliant message to sign based on the login payload
|
||||
*/
|
||||
private 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";
|
||||
}
|
||||
public parseToken(jwt: string): AuthenticationPayload {
|
||||
return parseJWT(jwt);
|
||||
}
|
||||
|
||||
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");
|
||||
private formatOptions<TOptions extends { domain?: string }>(
|
||||
options?: TOptions,
|
||||
): Omit<TOptions, "domain"> & { domain: string } {
|
||||
return options
|
||||
? { ...options, domain: options?.domain || this.domain }
|
||||
: ({ domain: this.domain } as Omit<TOptions, "domain"> & {
|
||||
domain: string;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,226 @@
|
||||
import {
|
||||
AuthenticateOptionsSchema,
|
||||
AuthenticationPayload,
|
||||
AuthenticationPayloadData,
|
||||
AuthenticationPayloadDataSchema,
|
||||
} from "../schema/authenticate";
|
||||
import { Json, User } from "../schema/common";
|
||||
import {
|
||||
BuildJwtParams,
|
||||
RefreshJwtParams,
|
||||
GenerateJwtParams,
|
||||
AuthenticateJwtParams,
|
||||
} from "../schema/functions";
|
||||
import { GenerateOptionsSchema } from "../schema/generate";
|
||||
import { RefreshOptionsSchema } from "../schema/refresh";
|
||||
import { verifyLoginPayload } from "./login";
|
||||
|
||||
function isBrowser() {
|
||||
return typeof window !== "undefined";
|
||||
}
|
||||
|
||||
function base64encode(data: string): string {
|
||||
if (isBrowser()) {
|
||||
return window.btoa(data);
|
||||
}
|
||||
|
||||
return Buffer.from(data).toString("base64").replace(/=/g, "");
|
||||
}
|
||||
|
||||
function base64decode(data: string): string {
|
||||
if (isBrowser()) {
|
||||
return window.atob(data);
|
||||
}
|
||||
|
||||
return Buffer.from(data, "base64").toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Build JWT token based on the authentication payload
|
||||
*/
|
||||
async function buildJWT({ wallet, payload }: BuildJwtParams): Promise<string> {
|
||||
const payloadData = AuthenticationPayloadDataSchema.parse(payload);
|
||||
|
||||
const message = JSON.stringify(payloadData);
|
||||
const signature = await wallet.signMessage(message);
|
||||
|
||||
// Header used for JWT token specifying hash algorithm
|
||||
const header = {
|
||||
// Specify ECDSA with SHA-256 for hashing algorithm
|
||||
alg: "ES256",
|
||||
typ: "JWT",
|
||||
};
|
||||
|
||||
const encodedHeader = base64encode(JSON.stringify(header));
|
||||
const encodedData = base64encode(JSON.stringify(payloadData));
|
||||
const encodedSignature = base64encode(signature);
|
||||
|
||||
// Generate a JWT with base64 encoded header, payload, and signature
|
||||
const jwt = `${encodedHeader}.${encodedData}.${encodedSignature}`;
|
||||
|
||||
return jwt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a new JWT using a login payload
|
||||
*/
|
||||
export async function generateJWT({
|
||||
wallet,
|
||||
payload,
|
||||
options,
|
||||
}: GenerateJwtParams): Promise<string> {
|
||||
const parsedOptions = GenerateOptionsSchema.parse(options);
|
||||
const userAddress = await verifyLoginPayload({
|
||||
wallet,
|
||||
payload,
|
||||
options: {
|
||||
domain: parsedOptions.domain,
|
||||
...parsedOptions.verifyOptions,
|
||||
},
|
||||
});
|
||||
|
||||
let session: Json | undefined = undefined;
|
||||
if (typeof parsedOptions?.session === "function") {
|
||||
const sessionTrigger = (await parsedOptions.session(userAddress)) as Json;
|
||||
if (sessionTrigger) {
|
||||
session = sessionTrigger;
|
||||
}
|
||||
} else {
|
||||
session = parsedOptions?.session;
|
||||
}
|
||||
|
||||
const adminAddress = await wallet.getAddress();
|
||||
return buildJWT({
|
||||
wallet,
|
||||
payload: {
|
||||
iss: adminAddress,
|
||||
sub: userAddress,
|
||||
aud: parsedOptions.domain,
|
||||
nbf: parsedOptions?.invalidBefore || new Date(),
|
||||
exp: parsedOptions.expirationTime,
|
||||
iat: new Date(),
|
||||
jti: parsedOptions?.tokenId,
|
||||
ctx: session,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse data from an encoded auth JWT
|
||||
*/
|
||||
export function parseJWT(jwt: string): AuthenticationPayload {
|
||||
const encodedPayload = jwt.split(".")[1];
|
||||
const encodedSignature = jwt.split(".")[2];
|
||||
const payload: AuthenticationPayloadData = JSON.parse(
|
||||
base64decode(encodedPayload),
|
||||
);
|
||||
const signature = base64decode(encodedSignature);
|
||||
|
||||
return {
|
||||
payload,
|
||||
signature,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh an existing JWT
|
||||
*/
|
||||
export async function refreshJWT({
|
||||
wallet,
|
||||
jwt,
|
||||
options,
|
||||
}: RefreshJwtParams): Promise<string> {
|
||||
const { payload } = parseJWT(jwt);
|
||||
const parsedOptions = RefreshOptionsSchema.parse(options);
|
||||
return buildJWT({
|
||||
wallet,
|
||||
payload: {
|
||||
iss: payload.iss,
|
||||
sub: payload.sub,
|
||||
aud: payload.aud,
|
||||
nbf: new Date(),
|
||||
exp: parsedOptions.expirationTime,
|
||||
iat: new Date(),
|
||||
ctx: payload.ctx,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a JWT and extract the user's info
|
||||
*/
|
||||
export async function authenticateJWT<TSession extends Json = Json>({
|
||||
wallet,
|
||||
jwt,
|
||||
options,
|
||||
}: AuthenticateJwtParams): Promise<User<TSession>> {
|
||||
const parsedOptions = AuthenticateOptionsSchema.parse(options);
|
||||
const { payload, signature } = parseJWT(jwt);
|
||||
|
||||
// Check that the payload unique ID is valid
|
||||
if (parsedOptions?.validateTokenId !== undefined) {
|
||||
try {
|
||||
await parsedOptions.validateTokenId(payload.jti);
|
||||
} catch (err) {
|
||||
throw new Error(`Token ID is invalid`);
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the token audience matches the domain
|
||||
if (payload.aud !== parsedOptions.domain) {
|
||||
throw new Error(
|
||||
`Expected token to be for the domain '${parsedOptions.domain}', but found token with domain '${payload.aud}'`,
|
||||
);
|
||||
}
|
||||
|
||||
// Check that the token is past the invalid before time
|
||||
const currentTime = Math.floor(new Date().getTime() / 1000);
|
||||
if (currentTime < payload.nbf) {
|
||||
throw new Error(
|
||||
`This token is invalid before epoch time '${payload.nbf}', current epoch time is '${currentTime}'`,
|
||||
);
|
||||
}
|
||||
|
||||
// Check that the token hasn't expired
|
||||
if (currentTime > payload.exp) {
|
||||
throw new Error(
|
||||
`This token expired at epoch time '${payload.exp}', current epoch time is '${currentTime}'`,
|
||||
);
|
||||
}
|
||||
|
||||
// Check that the connected wallet matches the token issuer
|
||||
const issuerAddress = parsedOptions.issuerAddress
|
||||
? parsedOptions.issuerAddress
|
||||
: await wallet.getAddress();
|
||||
if (issuerAddress.toLowerCase() !== payload.iss.toLowerCase()) {
|
||||
throw new Error(
|
||||
`The expected issuer address '${issuerAddress}' did not match the token issuer address '${payload.iss}'`,
|
||||
);
|
||||
}
|
||||
|
||||
let chainId: number | undefined = undefined;
|
||||
if (wallet.getChainId) {
|
||||
try {
|
||||
chainId = await wallet.getChainId();
|
||||
} catch {
|
||||
// ignore error
|
||||
}
|
||||
}
|
||||
|
||||
const verified = await wallet.verifySignature(
|
||||
JSON.stringify(payload),
|
||||
signature,
|
||||
issuerAddress,
|
||||
chainId,
|
||||
);
|
||||
if (!verified) {
|
||||
throw new Error(
|
||||
`The expected signer address '${issuerAddress}' did not sign the token`,
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
address: payload.sub,
|
||||
session: payload.ctx as TSession | undefined,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
import {
|
||||
BuildLoginPayloadParams,
|
||||
SignLoginPayloadParams,
|
||||
VerifyLoginPayloadParams,
|
||||
} from "../schema/functions";
|
||||
import {
|
||||
LoginOptionsSchema,
|
||||
LoginPayload,
|
||||
LoginPayloadData,
|
||||
LoginPayloadDataSchema,
|
||||
} from "../schema/login";
|
||||
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 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");
|
||||
}
|
||||
|
||||
export async function buildLoginPayload({
|
||||
wallet,
|
||||
options,
|
||||
}: BuildLoginPayloadParams): Promise<LoginPayloadData> {
|
||||
const parsedOptions = LoginOptionsSchema.parse(options);
|
||||
|
||||
let chainId: string | undefined = parsedOptions?.chainId;
|
||||
if (!chainId && wallet.getChainId) {
|
||||
try {
|
||||
chainId = (await wallet.getChainId()).toString();
|
||||
} catch {
|
||||
// ignore error
|
||||
}
|
||||
}
|
||||
|
||||
return LoginPayloadDataSchema.parse({
|
||||
type: wallet.type,
|
||||
domain: parsedOptions.domain,
|
||||
address: parsedOptions?.address || (await wallet.getAddress()),
|
||||
statement: parsedOptions?.statement,
|
||||
version: parsedOptions?.version,
|
||||
uri: parsedOptions?.uri,
|
||||
chain_id: chainId,
|
||||
nonce: parsedOptions?.nonce,
|
||||
expiration_time: parsedOptions.expirationTime,
|
||||
invalid_before: parsedOptions.invalidBefore,
|
||||
resources: parsedOptions?.resources,
|
||||
});
|
||||
}
|
||||
|
||||
export async function signLoginPayload({
|
||||
wallet,
|
||||
payload,
|
||||
}: SignLoginPayloadParams): Promise<LoginPayload> {
|
||||
const message = createLoginMessage(payload);
|
||||
const signature = await wallet.signMessage(message);
|
||||
|
||||
return {
|
||||
payload,
|
||||
signature,
|
||||
};
|
||||
}
|
||||
|
||||
export async function buildAndSignLoginPayload({
|
||||
wallet,
|
||||
options,
|
||||
}: BuildLoginPayloadParams): Promise<LoginPayload> {
|
||||
const payload = await buildLoginPayload({ wallet, options });
|
||||
return signLoginPayload({ wallet, payload });
|
||||
}
|
||||
|
||||
export async function verifyLoginPayload({
|
||||
wallet,
|
||||
payload,
|
||||
options,
|
||||
}: VerifyLoginPayloadParams): Promise<string> {
|
||||
const parsedOptions = VerifyOptionsSchema.parse(options);
|
||||
|
||||
if (payload.payload.type !== wallet.type) {
|
||||
throw new Error(
|
||||
`Expected chain type '${wallet.type}' does not match chain type on payload '${payload.payload.type}'`,
|
||||
);
|
||||
}
|
||||
|
||||
// Check that the intended domain matches the domain of the payload
|
||||
if (payload.payload.domain !== parsedOptions.domain) {
|
||||
throw new Error(
|
||||
`Expected domain '${parsedOptions.domain}' does not match domain on payload '${payload.payload.domain}'`,
|
||||
);
|
||||
}
|
||||
|
||||
// Check that the payload statement matches the expected statement
|
||||
if (parsedOptions?.statement) {
|
||||
if (payload.payload.statement !== parsedOptions.statement) {
|
||||
throw new Error(
|
||||
`Expected statement '${parsedOptions.statement}' does not match statement on payload '${payload.payload.statement}'`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the intended URI matches the URI of the payload
|
||||
if (parsedOptions?.uri) {
|
||||
if (payload.payload.uri !== parsedOptions.uri) {
|
||||
throw new Error(
|
||||
`Expected URI '${parsedOptions.uri}' does not match URI on payload '${payload.payload.uri}'`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the intended version matches the version of the payload
|
||||
if (parsedOptions?.version) {
|
||||
if (payload.payload.version !== parsedOptions.version) {
|
||||
throw new Error(
|
||||
`Expected version '${parsedOptions.version}' does not match version on payload '${payload.payload.version}'`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the intended chain ID matches the chain ID of the payload
|
||||
if (parsedOptions?.chainId) {
|
||||
if (payload.payload.chain_id !== parsedOptions.chainId) {
|
||||
throw new Error(
|
||||
`Expected chain ID '${parsedOptions.chainId}' does not match chain ID on payload '${payload.payload.chain_id}'`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the payload nonce is valid
|
||||
if (parsedOptions?.validateNonce !== undefined) {
|
||||
try {
|
||||
await parsedOptions.validateNonce(payload.payload.nonce);
|
||||
} catch (err) {
|
||||
throw new Error(`Login request nonce is invalid`);
|
||||
}
|
||||
}
|
||||
|
||||
// Check that it isn't before the invalid before time
|
||||
const currentTime = new Date();
|
||||
if (currentTime < new Date(payload.payload.invalid_before)) {
|
||||
throw new Error(`Login request is not yet valid`);
|
||||
}
|
||||
|
||||
// Check that the payload hasn't expired
|
||||
if (currentTime > new Date(payload.payload.expiration_time)) {
|
||||
throw new Error(`Login request has expired`);
|
||||
}
|
||||
|
||||
// Check that the specified resources are present on the payload
|
||||
if (parsedOptions?.resources) {
|
||||
const missingResources = parsedOptions.resources.filter(
|
||||
(resource) => !payload.payload.resources?.includes(resource),
|
||||
);
|
||||
if (missingResources.length > 0) {
|
||||
throw new Error(
|
||||
`Login request is missing required resources: ${missingResources.join(
|
||||
", ",
|
||||
)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the signing address is the claimed wallet address
|
||||
const message = createLoginMessage(payload.payload);
|
||||
const chainId =
|
||||
wallet.type === "evm" && payload.payload.chain_id
|
||||
? parseInt(payload.payload.chain_id)
|
||||
: undefined;
|
||||
const verified = await wallet.verifySignature(
|
||||
message,
|
||||
payload.signature,
|
||||
payload.payload.address,
|
||||
chainId,
|
||||
);
|
||||
if (!verified) {
|
||||
throw new Error(
|
||||
`Signer address does not match payload address '${payload.payload.address.toLowerCase()}'`,
|
||||
);
|
||||
}
|
||||
|
||||
return payload.payload.address;
|
||||
}
|
||||
@@ -1,2 +1,25 @@
|
||||
// Export thirdweb auth class
|
||||
export { ThirdwebAuth } from "./auth";
|
||||
export * from "./schema";
|
||||
|
||||
// Export individual auth functions
|
||||
export {
|
||||
generateJWT,
|
||||
parseJWT,
|
||||
refreshJWT,
|
||||
authenticateJWT,
|
||||
} from "./functions/jwt";
|
||||
export {
|
||||
buildLoginPayload,
|
||||
signLoginPayload,
|
||||
buildAndSignLoginPayload,
|
||||
verifyLoginPayload,
|
||||
} from "./functions/login";
|
||||
|
||||
// Export schema files individually
|
||||
export * from "./schema/authenticate";
|
||||
export * from "./schema/common";
|
||||
export * from "./schema/functions";
|
||||
export * from "./schema/generate";
|
||||
export * from "./schema/login";
|
||||
export * from "./schema/refresh";
|
||||
export * from "./schema/verify";
|
||||
|
||||
@@ -1,216 +0,0 @@
|
||||
import { utils, BigNumber } from "ethers";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { z } from "zod";
|
||||
|
||||
export const AddressSchema = z.string().refine(
|
||||
(arg) => utils.isAddress(arg),
|
||||
(out) => {
|
||||
return {
|
||||
message: `${out} is not a valid address`,
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
export const RawDateSchema = z.date().transform((i) => {
|
||||
return BigNumber.from(Math.floor(i.getTime() / 1000));
|
||||
});
|
||||
|
||||
export const AccountTypeSchema = z.union([
|
||||
z.literal("evm"),
|
||||
z.literal("solana"),
|
||||
]);
|
||||
|
||||
const literalSchema = z.union([z.string(), z.number(), z.boolean(), z.null()]);
|
||||
type Literal = z.infer<typeof literalSchema>;
|
||||
export type Json = Literal | { [key: string]: Json } | Json[];
|
||||
const JsonSchema: z.ZodType<Json> = z.lazy(
|
||||
() => z.union([literalSchema, z.array(JsonSchema), z.record(JsonSchema)]),
|
||||
{ invalid_type_error: "Provided value was not valid JSON" },
|
||||
);
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export const LoginOptionsSchema = z
|
||||
.object({
|
||||
domain: z.string().optional(),
|
||||
address: z.string().optional(),
|
||||
statement: z.string().optional(),
|
||||
uri: z.string().optional(),
|
||||
version: z.string().optional(),
|
||||
chainId: z.string().optional(),
|
||||
nonce: z.string().optional(),
|
||||
expirationTime: z.date().optional(),
|
||||
invalidBefore: z.date().optional(),
|
||||
resources: z.array(z.string()).optional(),
|
||||
})
|
||||
.optional();
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export const LoginPayloadDataSchema = z.object({
|
||||
type: AccountTypeSchema,
|
||||
domain: z.string(),
|
||||
address: z.string(),
|
||||
statement: z
|
||||
.string()
|
||||
.default(
|
||||
"Please ensure that the domain above matches the URL of the current website.",
|
||||
),
|
||||
uri: z.string().optional(),
|
||||
version: z.string().default("1"),
|
||||
chain_id: z.string().optional(),
|
||||
nonce: z.string().default(uuidv4()),
|
||||
issued_at: z
|
||||
.date()
|
||||
.default(new Date())
|
||||
.transform((d) => d.toISOString()),
|
||||
expiration_time: z.date().transform((d) => d.toISOString()),
|
||||
invalid_before: z
|
||||
.date()
|
||||
.default(new Date())
|
||||
.transform((d) => d.toISOString()),
|
||||
resources: z.array(z.string()).optional(),
|
||||
});
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export const LoginPayloadSchema = z.object({
|
||||
payload: LoginPayloadDataSchema,
|
||||
signature: z.string(),
|
||||
});
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
const VerifyOptionsSchemaRequired = z.object({
|
||||
domain: z.string().optional(),
|
||||
statement: z.string().optional(),
|
||||
uri: z.string().optional(),
|
||||
version: z.string().optional(),
|
||||
chainId: z.string().optional(),
|
||||
validateNonce: z.function().args(z.string()).optional(),
|
||||
resources: z.array(z.string()).optional(),
|
||||
});
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export const VerifyOptionsSchema = VerifyOptionsSchemaRequired.optional();
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export const GenerateOptionsSchema = z
|
||||
.object({
|
||||
domain: z.string().optional(),
|
||||
tokenId: z.string().optional(),
|
||||
expirationTime: z.date().optional(),
|
||||
invalidBefore: z.date().optional(),
|
||||
session: z.union([JsonSchema, z.function().args(z.string())]).optional(),
|
||||
verifyOptions: VerifyOptionsSchemaRequired.omit({
|
||||
domain: true,
|
||||
}).optional(),
|
||||
})
|
||||
.optional();
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export const AuthenticationPayloadDataSchema = z.object({
|
||||
iss: z.string(),
|
||||
sub: z.string(),
|
||||
aud: z.string(),
|
||||
exp: RawDateSchema.transform((b) => b.toNumber()),
|
||||
nbf: RawDateSchema.transform((b) => b.toNumber()),
|
||||
iat: RawDateSchema.transform((b) => b.toNumber()),
|
||||
jti: z.string().default(uuidv4()),
|
||||
ctx: JsonSchema.optional(),
|
||||
});
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export const AuthenticationPayloadSchema = z.object({
|
||||
payload: AuthenticationPayloadDataSchema,
|
||||
signature: z.string(),
|
||||
});
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export const AuthenticateOptionsSchema = z
|
||||
.object({
|
||||
domain: z.string().optional(),
|
||||
validateTokenId: z.function().args(z.string()).optional(),
|
||||
})
|
||||
.optional();
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type LoginOptions = z.input<typeof LoginOptionsSchema>;
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type LoginPayloadData = z.output<typeof LoginPayloadDataSchema>;
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type LoginPayload = z.output<typeof LoginPayloadSchema>;
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type VerifyOptions = z.input<typeof VerifyOptionsSchema>;
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type GenerateOptions = z.input<typeof GenerateOptionsSchema>;
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type AuthenticationPayloadData = z.output<
|
||||
typeof AuthenticationPayloadDataSchema
|
||||
>;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export type AuthenticationPayloadDataInput = z.input<
|
||||
typeof AuthenticationPayloadDataSchema
|
||||
>;
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type AuthenticationPayload = z.output<
|
||||
typeof AuthenticationPayloadSchema
|
||||
>;
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type AuthenticateOptions = z.output<typeof AuthenticateOptionsSchema>;
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type User<TContext extends Json = Json> = {
|
||||
address: string;
|
||||
session?: TContext;
|
||||
};
|
||||
|
||||
export const LoginPayloadOutputSchema = LoginPayloadSchema.extend({
|
||||
payload: LoginPayloadDataSchema.extend({
|
||||
issued_at: z.string(),
|
||||
expiration_time: z.string(),
|
||||
invalid_before: z.string(),
|
||||
}),
|
||||
});
|
||||
@@ -0,0 +1,46 @@
|
||||
import { z } from "zod";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { AddressSchema, JsonSchema, RawDateSchema } from "./common";
|
||||
|
||||
export const AuthenticationPayloadDataSchema = z.object({
|
||||
iss: z.string(),
|
||||
sub: z.string(),
|
||||
aud: z.string(),
|
||||
exp: RawDateSchema,
|
||||
nbf: RawDateSchema,
|
||||
iat: RawDateSchema,
|
||||
jti: z.string().default(uuidv4()),
|
||||
ctx: JsonSchema.optional(),
|
||||
});
|
||||
|
||||
export const AuthenticationPayloadSchema = z.object({
|
||||
payload: AuthenticationPayloadDataSchema,
|
||||
signature: z.string(),
|
||||
});
|
||||
|
||||
export const AuthenticateOptionsSchema = z.object({
|
||||
domain: z.string(),
|
||||
issuerAddress: AddressSchema.optional(),
|
||||
validateTokenId: z.function().args(z.string()).optional(),
|
||||
});
|
||||
|
||||
export type AuthenticationPayloadDataInput = z.input<
|
||||
typeof AuthenticationPayloadDataSchema
|
||||
>;
|
||||
|
||||
export type AuthenticationPayloadData = z.output<
|
||||
typeof AuthenticationPayloadDataSchema
|
||||
>;
|
||||
|
||||
export type AuthenticationPayload = z.output<
|
||||
typeof AuthenticationPayloadSchema
|
||||
>;
|
||||
|
||||
export type AuthenticateOptions = z.output<typeof AuthenticateOptionsSchema>;
|
||||
|
||||
export type AuthenticateOptionsWithOptionalDomain = Omit<
|
||||
AuthenticateOptions,
|
||||
"domain"
|
||||
> & {
|
||||
domain?: string;
|
||||
};
|
||||
@@ -0,0 +1,34 @@
|
||||
import { utils } from "ethers";
|
||||
import { z } from "zod";
|
||||
|
||||
const literalSchema = z.union([z.string(), z.number(), z.boolean(), z.null()]);
|
||||
type Literal = z.infer<typeof literalSchema>;
|
||||
export type Json = Literal | { [key: string]: Json } | Json[];
|
||||
|
||||
export const JsonSchema: z.ZodType<Json> = z.lazy(
|
||||
() => z.union([literalSchema, z.array(JsonSchema), z.record(JsonSchema)]),
|
||||
{ invalid_type_error: "Provided value was not valid JSON" },
|
||||
);
|
||||
|
||||
export const AddressSchema = z.string().refine(
|
||||
(arg) => utils.isAddress(arg),
|
||||
(out) => {
|
||||
return {
|
||||
message: `${out} is not a valid address`,
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
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 type User<TContext extends Json = Json> = {
|
||||
address: string;
|
||||
session?: TContext;
|
||||
};
|
||||
@@ -0,0 +1,48 @@
|
||||
import { GenericAuthWallet } from "@thirdweb-dev/wallets";
|
||||
import { LoginOptions, LoginPayload, LoginPayloadData } from "./login";
|
||||
import { VerifyOptions } from "./verify";
|
||||
import {
|
||||
AuthenticateOptions,
|
||||
AuthenticationPayloadDataInput,
|
||||
} from "./authenticate";
|
||||
import { RefreshOptions } from "./refresh";
|
||||
import { GenerateOptions } from "./generate";
|
||||
|
||||
export type BuildLoginPayloadParams = {
|
||||
wallet: GenericAuthWallet;
|
||||
options: LoginOptions;
|
||||
};
|
||||
|
||||
export type SignLoginPayloadParams = {
|
||||
wallet: GenericAuthWallet;
|
||||
payload: LoginPayloadData;
|
||||
};
|
||||
|
||||
export type VerifyLoginPayloadParams = {
|
||||
wallet: GenericAuthWallet;
|
||||
payload: LoginPayload;
|
||||
options: VerifyOptions;
|
||||
};
|
||||
|
||||
export type BuildJwtParams = {
|
||||
wallet: GenericAuthWallet;
|
||||
payload: AuthenticationPayloadDataInput;
|
||||
};
|
||||
|
||||
export type GenerateJwtParams = {
|
||||
wallet: GenericAuthWallet;
|
||||
payload: LoginPayload;
|
||||
options: GenerateOptions;
|
||||
};
|
||||
|
||||
export type RefreshJwtParams = {
|
||||
wallet: GenericAuthWallet;
|
||||
jwt: string;
|
||||
options?: RefreshOptions;
|
||||
};
|
||||
|
||||
export type AuthenticateJwtParams = {
|
||||
wallet: GenericAuthWallet;
|
||||
jwt: string;
|
||||
options: AuthenticateOptions;
|
||||
};
|
||||
@@ -0,0 +1,31 @@
|
||||
import { z } from "zod";
|
||||
import { VerifyOptionsSchema } from "./verify";
|
||||
import { JsonSchema } from "./common";
|
||||
import { THIRDWEB_AUTH_DEFAULT_TOKEN_DURATION_IN_SECONDS } from "../../constants";
|
||||
|
||||
export const GenerateOptionsSchema = z.object({
|
||||
domain: z.string(),
|
||||
tokenId: z.string().optional(),
|
||||
expirationTime: z
|
||||
.date()
|
||||
.default(
|
||||
() =>
|
||||
new Date(
|
||||
Date.now() + 1000 * THIRDWEB_AUTH_DEFAULT_TOKEN_DURATION_IN_SECONDS,
|
||||
),
|
||||
),
|
||||
invalidBefore: z.date().optional(),
|
||||
session: z.union([JsonSchema, z.function().args(z.string())]).optional(),
|
||||
verifyOptions: VerifyOptionsSchema.omit({
|
||||
domain: true,
|
||||
}).optional(),
|
||||
});
|
||||
|
||||
export type GenerateOptions = z.input<typeof GenerateOptionsSchema>;
|
||||
|
||||
export type GenerateOptionsWithOptionalDomain = Omit<
|
||||
GenerateOptions,
|
||||
"domain"
|
||||
> & {
|
||||
domain?: string;
|
||||
};
|
||||
@@ -0,0 +1,81 @@
|
||||
import { z } from "zod";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { AccountTypeSchema } from "./common";
|
||||
import { THIRDWEB_AUTH_DEFAULT_LOGIN_PAYLOAD_DURATION_IN_SECONDS } from "../../constants";
|
||||
|
||||
export const LoginOptionsSchema = z.object({
|
||||
domain: z.string(),
|
||||
address: z.string().optional(),
|
||||
statement: z.string().optional(),
|
||||
uri: z.string().optional(),
|
||||
version: z.string().optional(),
|
||||
chainId: z.string().optional(),
|
||||
nonce: z.string().optional(),
|
||||
expirationTime: z
|
||||
.date()
|
||||
.default(
|
||||
() =>
|
||||
new Date(
|
||||
Date.now() +
|
||||
1000 * THIRDWEB_AUTH_DEFAULT_LOGIN_PAYLOAD_DURATION_IN_SECONDS,
|
||||
),
|
||||
),
|
||||
invalidBefore: z
|
||||
.date()
|
||||
.default(
|
||||
() =>
|
||||
new Date(
|
||||
Date.now() -
|
||||
1000 * THIRDWEB_AUTH_DEFAULT_LOGIN_PAYLOAD_DURATION_IN_SECONDS,
|
||||
),
|
||||
),
|
||||
resources: z.array(z.string()).optional(),
|
||||
});
|
||||
|
||||
export const LoginPayloadDataSchema = z.object({
|
||||
type: AccountTypeSchema,
|
||||
domain: z.string(),
|
||||
address: z.string(),
|
||||
statement: z
|
||||
.string()
|
||||
.default(
|
||||
"Please ensure that the domain above matches the URL of the current website.",
|
||||
),
|
||||
uri: z.string().optional(),
|
||||
version: z.string().default("1"),
|
||||
chain_id: z.string().optional(),
|
||||
nonce: z.string().default(uuidv4()),
|
||||
issued_at: z
|
||||
.date()
|
||||
.default(new Date())
|
||||
.transform((d) => d.toISOString()),
|
||||
expiration_time: z.date().transform((d) => d.toISOString()),
|
||||
invalid_before: z
|
||||
.date()
|
||||
.default(new Date())
|
||||
.transform((d) => d.toISOString()),
|
||||
resources: z.array(z.string()).optional(),
|
||||
});
|
||||
|
||||
export const LoginPayloadSchema = z.object({
|
||||
payload: LoginPayloadDataSchema,
|
||||
signature: z.string(),
|
||||
});
|
||||
|
||||
export const LoginPayloadOutputSchema = LoginPayloadSchema.extend({
|
||||
payload: LoginPayloadDataSchema.extend({
|
||||
issued_at: z.string(),
|
||||
expiration_time: z.string(),
|
||||
invalid_before: z.string(),
|
||||
}),
|
||||
});
|
||||
|
||||
export type LoginOptions = z.input<typeof LoginOptionsSchema>;
|
||||
|
||||
export type LoginPayloadData = z.output<typeof LoginPayloadDataSchema>;
|
||||
|
||||
export type LoginPayload = z.output<typeof LoginPayloadSchema>;
|
||||
|
||||
export type LoginOptionsWithOptionalDomain = Omit<LoginOptions, "domain"> & {
|
||||
domain?: string;
|
||||
};
|
||||
@@ -0,0 +1,15 @@
|
||||
import { z } from "zod";
|
||||
import { THIRDWEB_AUTH_DEFAULT_TOKEN_DURATION_IN_SECONDS } from "../../constants";
|
||||
|
||||
export const RefreshOptionsSchema = z.object({
|
||||
expirationTime: z
|
||||
.date()
|
||||
.default(
|
||||
() =>
|
||||
new Date(
|
||||
Date.now() + 1000 * THIRDWEB_AUTH_DEFAULT_TOKEN_DURATION_IN_SECONDS,
|
||||
),
|
||||
),
|
||||
});
|
||||
|
||||
export type RefreshOptions = z.input<typeof RefreshOptionsSchema>;
|
||||
@@ -0,0 +1,17 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export const VerifyOptionsSchema = z.object({
|
||||
domain: z.string(),
|
||||
statement: z.string().optional(),
|
||||
uri: z.string().optional(),
|
||||
version: z.string().optional(),
|
||||
chainId: z.string().optional(),
|
||||
validateNonce: z.function().args(z.string()).optional(),
|
||||
resources: z.array(z.string()).optional(),
|
||||
});
|
||||
|
||||
export type VerifyOptions = z.input<typeof VerifyOptionsSchema>;
|
||||
|
||||
export type VerifyOptionsWithOptionalDomain = Omit<VerifyOptions, "domain"> & {
|
||||
domain?: string;
|
||||
};
|
||||
@@ -1,9 +0,0 @@
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export const isBrowser = () => typeof window !== "undefined";
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export const isNode = () => !isBrowser();
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ThirdwebAuth } from "../../core";
|
||||
import { Json, LoginPayloadOutputSchema, User } from "../../core/schema";
|
||||
import { Json, LoginPayloadOutputSchema, User } from "../../core";
|
||||
import type { GenericAuthWallet } from "@thirdweb-dev/wallets";
|
||||
import { Request } from "express";
|
||||
import { z } from "zod";
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { ThirdwebAuth } from "../../core";
|
||||
import { Json, LoginPayloadOutputSchema, User } from "../../core/schema";
|
||||
import { Json, LoginPayloadOutputSchema, ThirdwebAuth, User } from "../../core";
|
||||
import type { GenericAuthWallet } from "@thirdweb-dev/wallets";
|
||||
import { GetServerSidePropsContext, NextApiRequest } from "next";
|
||||
import { NextRequest } from "next/server";
|
||||
|
||||
@@ -3,7 +3,7 @@ import { EthersWallet } from "@thirdweb-dev/wallets/evm/wallets/ethers";
|
||||
import { expect } from "chai";
|
||||
import { Wallet } from "ethers";
|
||||
|
||||
describe("Wallet Authentication", async () => {
|
||||
describe("Wallet Authentication - EVM", async () => {
|
||||
let adminWallet: any, signerWallet: any, attackerWallet: any;
|
||||
let auth: ThirdwebAuth;
|
||||
|
||||
@@ -272,7 +272,7 @@ describe("Wallet Authentication", async () => {
|
||||
expect.fail();
|
||||
} catch (err: any) {
|
||||
expect(err.message).to.contain(
|
||||
`Expected the connected wallet address '${await signerWallet.getAddress()}' to match the token issuer address '${await adminWallet.getAddress()}'`,
|
||||
`The expected issuer address '${await signerWallet.getAddress()}' did not match the token issuer address '${await adminWallet.getAddress()}'`,
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -350,4 +350,24 @@ describe("Wallet Authentication", async () => {
|
||||
role: "admin",
|
||||
});
|
||||
});
|
||||
|
||||
it("Should authenticate with issuer address", async () => {
|
||||
const payload = await auth.login();
|
||||
|
||||
auth.updateWallet(adminWallet);
|
||||
const token = await auth.generate(payload);
|
||||
|
||||
auth.updateWallet(attackerWallet);
|
||||
try {
|
||||
await auth.authenticate(token);
|
||||
expect.fail();
|
||||
} catch (err: any) {
|
||||
expect(err.message).to.contain("The expected issuer address");
|
||||
}
|
||||
|
||||
const user = await auth.authenticate(token, {
|
||||
issuerAddress: await adminWallet.getAddress(),
|
||||
});
|
||||
expect(user.address).to.equal(await signerWallet.getAddress());
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Keypair } from "@solana/web3.js";
|
||||
import { KeypairWallet } from "@thirdweb-dev/wallets/solana/wallets/keypair";
|
||||
import { expect } from "chai";
|
||||
|
||||
describe("Wallet Authentication", async () => {
|
||||
describe("Wallet Authentication - Solana", async () => {
|
||||
let adminWallet: any, signerWallet: any, attackerWallet: any;
|
||||
let auth: ThirdwebAuth;
|
||||
|
||||
@@ -272,7 +272,7 @@ describe("Wallet Authentication", async () => {
|
||||
expect.fail();
|
||||
} catch (err: any) {
|
||||
expect(err.message).to.contain(
|
||||
`Expected the connected wallet address '${await signerWallet.getAddress()}' to match the token issuer address '${await adminWallet.getAddress()}'`,
|
||||
`The expected issuer address '${await signerWallet.getAddress()}' did not match the token issuer address '${await adminWallet.getAddress()}'`,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,5 +1,31 @@
|
||||
# @thirdweb-dev/chains
|
||||
|
||||
## 0.1.43
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1469](https://github.com/thirdweb-dev/js/pull/1469) [`cb1c9937`](https://github.com/thirdweb-dev/js/commit/cb1c9937fadb2d06eb148cf9819f2b3601376308) Thanks [@jnsdls](https://github.com/jnsdls)! - update chains
|
||||
|
||||
- [#1474](https://github.com/thirdweb-dev/js/pull/1474) [`a1732663`](https://github.com/thirdweb-dev/js/commit/a17326634e758c3bf42f0cc3869b8792f1e18cc9) Thanks [@adam-maj](https://github.com/adam-maj)! - Add back scroll-alpha-testnet
|
||||
|
||||
- [#1458](https://github.com/thirdweb-dev/js/pull/1458) [`588b2106`](https://github.com/thirdweb-dev/js/commit/588b21060139a7c0bf5805e2c629a16792ed2c76) Thanks [@kien-ngo](https://github.com/kien-ngo)! - Update chains
|
||||
|
||||
- [#1461](https://github.com/thirdweb-dev/js/pull/1461) [`269e68c0`](https://github.com/thirdweb-dev/js/commit/269e68c0a15e8f78cb5b68c9456ca8094b9e1f30) Thanks [@0xFirekeeper](https://github.com/0xFirekeeper)! - add xai-goerli chain and support BigInteger from Unity
|
||||
|
||||
## 0.1.42
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1450](https://github.com/thirdweb-dev/js/pull/1450) [`262edc6a`](https://github.com/thirdweb-dev/js/commit/262edc6a46792da88f49ff6ef0a756a932a6a0cf) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - update chains
|
||||
|
||||
## 0.1.41
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1436](https://github.com/thirdweb-dev/js/pull/1436) [`fd981655`](https://github.com/thirdweb-dev/js/commit/fd9816556fe595b0c764e34dbcf15b0ad1677edb) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Updated chains
|
||||
|
||||
- [#1432](https://github.com/thirdweb-dev/js/pull/1432) [`9f5adc5c`](https://github.com/thirdweb-dev/js/commit/9f5adc5c5c2782ffb878759df481e5fb1e1740e5) Thanks [@jnsdls](https://github.com/jnsdls)! - update chains
|
||||
|
||||
## 0.1.40
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -3,7 +3,7 @@ export default {
|
||||
"name": "Ultron Testnet",
|
||||
"chain": "Ultron",
|
||||
"icon": {
|
||||
"url": "ipfs://QmS4W4kY7XYBA4f52vuuytXh3YaTcNBXF14V9tEY6SNqhz",
|
||||
"url": "ipfs://QmPC6odFVyAQrXJQaZJVFpEQfRNbzZ5BjDZ7KBKmXPaYDw",
|
||||
"width": 512,
|
||||
"height": 512,
|
||||
"format": "png"
|
||||
@@ -27,7 +27,7 @@ export default {
|
||||
"name": "Ultron Testnet Explorer",
|
||||
"url": "https://explorer.ultron-dev.io",
|
||||
"icon": {
|
||||
"url": "ipfs://QmS4W4kY7XYBA4f52vuuytXh3YaTcNBXF14V9tEY6SNqhz",
|
||||
"url": "ipfs://QmPC6odFVyAQrXJQaZJVFpEQfRNbzZ5BjDZ7KBKmXPaYDw",
|
||||
"width": 512,
|
||||
"height": 512,
|
||||
"format": "png"
|
||||
|
||||
@@ -3,7 +3,7 @@ export default {
|
||||
"name": "Ultron Mainnet",
|
||||
"chain": "Ultron",
|
||||
"icon": {
|
||||
"url": "ipfs://QmS4W4kY7XYBA4f52vuuytXh3YaTcNBXF14V9tEY6SNqhz",
|
||||
"url": "ipfs://QmPC6odFVyAQrXJQaZJVFpEQfRNbzZ5BjDZ7KBKmXPaYDw",
|
||||
"width": 512,
|
||||
"height": 512,
|
||||
"format": "png"
|
||||
@@ -27,7 +27,7 @@ export default {
|
||||
"name": "Ultron Explorer",
|
||||
"url": "https://ulxscan.com",
|
||||
"icon": {
|
||||
"url": "ipfs://QmS4W4kY7XYBA4f52vuuytXh3YaTcNBXF14V9tEY6SNqhz",
|
||||
"url": "ipfs://QmPC6odFVyAQrXJQaZJVFpEQfRNbzZ5BjDZ7KBKmXPaYDw",
|
||||
"width": 512,
|
||||
"height": 512,
|
||||
"format": "png"
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Credit Smartchain Mainnet",
|
||||
"name": "Credit Smart Chain",
|
||||
"chain": "CREDIT",
|
||||
"rpc": [
|
||||
"https://credit-smartchain.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://mainnet-rpc.cscscan.io"
|
||||
"https://credit-smart-chain.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc.creditsmartchain.com"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
@@ -23,7 +23,7 @@ export default {
|
||||
"infoURL": "https://creditsmartchain.com",
|
||||
"shortName": "Credit",
|
||||
"chainId": 13308,
|
||||
"networkId": 1,
|
||||
"networkId": 13308,
|
||||
"icon": {
|
||||
"url": "ipfs://bafkreifbso3gd4wu5wxl27xyurxctmuae2jyuy37guqtzx23nga6ba4ag4",
|
||||
"width": 1000,
|
||||
@@ -32,8 +32,8 @@ export default {
|
||||
},
|
||||
"explorers": [
|
||||
{
|
||||
"name": "CSC Scan",
|
||||
"url": "https://explorer.cscscan.io",
|
||||
"name": "Creditscan",
|
||||
"url": "https://scan.creditsmartchain.com",
|
||||
"icon": {
|
||||
"url": "ipfs://bafkreifbso3gd4wu5wxl27xyurxctmuae2jyuy37guqtzx23nga6ba4ag4",
|
||||
"width": 1000,
|
||||
@@ -44,5 +44,5 @@ export default {
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "credit-smartchain"
|
||||
"slug": "credit-smart-chain"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,33 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Beam Testnet",
|
||||
"chain": "BEAM",
|
||||
"rpc": [
|
||||
"https://beam-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://subnets.avax.network/beam/testnet/rpc"
|
||||
],
|
||||
"features": [
|
||||
{
|
||||
"name": "EIP1559"
|
||||
}
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "Merit Circle",
|
||||
"symbol": "MC",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://gaming.meritcircle.io",
|
||||
"shortName": "BEAM",
|
||||
"chainId": 13337,
|
||||
"networkId": 13337,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Beam Explorer",
|
||||
"url": "https://subnets-test.avax.network/beam",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": true,
|
||||
"slug": "beam-testnet"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,40 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Kalar Chain",
|
||||
"chain": "KLC",
|
||||
"icon": {
|
||||
"url": "ipfs://bafkreihfoy2kgf2rebaoicso7z5h7ju46z6gtr64mskkths3qbfkrtnkjm",
|
||||
"width": 190,
|
||||
"height": 170,
|
||||
"format": "png"
|
||||
},
|
||||
"rpc": [
|
||||
"https://kalar-chain.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc-api.kalarchain.tech"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "Kalar",
|
||||
"symbol": "KLC",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://kalarchain.tech",
|
||||
"shortName": "KLC",
|
||||
"chainId": 1379,
|
||||
"networkId": 1379,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "kalarscan",
|
||||
"url": "https://explorer.kalarchain.tech",
|
||||
"icon": {
|
||||
"url": "ipfs://bafkreidbzzv3lrwlzquhlpl4jcmr54sifhi5ufoek6olb5kjh3h3kvktdq",
|
||||
"width": 411,
|
||||
"height": 159,
|
||||
"format": "png"
|
||||
},
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "kalar-chain"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,24 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Humanode Testnet 5 Israfel",
|
||||
"chain": "Humanode Testnet 5",
|
||||
"rpc": [
|
||||
"https://humanode-testnet-5-israfel.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://explorer-rpc-http.testnet5.stages.humanode.io"
|
||||
],
|
||||
"faucets": [
|
||||
"https://t.me/HumanodeTestnet5FaucetBot"
|
||||
],
|
||||
"nativeCurrency": {
|
||||
"name": "HMND",
|
||||
"symbol": "HMND",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://humanode.io",
|
||||
"shortName": "hmnd-t5",
|
||||
"chainId": 14853,
|
||||
"networkId": 14853,
|
||||
"explorers": [],
|
||||
"testnet": true,
|
||||
"slug": "humanode-testnet-5-israfel"
|
||||
} as const satisfies Chain;
|
||||
@@ -5,17 +5,23 @@ export default {
|
||||
"rpc": [
|
||||
"https://harmony-shard-0.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://api.harmony.one",
|
||||
"https://api.s0.t.hmny.io"
|
||||
],
|
||||
"faucets": [
|
||||
"https://free-online-app.com/faucet-for-eth-evm-chains/"
|
||||
"https://a.api.s0.t.hmny.io",
|
||||
"https://api.s0.t.hmny.io",
|
||||
"https://rpc.ankr.com/harmony",
|
||||
"https://harmony.api.onfinality.io/public",
|
||||
"https://1rpc.io/one"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "ONE",
|
||||
"symbol": "ONE",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://www.harmony.one/",
|
||||
"slip44": 1023,
|
||||
"ens": {
|
||||
"registry": "0x4cd2563118e57b19179d8dc033f2b0c5b5d69ff5"
|
||||
},
|
||||
"shortName": "hmy-s0",
|
||||
"chainId": 1666600000,
|
||||
"networkId": 1666600000,
|
||||
|
||||
@@ -13,9 +13,17 @@ export default {
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://www.harmony.one/",
|
||||
"slip44": 1023,
|
||||
"shortName": "hmy-s1",
|
||||
"chainId": 1666600001,
|
||||
"networkId": 1666600001,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Harmony Block Explorer",
|
||||
"url": "https://explorer.harmony.one/blocks/shard/1",
|
||||
"standard": "none"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "harmony-shard-1"
|
||||
} as const satisfies Chain;
|
||||
@@ -13,9 +13,17 @@ export default {
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://www.harmony.one/",
|
||||
"slip44": 1023,
|
||||
"shortName": "hmy-s2",
|
||||
"chainId": 1666600002,
|
||||
"networkId": 1666600002,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Harmony Block Explorer",
|
||||
"url": "https://explorer.harmony.one/blocks/shard/2",
|
||||
"standard": "none"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "harmony-shard-2"
|
||||
} as const satisfies Chain;
|
||||
@@ -13,9 +13,17 @@ export default {
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://www.harmony.one/",
|
||||
"slip44": 1023,
|
||||
"shortName": "hmy-s3",
|
||||
"chainId": 1666600003,
|
||||
"networkId": 1666600003,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Harmony Block Explorer",
|
||||
"url": "https://explorer.harmony.one/blocks/shard/3",
|
||||
"standard": "none"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "harmony-shard-3"
|
||||
} as const satisfies Chain;
|
||||
@@ -21,7 +21,7 @@ export default {
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Harmony Testnet Block Explorer",
|
||||
"url": "https://explorer.pops.one",
|
||||
"url": "https://explorer.testnet.harmony.one",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -6,7 +6,9 @@ export default {
|
||||
"https://harmony-testnet-shard-1.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://api.s1.b.hmny.io"
|
||||
],
|
||||
"faucets": [],
|
||||
"faucets": [
|
||||
"https://faucet.pops.one"
|
||||
],
|
||||
"nativeCurrency": {
|
||||
"name": "ONE",
|
||||
"symbol": "ONE",
|
||||
@@ -16,6 +18,13 @@ export default {
|
||||
"shortName": "hmy-b-s1",
|
||||
"chainId": 1666700001,
|
||||
"networkId": 1666700001,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Harmony Block Explorer",
|
||||
"url": "https://explorer.testnet.harmony.one",
|
||||
"standard": "none"
|
||||
}
|
||||
],
|
||||
"testnet": true,
|
||||
"slug": "harmony-testnet-shard-1"
|
||||
} as const satisfies Chain;
|
||||
@@ -1,21 +0,0 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Harmony Testnet Shard 2",
|
||||
"chain": "Harmony",
|
||||
"rpc": [
|
||||
"https://harmony-testnet-shard-2.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://api.s2.b.hmny.io"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "ONE",
|
||||
"symbol": "ONE",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://www.harmony.one/",
|
||||
"shortName": "hmy-b-s2",
|
||||
"chainId": 1666700002,
|
||||
"networkId": 1666700002,
|
||||
"testnet": true,
|
||||
"slug": "harmony-testnet-shard-2"
|
||||
} as const satisfies Chain;
|
||||
@@ -1,21 +0,0 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Harmony Testnet Shard 3",
|
||||
"chain": "Harmony",
|
||||
"rpc": [
|
||||
"https://harmony-testnet-shard-3.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://api.s3.b.hmny.io"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "ONE",
|
||||
"symbol": "ONE",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://www.harmony.one/",
|
||||
"shortName": "hmy-b-s3",
|
||||
"chainId": 1666700003,
|
||||
"networkId": 1666700003,
|
||||
"testnet": true,
|
||||
"slug": "harmony-testnet-shard-3"
|
||||
} as const satisfies Chain;
|
||||
@@ -4,11 +4,9 @@ export default {
|
||||
"chain": "Harmony",
|
||||
"rpc": [
|
||||
"https://harmony-devnet-shard-0.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://api.s1.ps.hmny.io"
|
||||
],
|
||||
"faucets": [
|
||||
"http://dev.faucet.easynode.one/"
|
||||
"https://api.s0.ps.hmny.io"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "ONE",
|
||||
"symbol": "ONE",
|
||||
@@ -18,13 +16,7 @@ export default {
|
||||
"shortName": "hmy-ps-s0",
|
||||
"chainId": 1666900000,
|
||||
"networkId": 1666900000,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Harmony Block Explorer",
|
||||
"url": "https://explorer.ps.hmny.io",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"explorers": [],
|
||||
"testnet": false,
|
||||
"slug": "harmony-devnet-shard-0"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,22 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Harmony Devnet Shard 1",
|
||||
"chain": "Harmony",
|
||||
"rpc": [
|
||||
"https://harmony-devnet-shard-1.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://api.s1.ps.hmny.io"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "ONE",
|
||||
"symbol": "ONE",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://www.harmony.one/",
|
||||
"shortName": "hmy-ps-s1",
|
||||
"chainId": 1666900001,
|
||||
"networkId": 1666900001,
|
||||
"explorers": [],
|
||||
"testnet": false,
|
||||
"slug": "harmony-devnet-shard-1"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,34 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "WhiteBIT Network",
|
||||
"chain": "WBT",
|
||||
"rpc": [
|
||||
"https://whitebit-network.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc.whitebit.network"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "WhiteBIT Coin",
|
||||
"symbol": "WBT",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://whitebit.network",
|
||||
"shortName": "wbt",
|
||||
"chainId": 1875,
|
||||
"networkId": 1875,
|
||||
"icon": {
|
||||
"url": "ipfs://Qmbi6cqsQyDjkQSoxbNTTUy8WGyVEFqCtATX2aF4KLmCcZ",
|
||||
"width": 512,
|
||||
"height": 512,
|
||||
"format": "png"
|
||||
},
|
||||
"explorers": [
|
||||
{
|
||||
"name": "wb-explorer",
|
||||
"url": "https://explorer.whitebit.network",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "whitebit-network"
|
||||
} as const satisfies Chain;
|
||||
@@ -3,9 +3,9 @@ export default {
|
||||
"name": "Lightlink Phoenix Mainnet",
|
||||
"chain": "Lightlink Phoenix Mainnet",
|
||||
"icon": {
|
||||
"url": "ipfs://QmNRUoMgx16hurD3au3ou5A9rmTLYmre8WiGmQEPFmP2Vo",
|
||||
"width": 600,
|
||||
"height": 600,
|
||||
"url": "ipfs://QmXMDj6iAFn2ducQcUU1M87PMMdT2jfyL3Tp3Lz5uUD5Lv",
|
||||
"width": 200,
|
||||
"height": 200,
|
||||
"format": "png"
|
||||
},
|
||||
"rpc": [
|
||||
@@ -33,9 +33,9 @@ export default {
|
||||
"name": "phoenix",
|
||||
"url": "https://phoenix.lightlink.io",
|
||||
"icon": {
|
||||
"url": "ipfs://QmNRUoMgx16hurD3au3ou5A9rmTLYmre8WiGmQEPFmP2Vo",
|
||||
"width": 600,
|
||||
"height": 600,
|
||||
"url": "ipfs://QmXMDj6iAFn2ducQcUU1M87PMMdT2jfyL3Tp3Lz5uUD5Lv",
|
||||
"width": 200,
|
||||
"height": 200,
|
||||
"format": "png"
|
||||
},
|
||||
"standard": "EIP3091"
|
||||
|
||||
@@ -3,9 +3,9 @@ export default {
|
||||
"name": "Lightlink Pegasus Testnet",
|
||||
"chain": "Lightlink Pegasus Testnet",
|
||||
"icon": {
|
||||
"url": "ipfs://QmNRUoMgx16hurD3au3ou5A9rmTLYmre8WiGmQEPFmP2Vo",
|
||||
"width": 600,
|
||||
"height": 600,
|
||||
"url": "ipfs://QmXMDj6iAFn2ducQcUU1M87PMMdT2jfyL3Tp3Lz5uUD5Lv",
|
||||
"width": 200,
|
||||
"height": 200,
|
||||
"format": "png"
|
||||
},
|
||||
"rpc": [
|
||||
@@ -35,9 +35,9 @@ export default {
|
||||
"name": "pegasus",
|
||||
"url": "https://pegasus.lightlink.io",
|
||||
"icon": {
|
||||
"url": "ipfs://QmNRUoMgx16hurD3au3ou5A9rmTLYmre8WiGmQEPFmP2Vo",
|
||||
"width": 600,
|
||||
"height": 600,
|
||||
"url": "ipfs://QmXMDj6iAFn2ducQcUU1M87PMMdT2jfyL3Tp3Lz5uUD5Lv",
|
||||
"width": 200,
|
||||
"height": 200,
|
||||
"format": "png"
|
||||
},
|
||||
"standard": "EIP3091"
|
||||
|
||||
@@ -4,7 +4,7 @@ export default {
|
||||
"chain": "REAP",
|
||||
"rpc": [
|
||||
"https://reapchain-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://test-rpc.reapchain.org"
|
||||
"https://test-eth.reapchain.org"
|
||||
],
|
||||
"faucets": [
|
||||
"http://faucet.reapchain.com"
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Cronos Mainnet Beta",
|
||||
"name": "Cronos Mainnet",
|
||||
"chain": "CRO",
|
||||
"rpc": [
|
||||
"https://cronos-beta.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://cronos.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://evm.cronos.org",
|
||||
"https://cronos-evm.publicnode.com"
|
||||
],
|
||||
@@ -30,5 +30,5 @@ export default {
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "cronos-beta"
|
||||
"slug": "cronos"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,42 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Manta Pacific Testnet",
|
||||
"chain": "Manta Pacific",
|
||||
"rpc": [
|
||||
"https://manta-pacific-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://manta-testnet.calderachain.xyz/http"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "Manta",
|
||||
"symbol": "MANTA",
|
||||
"decimals": 18
|
||||
},
|
||||
"features": [
|
||||
{
|
||||
"name": "EIP155"
|
||||
},
|
||||
{
|
||||
"name": "EIP1559"
|
||||
}
|
||||
],
|
||||
"infoURL": "https://manta-testnet.caldera.dev/",
|
||||
"shortName": "manta",
|
||||
"chainId": 3441005,
|
||||
"networkId": 3441005,
|
||||
"icon": {
|
||||
"url": "ipfs://QmTckcVTViRZ3NqT36MTt8AvgBSmudrbgU3pi8AaNtthoV",
|
||||
"width": 834,
|
||||
"height": 834,
|
||||
"format": "png"
|
||||
},
|
||||
"explorers": [
|
||||
{
|
||||
"name": "manta-testnet Explorer",
|
||||
"url": "https://manta-testnet.calderaexplorer.xyz",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": true,
|
||||
"slug": "manta-pacific-testnet"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,27 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Xai Goerli Orbit",
|
||||
"chain": "Xai Goerli Orbit Testnet",
|
||||
"shortName": "xai-goerli",
|
||||
"chainId": 47279324479,
|
||||
"testnet": true,
|
||||
"nativeCurrency": {
|
||||
"name": "Xai Goerli Ether",
|
||||
"symbol": "ETH",
|
||||
"decimals": 18
|
||||
},
|
||||
"rpc": [
|
||||
"https://xai-goerli-orbit.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://testnet.xai-chain.net/rpc"
|
||||
],
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Xai Goerli Testnet Explorer",
|
||||
"url": "https://testnet-explorer.xai-chain.net",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"faucets": [],
|
||||
"infoURL": "https://xai.games/",
|
||||
"slug": "xai-goerli-orbit"
|
||||
} as const satisfies Chain;
|
||||
@@ -2,8 +2,11 @@ import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Scroll Sepolia Testnet",
|
||||
"chain": "ETH",
|
||||
"status": "incubating",
|
||||
"rpc": [],
|
||||
"status": "active",
|
||||
"rpc": [
|
||||
"https://scroll-sepolia-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://sepolia-rpc.scroll.io/"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "Ether",
|
||||
@@ -14,11 +17,21 @@ export default {
|
||||
"shortName": "scr-sepolia",
|
||||
"chainId": 534351,
|
||||
"networkId": 534351,
|
||||
"explorers": [],
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Scroll Sepolia Testnet Block Explorer",
|
||||
"url": "https://sepolia-blockscout.scroll.io",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"parent": {
|
||||
"type": "L2",
|
||||
"chain": "eip155-11155111",
|
||||
"bridges": []
|
||||
"bridges": [
|
||||
{
|
||||
"url": "https://scroll.io/bridge"
|
||||
}
|
||||
]
|
||||
},
|
||||
"testnet": true,
|
||||
"slug": "scroll-sepolia-testnet"
|
||||
|
||||
@@ -3,7 +3,10 @@ export default {
|
||||
"name": "Scroll",
|
||||
"chain": "ETH",
|
||||
"status": "incubating",
|
||||
"rpc": [],
|
||||
"rpc": [
|
||||
"https://scroll.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc.scroll.io"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "Ether",
|
||||
@@ -14,11 +17,21 @@ export default {
|
||||
"shortName": "scr",
|
||||
"chainId": 534352,
|
||||
"networkId": 534352,
|
||||
"explorers": [],
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Scroll Mainnet Block Explorer",
|
||||
"url": "https://blockscout.scroll.io",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"parent": {
|
||||
"type": "L2",
|
||||
"chain": "eip155-1",
|
||||
"bridges": []
|
||||
"bridges": [
|
||||
{
|
||||
"url": "https://scroll.io/bridge"
|
||||
}
|
||||
]
|
||||
},
|
||||
"testnet": false,
|
||||
"slug": "scroll"
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Scroll Alpha Testnet",
|
||||
"chain": "ETH",
|
||||
"status": "active",
|
||||
"status": "deprecated",
|
||||
"rpc": [
|
||||
"https://scroll-alpha-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://alpha-rpc.scroll.io/l2"
|
||||
@@ -20,12 +20,7 @@ export default {
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Scroll Alpha Testnet Block Explorer",
|
||||
"url": "https://blockscout.scroll.io",
|
||||
"standard": "EIP3091"
|
||||
},
|
||||
{
|
||||
"name": "Scroll Alpha Testnet Block Explorer",
|
||||
"url": "https://scrollscan.co",
|
||||
"url": "https://alpha-blockscout.scroll.io",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -7,7 +7,8 @@ export default {
|
||||
"https://rpc.syscoin.org",
|
||||
"https://rpc.ankr.com/syscoin/${ANKR_API_KEY}",
|
||||
"https://syscoin.public-rpc.com",
|
||||
"wss://rpc.syscoin.org/wss"
|
||||
"wss://rpc.syscoin.org/wss",
|
||||
"https://syscoin-evm.publicnode.com"
|
||||
],
|
||||
"faucets": [
|
||||
"https://faucet.syscoin.org"
|
||||
|
||||
@@ -5,7 +5,8 @@ export default {
|
||||
"rpc": [
|
||||
"https://syscoin-tanenbaum-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc.tanenbaum.io",
|
||||
"wss://rpc.tanenbaum.io/wss"
|
||||
"wss://rpc.tanenbaum.io/wss",
|
||||
"https://syscoin-tanenbaum-evm.publicnode.com"
|
||||
],
|
||||
"faucets": [
|
||||
"https://faucet.tanenbaum.io"
|
||||
|
||||
@@ -1,8 +1,20 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Acala Mandala Testnet",
|
||||
"name": "Acala Mandala Testnet TC9",
|
||||
"chain": "mACA",
|
||||
"rpc": [],
|
||||
"rpc": [
|
||||
"https://acala-mandala-testnet-tc9.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://eth-rpc-tc9.aca-staging.network",
|
||||
"wss://eth-rpc-tc9.aca-staging.network"
|
||||
],
|
||||
"features": [
|
||||
{
|
||||
"name": "EIP155"
|
||||
},
|
||||
{
|
||||
"name": "EIP1559"
|
||||
}
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "Acala Mandala Token",
|
||||
@@ -13,6 +25,14 @@ export default {
|
||||
"shortName": "maca",
|
||||
"chainId": 595,
|
||||
"networkId": 595,
|
||||
"slip44": 595,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "blockscout",
|
||||
"url": "https://blockscout.mandala.aca-staging.network",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": true,
|
||||
"slug": "acala-mandala-testnet"
|
||||
"slug": "acala-mandala-testnet-tc9"
|
||||
} as const satisfies Chain;
|
||||
@@ -2,7 +2,11 @@ import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Karura Network Testnet",
|
||||
"chain": "KAR",
|
||||
"rpc": [],
|
||||
"rpc": [
|
||||
"https://karura-network-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://eth-rpc-karura-testnet.aca-staging.network",
|
||||
"wss://eth-rpc-karura-testnet.aca-staging.network"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "Karura Token",
|
||||
@@ -14,6 +18,13 @@ export default {
|
||||
"chainId": 596,
|
||||
"networkId": 596,
|
||||
"slip44": 596,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "blockscout",
|
||||
"url": "https://blockscout.karura-testnet.aca-staging.network",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": true,
|
||||
"slug": "karura-network-testnet"
|
||||
} as const satisfies Chain;
|
||||
@@ -2,7 +2,11 @@ import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Acala Network Testnet",
|
||||
"chain": "ACA",
|
||||
"rpc": [],
|
||||
"rpc": [
|
||||
"https://acala-network-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://eth-rpc-acala-testnet.aca-staging.network",
|
||||
"wss://eth-rpc-acala-testnet.aca-staging.network"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "Acala Token",
|
||||
@@ -14,6 +18,13 @@ export default {
|
||||
"chainId": 597,
|
||||
"networkId": 597,
|
||||
"slip44": 597,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "blockscout",
|
||||
"url": "https://blockscout.acala-dev.aca-dev.network",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": true,
|
||||
"slug": "acala-network-testnet"
|
||||
} as const satisfies Chain;
|
||||
@@ -2,18 +2,37 @@ import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Karura Network",
|
||||
"chain": "KAR",
|
||||
"rpc": [],
|
||||
"rpc": [
|
||||
"https://karura-network.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://eth-rpc-karura.aca-api.network",
|
||||
"wss://eth-rpc-karura.aca-api.network"
|
||||
],
|
||||
"features": [
|
||||
{
|
||||
"name": "EIP155"
|
||||
},
|
||||
{
|
||||
"name": "EIP1559"
|
||||
}
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "Karura Token",
|
||||
"symbol": "KAR",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://karura.network",
|
||||
"infoURL": "https://acala.network/karura",
|
||||
"shortName": "kar",
|
||||
"chainId": 686,
|
||||
"networkId": 686,
|
||||
"slip44": 686,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "blockscout",
|
||||
"url": "https://blockscout.karura.network",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "karura-network"
|
||||
} as const satisfies Chain;
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "ZetaChain Athens Testnet",
|
||||
"name": "ZetaChain Athens 3 Testnet",
|
||||
"chain": "ZetaChain",
|
||||
"icon": {
|
||||
"url": "ipfs://QmP4Gnf4Lkp8q5LQVePNjAWxSqrw8vU2JAf7amcFz4vEUy",
|
||||
@@ -9,8 +9,8 @@ export default {
|
||||
"format": "png"
|
||||
},
|
||||
"rpc": [
|
||||
"https://zetachain-athens-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://api.athens2.zetachain.com/evm"
|
||||
"https://zetachain-athens-3-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc.ankr.com/zetachain_evm_athens_testnet"
|
||||
],
|
||||
"faucets": [
|
||||
"https://labs.zetachain.com/get-zeta"
|
||||
@@ -39,10 +39,10 @@ export default {
|
||||
},
|
||||
{
|
||||
"name": "ZetaChain Athens Testnet Explorer",
|
||||
"url": "https://explorer.athens.zetachain.com",
|
||||
"url": "https://athens3.explorer.zetachain.com",
|
||||
"standard": "none"
|
||||
}
|
||||
],
|
||||
"testnet": true,
|
||||
"slug": "zetachain-athens-testnet"
|
||||
"slug": "zetachain-athens-3-testnet"
|
||||
} as const satisfies Chain;
|
||||
@@ -2,7 +2,19 @@ import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Acala Network",
|
||||
"chain": "ACA",
|
||||
"rpc": [],
|
||||
"rpc": [
|
||||
"https://acala-network.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://eth-rpc-acala.aca-api.network",
|
||||
"wss://eth-rpc-acala.aca-api.network"
|
||||
],
|
||||
"features": [
|
||||
{
|
||||
"name": "EIP155"
|
||||
},
|
||||
{
|
||||
"name": "EIP1559"
|
||||
}
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "Acala Token",
|
||||
@@ -14,6 +26,13 @@ export default {
|
||||
"chainId": 787,
|
||||
"networkId": 787,
|
||||
"slip44": 787,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "blockscout",
|
||||
"url": "https://blockscout.acala.network",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "acala-network"
|
||||
} as const satisfies Chain;
|
||||
@@ -9,7 +9,11 @@ export default {
|
||||
"https://evm-dataseed3.meerscan.io",
|
||||
"https://evm-dataseed.meerscan.com",
|
||||
"https://evm-dataseed1.meerscan.com",
|
||||
"https://evm-dataseed2.meerscan.com"
|
||||
"https://evm-dataseed2.meerscan.com",
|
||||
"https://qng.rpc.qitmeer.io",
|
||||
"https://mainnet.meerlabs.com",
|
||||
"https://rpc.dimai.ai",
|
||||
"https://rpc.woowow.io"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
@@ -37,7 +41,7 @@ export default {
|
||||
"height": 512,
|
||||
"format": "png"
|
||||
},
|
||||
"url": "https://evm.meerscan.com",
|
||||
"url": "https://qng.meerscan.io",
|
||||
"standard": "none"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -2,8 +2,15 @@ import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Qitmeer Network Testnet",
|
||||
"chain": "MEER",
|
||||
"rpc": [],
|
||||
"faucets": [],
|
||||
"rpc": [
|
||||
"https://qitmeer-network-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://testnet-qng.rpc.qitmeer.io",
|
||||
"https://testnet.meerlabs.com",
|
||||
"https://meer.testnet.meerfans.club"
|
||||
],
|
||||
"faucets": [
|
||||
"https://faucet.qitmeer.io"
|
||||
],
|
||||
"nativeCurrency": {
|
||||
"name": "Qitmeer Testnet",
|
||||
"symbol": "MEER-T",
|
||||
@@ -28,7 +35,7 @@ export default {
|
||||
"height": 512,
|
||||
"format": "png"
|
||||
},
|
||||
"url": "https://testnet.qng.meerscan.io",
|
||||
"url": "https://qng-testnet.meerscan.io",
|
||||
"standard": "none"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -4,7 +4,7 @@ export default {
|
||||
"chain": "ETH",
|
||||
"rpc": [
|
||||
"https://base.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://developer-access-mainnet.base.org/"
|
||||
"https://mainnet.base.org/"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "IMPERIUM TESTNET",
|
||||
"chain": "tIMP",
|
||||
"rpc": [
|
||||
"https://imperium-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://data-aws-testnet.imperiumchain.com",
|
||||
"https://data-aws2-testnet.imperiumchain.com"
|
||||
],
|
||||
"faucets": [
|
||||
"https://faucet.imperiumchain.com/"
|
||||
],
|
||||
"nativeCurrency": {
|
||||
"name": "tIMP",
|
||||
"symbol": "tIMP",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://imperiumchain.com",
|
||||
"shortName": "tIMP",
|
||||
"chainId": 9818,
|
||||
"networkId": 9818,
|
||||
"icon": {
|
||||
"url": "ipfs://QmcNGLzKyc7Gu2dgpBFF6t3KJwFuKC79D56DW8GTc5DWRw",
|
||||
"width": 200,
|
||||
"height": 200,
|
||||
"format": "png"
|
||||
},
|
||||
"explorers": [
|
||||
{
|
||||
"name": "IMPERIUM TESTNET Explorer",
|
||||
"icon": {
|
||||
"url": "ipfs://QmcNGLzKyc7Gu2dgpBFF6t3KJwFuKC79D56DW8GTc5DWRw",
|
||||
"width": 200,
|
||||
"height": 200,
|
||||
"format": "png"
|
||||
},
|
||||
"url": "https://network.impscan.com",
|
||||
"standard": "none"
|
||||
}
|
||||
],
|
||||
"testnet": true,
|
||||
"slug": "imperium-testnet"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,43 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "IMPERIUM MAINNET",
|
||||
"chain": "IMP",
|
||||
"rpc": [
|
||||
"https://imperium.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://data-aws-mainnet.imperiumchain.com",
|
||||
"https://data-aws2-mainnet.imperiumchain.com"
|
||||
],
|
||||
"faucets": [
|
||||
"https://faucet.imperiumchain.com/"
|
||||
],
|
||||
"nativeCurrency": {
|
||||
"name": "IMP",
|
||||
"symbol": "IMP",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://imperiumchain.com",
|
||||
"shortName": "IMP",
|
||||
"chainId": 9819,
|
||||
"networkId": 9819,
|
||||
"icon": {
|
||||
"url": "ipfs://QmcNGLzKyc7Gu2dgpBFF6t3KJwFuKC79D56DW8GTc5DWRw",
|
||||
"width": 200,
|
||||
"height": 200,
|
||||
"format": "png"
|
||||
},
|
||||
"explorers": [
|
||||
{
|
||||
"name": "IMPERIUM Explorer",
|
||||
"icon": {
|
||||
"url": "ipfs://QmcNGLzKyc7Gu2dgpBFF6t3KJwFuKC79D56DW8GTc5DWRw",
|
||||
"width": 200,
|
||||
"height": 200,
|
||||
"format": "png"
|
||||
},
|
||||
"url": "https://impscan.com",
|
||||
"standard": "none"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "imperium"
|
||||
} as const satisfies Chain;
|
||||
@@ -11,7 +11,8 @@ export default {
|
||||
"rpc": [
|
||||
"https://mind-smart-chain.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc-msc.mindchain.info/",
|
||||
"https://seednode.mindchain.info"
|
||||
"https://seednode.mindchain.info",
|
||||
"wss://seednode.mindchain.info/ws"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
// @ts-check
|
||||
/** @typedef { import("../../src/types").Chain } Chain */
|
||||
|
||||
/** @type {Omit<Chain, "slug">} */
|
||||
export default {
|
||||
name: "Xai Goerli Orbit",
|
||||
chain: "Xai Goerli Orbit Testnet",
|
||||
shortName: "xai-goerli",
|
||||
chainId: 47279324479,
|
||||
testnet: true,
|
||||
nativeCurrency: {
|
||||
name: "Xai Goerli Ether",
|
||||
symbol: "ETH",
|
||||
decimals: 18,
|
||||
},
|
||||
rpc: ["https://testnet.xai-chain.net/rpc"],
|
||||
explorers: [
|
||||
{
|
||||
name: "Xai Goerli Testnet Explorer",
|
||||
url: "https://testnet-explorer.xai-chain.net",
|
||||
standard: "EIP3091",
|
||||
},
|
||||
],
|
||||
faucets: [],
|
||||
infoURL: "https://xai.games/",
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/chains",
|
||||
"version": "0.1.40",
|
||||
"version": "0.1.43",
|
||||
"main": "dist/thirdweb-dev-chains.cjs.js",
|
||||
"module": "dist/thirdweb-dev-chains.esm.js",
|
||||
"browser": {
|
||||
|
||||
@@ -105,7 +105,8 @@ for (const file of additionalChainsFiles) {
|
||||
}
|
||||
|
||||
chains = chains
|
||||
.filter((c) => c.status !== "deprecated")
|
||||
// Keep scroll-alpha-testnet for now even though its deprecated
|
||||
.filter((c) => c.status !== "deprecated" || c.chainId === 534353)
|
||||
.map((chain) => {
|
||||
if (overrides[chain.chainId]) {
|
||||
chain = merge(chain, overrides[chain.chainId], {
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,5 +1,59 @@
|
||||
# thirdweb
|
||||
|
||||
## 0.11.12
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`73462ef1`](https://github.com/thirdweb-dev/js/commit/73462ef10800aeeb5976634e2bc6fb5d3e8501e4), [`27c225a5`](https://github.com/thirdweb-dev/js/commit/27c225a51221417592b5940887abd1ccb8b67e47), [`cb1c9937`](https://github.com/thirdweb-dev/js/commit/cb1c9937fadb2d06eb148cf9819f2b3601376308), [`70c4a119`](https://github.com/thirdweb-dev/js/commit/70c4a119d691a37ec999d9f6087902d532cc82ed), [`a1732663`](https://github.com/thirdweb-dev/js/commit/a17326634e758c3bf42f0cc3869b8792f1e18cc9), [`f0443bd9`](https://github.com/thirdweb-dev/js/commit/f0443bd989dbba50d0836d1cf274bfb2f44a53fd), [`cb1c9937`](https://github.com/thirdweb-dev/js/commit/cb1c9937fadb2d06eb148cf9819f2b3601376308), [`588b2106`](https://github.com/thirdweb-dev/js/commit/588b21060139a7c0bf5805e2c629a16792ed2c76), [`269e68c0`](https://github.com/thirdweb-dev/js/commit/269e68c0a15e8f78cb5b68c9456ca8094b9e1f30)]:
|
||||
- @thirdweb-dev/storage@1.2.5
|
||||
- @thirdweb-dev/sdk@3.10.48
|
||||
- @thirdweb-dev/chains@0.1.43
|
||||
|
||||
## 0.11.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`4c37af49`](https://github.com/thirdweb-dev/js/commit/4c37af49aa4fa66beb8ffe8ef556068a29f3c5d4)]:
|
||||
- @thirdweb-dev/storage@1.2.4
|
||||
- @thirdweb-dev/sdk@3.10.47
|
||||
|
||||
## 0.11.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`262edc6a`](https://github.com/thirdweb-dev/js/commit/262edc6a46792da88f49ff6ef0a756a932a6a0cf), [`262edc6a`](https://github.com/thirdweb-dev/js/commit/262edc6a46792da88f49ff6ef0a756a932a6a0cf)]:
|
||||
- @thirdweb-dev/chains@0.1.42
|
||||
- @thirdweb-dev/sdk@3.10.46
|
||||
|
||||
## 0.11.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1442](https://github.com/thirdweb-dev/js/pull/1442) [`7f54012e`](https://github.com/thirdweb-dev/js/commit/7f54012ec648b727b60784990e71b0efb4690934) Thanks [@Marfuen](https://github.com/Marfuen)! - - Warn users on windows to not use the powershell as there are some compatibility issues with it at the moment.
|
||||
- Warn users if they are pasting a client id instead of a secret key.
|
||||
- Updated dependencies [[`2a91113a`](https://github.com/thirdweb-dev/js/commit/2a91113a760733fcff2aec90041f69e15de33905)]:
|
||||
- @thirdweb-dev/sdk@3.10.45
|
||||
|
||||
## 0.11.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1443](https://github.com/thirdweb-dev/js/pull/1443) [`8c0dc9c8`](https://github.com/thirdweb-dev/js/commit/8c0dc9c88084efcd184a416ed372c50c2fb8a209) Thanks [@nessup](https://github.com/nessup)! - Switch IPFS download domain used in CLI
|
||||
|
||||
- Updated dependencies [[`a5d0be93`](https://github.com/thirdweb-dev/js/commit/a5d0be939a143095e769b68cf86360bfe4720744), [`c0a6d2f1`](https://github.com/thirdweb-dev/js/commit/c0a6d2f18231310d143c9b0cb1b2ff59315087a4), [`becbb637`](https://github.com/thirdweb-dev/js/commit/becbb637367285ed3d8d7d131e1020bf23e38298), [`fd981655`](https://github.com/thirdweb-dev/js/commit/fd9816556fe595b0c764e34dbcf15b0ad1677edb), [`c9bf4f05`](https://github.com/thirdweb-dev/js/commit/c9bf4f05c161707c6eb799ecef82f462e4a82405), [`67b145b9`](https://github.com/thirdweb-dev/js/commit/67b145b94dafb2fb1d90553ed4829f0ed22e2907), [`5ee700e8`](https://github.com/thirdweb-dev/js/commit/5ee700e80438650fa253c25c0bee6658ce68d2cf), [`9f5adc5c`](https://github.com/thirdweb-dev/js/commit/9f5adc5c5c2782ffb878759df481e5fb1e1740e5)]:
|
||||
- @thirdweb-dev/sdk@3.10.44
|
||||
- @thirdweb-dev/chains@0.1.41
|
||||
|
||||
## 0.11.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1419](https://github.com/thirdweb-dev/js/pull/1419) [`2b96f71e`](https://github.com/thirdweb-dev/js/commit/2b96f71e191d7f69c2c75f9c6a9ee4537bac65aa) Thanks [@Marfuen](https://github.com/Marfuen)! - Fix path of cache to work with windows.
|
||||
|
||||
- Updated dependencies [[`3b6b0746`](https://github.com/thirdweb-dev/js/commit/3b6b0746b3fc792f4c5092814a7abfabcbc9801e)]:
|
||||
- @thirdweb-dev/storage@1.2.3
|
||||
- @thirdweb-dev/sdk@3.10.43
|
||||
|
||||
## 0.11.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "thirdweb",
|
||||
"main": "dist/cli/index.js",
|
||||
"version": "0.11.6",
|
||||
"version": "0.11.12",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/cli",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -2,6 +2,7 @@ import chalk from "chalk";
|
||||
import prompts from "prompts";
|
||||
import Cache, { CacheEntry } from "sync-disk-cache";
|
||||
import { ApiResponse } from "../lib/types";
|
||||
import os from "os";
|
||||
|
||||
export async function loginUser(
|
||||
cache: Cache,
|
||||
@@ -40,6 +41,10 @@ export function getSession(cache: Cache) {
|
||||
|
||||
export async function createSession(cache: Cache) {
|
||||
try {
|
||||
const isWindows = os.type() === "Windows_NT";
|
||||
if (isWindows) {
|
||||
console.log(chalk.yellow("Windows detected: if you are using powershell, there are some known issues with it that we are actively working on, please use git bash or the command prompt. Thank you for your understanding."));
|
||||
}
|
||||
const response = await prompts({
|
||||
type: "invisible",
|
||||
name: "apiSecretKey",
|
||||
@@ -48,6 +53,20 @@ export async function createSession(cache: Cache) {
|
||||
)}`,
|
||||
});
|
||||
|
||||
const keyPassed = response.apiSecretKey;
|
||||
if (!keyPassed) {
|
||||
console.log(chalk.red("You need to pass an API secret key"));
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (keyPassed.length === 32) {
|
||||
console.log(chalk.red(`This is not a valid secret key. To get your secret key
|
||||
1. Create an API key at https://thirdweb.com/create-api-key
|
||||
2. Store and copy your Secret Key. This will be shown only once.
|
||||
3. Paste it in the CLI when prompted`));
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
try {
|
||||
await validateKey(response.apiSecretKey);
|
||||
} catch (error) {
|
||||
|
||||
@@ -26,7 +26,7 @@ const main = async () => {
|
||||
const skipIntro = process.env.THIRDWEB_CLI_SKIP_INTRO === "true";
|
||||
|
||||
const program = new Command();
|
||||
const cache = new Cache("thirdweb:cli", {
|
||||
const cache = new Cache("thirdweb-cli", {
|
||||
location: path.join(os.homedir(), ".thirdweb", "creds"),
|
||||
});
|
||||
|
||||
|
||||
@@ -70,10 +70,7 @@ export async function deployApp(
|
||||
|
||||
try {
|
||||
const uri = await upload(storage, distPath);
|
||||
return `${uri.replace(
|
||||
"ipfs://",
|
||||
"https://ipfs-public.thirdwebcdn.com/ipfs/",
|
||||
)}`;
|
||||
return storage.resolveScheme(uri);
|
||||
} catch (err) {
|
||||
console.error("Can't upload project", err);
|
||||
return Promise.reject("Can't upload project");
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @thirdweb-dev/contracts-js
|
||||
|
||||
## 1.3.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1432](https://github.com/thirdweb-dev/js/pull/1432) [`9f5adc5c`](https://github.com/thirdweb-dev/js/commit/9f5adc5c5c2782ffb878759df481e5fb1e1740e5) Thanks [@jnsdls](https://github.com/jnsdls)! - upgrade contracts package
|
||||
|
||||
## 1.3.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"main": "dist/thirdweb-dev-contracts-js-factories-TWRegistryLegacy__factory.cjs.js",
|
||||
"module": "dist/thirdweb-dev-contracts-js-factories-TWRegistryLegacy__factory.esm.js"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/contracts-js",
|
||||
"version": "1.3.10",
|
||||
"version": "1.3.11",
|
||||
"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.8.1-0"
|
||||
"@thirdweb-dev/contracts": "3.8.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/preset-env": "^7.22.9",
|
||||
|
||||
@@ -1,5 +1,79 @@
|
||||
# @thirdweb-dev/react-core
|
||||
|
||||
## 3.14.29
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`73462ef1`](https://github.com/thirdweb-dev/js/commit/73462ef10800aeeb5976634e2bc6fb5d3e8501e4), [`27c225a5`](https://github.com/thirdweb-dev/js/commit/27c225a51221417592b5940887abd1ccb8b67e47), [`cb1c9937`](https://github.com/thirdweb-dev/js/commit/cb1c9937fadb2d06eb148cf9819f2b3601376308), [`70c4a119`](https://github.com/thirdweb-dev/js/commit/70c4a119d691a37ec999d9f6087902d532cc82ed), [`a1732663`](https://github.com/thirdweb-dev/js/commit/a17326634e758c3bf42f0cc3869b8792f1e18cc9), [`f0443bd9`](https://github.com/thirdweb-dev/js/commit/f0443bd989dbba50d0836d1cf274bfb2f44a53fd), [`cb1c9937`](https://github.com/thirdweb-dev/js/commit/cb1c9937fadb2d06eb148cf9819f2b3601376308), [`588b2106`](https://github.com/thirdweb-dev/js/commit/588b21060139a7c0bf5805e2c629a16792ed2c76), [`269e68c0`](https://github.com/thirdweb-dev/js/commit/269e68c0a15e8f78cb5b68c9456ca8094b9e1f30)]:
|
||||
- @thirdweb-dev/storage@1.2.5
|
||||
- @thirdweb-dev/wallets@1.1.12
|
||||
- @thirdweb-dev/sdk@3.10.48
|
||||
- @thirdweb-dev/chains@0.1.43
|
||||
- @thirdweb-dev/auth@3.2.29
|
||||
|
||||
## 3.14.28
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1460](https://github.com/thirdweb-dev/js/pull/1460) [`4b0e63dc`](https://github.com/thirdweb-dev/js/commit/4b0e63dcc0ca871ce9cef76f8a41ff290316741c) Thanks [@MananTank](https://github.com/MananTank)! - Save `oAuthRedirectResult` when autoconnecting Magic Link via social login
|
||||
|
||||
- Updated dependencies [[`4c37af49`](https://github.com/thirdweb-dev/js/commit/4c37af49aa4fa66beb8ffe8ef556068a29f3c5d4), [`4b0e63dc`](https://github.com/thirdweb-dev/js/commit/4b0e63dcc0ca871ce9cef76f8a41ff290316741c)]:
|
||||
- @thirdweb-dev/storage@1.2.4
|
||||
- @thirdweb-dev/wallets@1.1.11
|
||||
- @thirdweb-dev/sdk@3.10.47
|
||||
- @thirdweb-dev/auth@3.2.28
|
||||
|
||||
## 3.14.27
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1392](https://github.com/thirdweb-dev/js/pull/1392) [`dfd120a3`](https://github.com/thirdweb-dev/js/commit/dfd120a3a9d1582c8b174265c92bf43dbbaf5c86) Thanks [@adam-maj](https://github.com/adam-maj)! - Expose functions from auth and update useAuth
|
||||
|
||||
- Updated dependencies [[`262edc6a`](https://github.com/thirdweb-dev/js/commit/262edc6a46792da88f49ff6ef0a756a932a6a0cf), [`262edc6a`](https://github.com/thirdweb-dev/js/commit/262edc6a46792da88f49ff6ef0a756a932a6a0cf), [`dfd120a3`](https://github.com/thirdweb-dev/js/commit/dfd120a3a9d1582c8b174265c92bf43dbbaf5c86)]:
|
||||
- @thirdweb-dev/chains@0.1.42
|
||||
- @thirdweb-dev/sdk@3.10.46
|
||||
- @thirdweb-dev/auth@3.2.27
|
||||
- @thirdweb-dev/wallets@1.1.10
|
||||
|
||||
## 3.14.26
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`2a91113a`](https://github.com/thirdweb-dev/js/commit/2a91113a760733fcff2aec90041f69e15de33905)]:
|
||||
- @thirdweb-dev/sdk@3.10.45
|
||||
- @thirdweb-dev/wallets@1.1.9
|
||||
|
||||
## 3.14.25
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1423](https://github.com/thirdweb-dev/js/pull/1423) [`2283d210`](https://github.com/thirdweb-dev/js/commit/2283d21027503e047c25df5ebb21bdde0734be9e) Thanks [@nkrishang](https://github.com/nkrishang)! - Create useAccountAdmins hook
|
||||
|
||||
- [#1429](https://github.com/thirdweb-dev/js/pull/1429) [`ab36d84f`](https://github.com/thirdweb-dev/js/commit/ab36d84f1ce5647fa52475b4a35ea29d5007ad9b) Thanks [@iketw](https://github.com/iketw)! - Pass secretKey in the React SDK for server-side rendering
|
||||
|
||||
- [#1437](https://github.com/thirdweb-dev/js/pull/1437) [`5ee700e8`](https://github.com/thirdweb-dev/js/commit/5ee700e80438650fa253c25c0bee6658ce68d2cf) Thanks [@farhanW3](https://github.com/farhanW3)! - Updated the error messages
|
||||
|
||||
- Updated dependencies [[`a5d0be93`](https://github.com/thirdweb-dev/js/commit/a5d0be939a143095e769b68cf86360bfe4720744), [`c0a6d2f1`](https://github.com/thirdweb-dev/js/commit/c0a6d2f18231310d143c9b0cb1b2ff59315087a4), [`a9f2ff73`](https://github.com/thirdweb-dev/js/commit/a9f2ff73c9f83f05c3e2d3c53b23b2843e8a2576), [`fd981655`](https://github.com/thirdweb-dev/js/commit/fd9816556fe595b0c764e34dbcf15b0ad1677edb), [`becbb637`](https://github.com/thirdweb-dev/js/commit/becbb637367285ed3d8d7d131e1020bf23e38298), [`fd981655`](https://github.com/thirdweb-dev/js/commit/fd9816556fe595b0c764e34dbcf15b0ad1677edb), [`c9bf4f05`](https://github.com/thirdweb-dev/js/commit/c9bf4f05c161707c6eb799ecef82f462e4a82405), [`67b145b9`](https://github.com/thirdweb-dev/js/commit/67b145b94dafb2fb1d90553ed4829f0ed22e2907), [`5ee700e8`](https://github.com/thirdweb-dev/js/commit/5ee700e80438650fa253c25c0bee6658ce68d2cf), [`9f5adc5c`](https://github.com/thirdweb-dev/js/commit/9f5adc5c5c2782ffb878759df481e5fb1e1740e5)]:
|
||||
- @thirdweb-dev/sdk@3.10.44
|
||||
- @thirdweb-dev/wallets@1.1.8
|
||||
- @thirdweb-dev/chains@0.1.41
|
||||
|
||||
## 3.14.24
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`3b6b0746`](https://github.com/thirdweb-dev/js/commit/3b6b0746b3fc792f4c5092814a7abfabcbc9801e), [`b0ec1d80`](https://github.com/thirdweb-dev/js/commit/b0ec1d80839efccad11b50afbf2216c2c132cf7e)]:
|
||||
- @thirdweb-dev/storage@1.2.3
|
||||
- @thirdweb-dev/wallets@1.1.7
|
||||
- @thirdweb-dev/sdk@3.10.43
|
||||
|
||||
## 3.14.23
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`fbde927a`](https://github.com/thirdweb-dev/js/commit/fbde927a0cb36a6269e045d8e577536f23164ef7)]:
|
||||
- @thirdweb-dev/wallets@1.1.6
|
||||
|
||||
## 3.14.22
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/react-core",
|
||||
"version": "3.14.22",
|
||||
"version": "3.14.29",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-core",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"license": "Apache-2.0",
|
||||
@@ -104,6 +104,7 @@
|
||||
"@thirdweb-dev/sdk": "workspace:*",
|
||||
"@thirdweb-dev/storage": "workspace:*",
|
||||
"@thirdweb-dev/wallets": "workspace:*",
|
||||
"@thirdweb-dev/auth": "workspace:*",
|
||||
"mime": "3.0.0",
|
||||
"tiny-invariant": "^1.2.0"
|
||||
},
|
||||
|
||||
@@ -161,6 +161,7 @@ export const ThirdwebProviderCore = <TChains extends Chain[]>({
|
||||
storageInterface={props.storageInterface}
|
||||
authConfig={props.authConfig}
|
||||
clientId={props.clientId}
|
||||
secretKey={props.secretKey}
|
||||
>
|
||||
<ThirdwebAuthProvider value={props.authConfig}>
|
||||
{props.children}
|
||||
|
||||
@@ -317,10 +317,11 @@ export function ThirdwebWalletProvider(
|
||||
),
|
||||
{
|
||||
ms: autoConnectTimeout,
|
||||
message: "Failed to Auto connect. Auto connect timed out.",
|
||||
message: autoConnectTimeoutErrorMessage,
|
||||
},
|
||||
);
|
||||
} catch (e) {
|
||||
console.error("Failed to auto connect wallet");
|
||||
console.error(e);
|
||||
setConnectionStatus("disconnected");
|
||||
return;
|
||||
@@ -345,10 +346,11 @@ export function ThirdwebWalletProvider(
|
||||
setConnectionStatus("connecting");
|
||||
await timeoutPromise(wallet.autoConnect(walletInfo.connectParams), {
|
||||
ms: autoConnectTimeout,
|
||||
message: "Failed to Auto connect. Auto connect timed out.",
|
||||
message: autoConnectTimeoutErrorMessage,
|
||||
});
|
||||
setConnectedWallet(wallet, walletInfo.connectParams, true);
|
||||
} catch (e) {
|
||||
console.error("Failed to auto connect wallet");
|
||||
console.error(e);
|
||||
lastConnectedWalletStorage.removeItem(
|
||||
LAST_CONNECTED_WALLET_STORAGE_KEY,
|
||||
@@ -550,3 +552,5 @@ function timeoutPromise<T>(
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
const autoConnectTimeoutErrorMessage = `Failed to Auto connect. Auto connect timed out. You can increase the timeout duration using the autoConnectTimeout prop on <ThirdwebProvider />`;
|
||||
|
||||
@@ -21,13 +21,14 @@ import type {
|
||||
SmartContract,
|
||||
} from "@thirdweb-dev/sdk";
|
||||
import invariant from "tiny-invariant";
|
||||
import { WalletAddress } from "../../types";
|
||||
|
||||
/** **********************/
|
||||
/** READ HOOKS **/
|
||||
/** **********************/
|
||||
|
||||
/**
|
||||
* Get all accounts
|
||||
* Get all signers of account
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
@@ -50,7 +51,7 @@ export function useAccountSigners(
|
||||
requiredParamInvariant(contract, "No Contract instance provided");
|
||||
invariant(
|
||||
contract.account.getAllSigners,
|
||||
"Contract instance does not support contract.account.getSignersWithRestrictions",
|
||||
"Contract instance does not support contract.account.getAllSigners",
|
||||
);
|
||||
return contract.account.getAllSigners();
|
||||
},
|
||||
@@ -58,6 +59,71 @@ export function useAccountSigners(
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all admins of account
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* const { data: accounts, isLoading, error } = useAccountSigners(contract);
|
||||
* ```
|
||||
*
|
||||
* @param contract - an instance of a account
|
||||
* @returns a response object that includes an array of all admins of the provided account
|
||||
* @twfeature Account
|
||||
* @see {@link https://portal.thirdweb.com/react/react.useaccountadmins?utm_source=sdk | Documentation}
|
||||
* @beta
|
||||
*/
|
||||
export function useAccountAdmins(
|
||||
contract: RequiredParam<SmartContract>,
|
||||
): UseQueryResult<WalletAddress[]> {
|
||||
const contractAddress = contract?.getAddress();
|
||||
return useQueryWithNetwork(
|
||||
cacheKeys.contract.account.signers(contractAddress),
|
||||
() => {
|
||||
requiredParamInvariant(contract, "No Contract instance provided");
|
||||
invariant(
|
||||
contract.account.getAllAdmins,
|
||||
"Contract instance does not support contract.account.getAllAdmins",
|
||||
);
|
||||
return contract.account.getAllAdmins();
|
||||
},
|
||||
{ enabled: !!contract },
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all signers and admins of account
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* const { data: accounts, isLoading, error } = useAccountSigners(contract);
|
||||
* ```
|
||||
*
|
||||
* @param contract - an instance of a account
|
||||
* @returns a response object that includes an array of all admins of the provided account
|
||||
* @twfeature Account
|
||||
* @see {@link https://portal.thirdweb.com/react/react.useaccountadmins?utm_source=sdk | Documentation}
|
||||
* @beta
|
||||
*/
|
||||
export function useAccountAdminsAndSigners(
|
||||
contract: RequiredParam<SmartContract>,
|
||||
): UseQueryResult<SignerWithPermissions[]> {
|
||||
const contractAddress = contract?.getAddress();
|
||||
return useQueryWithNetwork(
|
||||
cacheKeys.contract.account.signers(contractAddress),
|
||||
() => {
|
||||
requiredParamInvariant(contract, "No Contract instance provided");
|
||||
invariant(
|
||||
contract.account.getAllAdminsAndSigners,
|
||||
"Contract instance does not support contract.account.getAllAdminsAndSigners",
|
||||
);
|
||||
|
||||
return contract.account.getAllAdminsAndSigners();
|
||||
},
|
||||
{ enabled: !!contract },
|
||||
);
|
||||
}
|
||||
|
||||
/** **********************/
|
||||
/** WRITE HOOKS **/
|
||||
/** **********************/
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { LoginOptions } from "@thirdweb-dev/auth";
|
||||
import { ThirdwebAuth } from "@thirdweb-dev/auth";
|
||||
import { useWallet } from "../../../core/hooks/wallet-hooks";
|
||||
import { useThirdwebAuthContext } from "../../contexts/thirdweb-auth";
|
||||
import { doLogin } from "./useLogin";
|
||||
import invariant from "tiny-invariant";
|
||||
import { useMemo } from "react";
|
||||
|
||||
export { useLogin, doLogin } from "./useLogin";
|
||||
export { useLogin } from "./useLogin";
|
||||
export { useLogout } from "./useLogout";
|
||||
export type { UserWithData } from "./useUser";
|
||||
export { useUser } from "./useUser";
|
||||
@@ -14,17 +13,15 @@ export function useAuth() {
|
||||
const wallet = useWallet();
|
||||
const authConfig = useThirdwebAuthContext();
|
||||
|
||||
return {
|
||||
login: async (options?: LoginOptions) => {
|
||||
invariant(
|
||||
authConfig,
|
||||
"Please specify an authConfig in the ThirdwebProvider",
|
||||
);
|
||||
invariant(wallet, "Need a connected a wallet!");
|
||||
return doLogin(wallet, {
|
||||
domain: authConfig.domain,
|
||||
...options,
|
||||
});
|
||||
},
|
||||
};
|
||||
return useMemo(() => {
|
||||
if (!authConfig?.domain) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (!wallet) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return new ThirdwebAuth(wallet, authConfig.domain)
|
||||
}, [wallet, authConfig, authConfig?.domain])
|
||||
}
|
||||
|
||||
@@ -2,12 +2,7 @@ import { useWallet } from "../../../core/hooks/wallet-hooks";
|
||||
import { useThirdwebAuthContext } from "../../contexts/thirdweb-auth";
|
||||
import { cacheKeys } from "../../utils/cache-keys";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import type {
|
||||
LoginOptions,
|
||||
LoginPayload,
|
||||
LoginPayloadData,
|
||||
} from "@thirdweb-dev/auth";
|
||||
import { GenericAuthWallet } from "@thirdweb-dev/wallets";
|
||||
import { signLoginPayload, type LoginPayloadData } from "@thirdweb-dev/auth";
|
||||
import invariant from "tiny-invariant";
|
||||
import { AUTH_TOKEN_STORAGE_KEY } from "../../../core/constants/auth";
|
||||
|
||||
@@ -59,7 +54,7 @@ export function useLogin() {
|
||||
throw new Error(`Failed to get payload`);
|
||||
}
|
||||
|
||||
const payload = await doLoginWithPayload(wallet, payloadData);
|
||||
const payload = await signLoginPayload({ wallet, payload: payloadData });
|
||||
|
||||
res = await fetch(`${authConfig.authUrl}/login`, {
|
||||
method: "POST",
|
||||
@@ -93,106 +88,3 @@ export function useLogin() {
|
||||
isLoading: login.isLoading,
|
||||
};
|
||||
}
|
||||
|
||||
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,
|
||||
chain_id: chainId,
|
||||
nonce: options?.nonce || nonce,
|
||||
issued_at: new Date().toISOString(),
|
||||
expiration_time: new Date(
|
||||
options?.expirationTime || Date.now() + 1000 * 60 * 10,
|
||||
).toISOString(),
|
||||
invalid_before: new Date(
|
||||
options?.invalidBefore || Date.now() - 1000 * 60 * 10,
|
||||
).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");
|
||||
}
|
||||
|
||||
@@ -203,7 +203,12 @@ export {
|
||||
} from "./hooks/async/account-factory";
|
||||
|
||||
// account
|
||||
export { useAccountSigners, useSetAccountSigners } from "./hooks/async/account";
|
||||
export {
|
||||
useAccountSigners,
|
||||
useSetAccountSigners,
|
||||
useAccountAdmins,
|
||||
useAccountAdminsAndSigners,
|
||||
} from "./hooks/async/account";
|
||||
|
||||
// thirdweb hooks (work as long as at least `<ThirdwebSdkProvider>` is used)
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ const WrappedThirdwebSDKProvider = <TChains extends Chain[]>({
|
||||
signer,
|
||||
children,
|
||||
clientId,
|
||||
secretKey,
|
||||
}: React.PropsWithChildren<
|
||||
{ supportedChains: Readonly<TChains> } & Omit<
|
||||
ThirdwebSDKProviderProps<TChains>,
|
||||
@@ -92,7 +93,7 @@ const WrappedThirdwebSDKProvider = <TChains extends Chain[]>({
|
||||
// sdk from chainId
|
||||
sdk_ = new ThirdwebSDK(
|
||||
chainId,
|
||||
{ ...mergedOptions, clientId },
|
||||
{ ...mergedOptions, clientId, secretKey },
|
||||
storageInterface,
|
||||
);
|
||||
}
|
||||
@@ -113,7 +114,14 @@ const WrappedThirdwebSDKProvider = <TChains extends Chain[]>({
|
||||
(sdk_ as any)._chainId = chainId;
|
||||
|
||||
return sdk_;
|
||||
}, [activeChainId, supportedChains, sdkOptions, storageInterface, clientId]);
|
||||
}, [
|
||||
activeChainId,
|
||||
supportedChains,
|
||||
sdkOptions,
|
||||
storageInterface,
|
||||
clientId,
|
||||
secretKey,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
// if we have an sdk and a signer update the signer
|
||||
@@ -163,7 +171,7 @@ export const ThirdwebSDKProvider = <TChains extends Chain[]>({
|
||||
}: React.PropsWithChildren<ThirdwebSDKProviderProps<TChains>>) => {
|
||||
if (!clientId) {
|
||||
checkClientIdOrSecretKey(
|
||||
"No clientId provided in ThirdwebSDK. You will have limited access to thirdweb's services for storage, RPC, and account abstraction. You can get a clientId from https://thirdweb.com/create-api-key",
|
||||
"No API key. Please provide a clientId. It is required to access thirdweb's services. You can create a key at https://thirdweb.com/create-api-key",
|
||||
clientId,
|
||||
undefined,
|
||||
);
|
||||
|
||||
@@ -45,4 +45,7 @@ export interface ThirdwebSDKProviderProps<TChains extends Chain[]>
|
||||
|
||||
// client Id for thirdweb services
|
||||
clientId?: string;
|
||||
|
||||
// pass in a secret key when doing server side rendering
|
||||
secretKey?: string;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
# @thirdweb-dev/react-native-compat
|
||||
|
||||
## 0.2.48
|
||||
|
||||
## 0.2.47
|
||||
|
||||
## 0.2.46
|
||||
|
||||
## 0.2.45
|
||||
|
||||
## 0.2.44
|
||||
|
||||
## 0.2.43
|
||||
|
||||
## 0.2.42
|
||||
|
||||
## 0.2.41
|
||||
|
||||
## 0.2.40
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/react-native-compat",
|
||||
"description": "Shims for Thirdweb in React Native Projects",
|
||||
"version": "0.2.41",
|
||||
"version": "0.2.48",
|
||||
"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,83 @@
|
||||
# @thirdweb-dev/react-native
|
||||
|
||||
## 0.2.48
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1458](https://github.com/thirdweb-dev/js/pull/1458) [`588b2106`](https://github.com/thirdweb-dev/js/commit/588b21060139a7c0bf5805e2c629a16792ed2c76) Thanks [@kien-ngo](https://github.com/kien-ngo)! - Add `hideTestnetFaucet` to hide the "Request Testnet funds" button in ConnectWallet details dropdown in `@thirdweb-dev/react-native` and `@thirdweb-dev/react`.
|
||||
|
||||
```ts
|
||||
<ConnectWallet hideTestnetFaucet={true} />
|
||||
```
|
||||
|
||||
- Updated dependencies [[`73462ef1`](https://github.com/thirdweb-dev/js/commit/73462ef10800aeeb5976634e2bc6fb5d3e8501e4), [`27c225a5`](https://github.com/thirdweb-dev/js/commit/27c225a51221417592b5940887abd1ccb8b67e47), [`cb1c9937`](https://github.com/thirdweb-dev/js/commit/cb1c9937fadb2d06eb148cf9819f2b3601376308), [`70c4a119`](https://github.com/thirdweb-dev/js/commit/70c4a119d691a37ec999d9f6087902d532cc82ed), [`a1732663`](https://github.com/thirdweb-dev/js/commit/a17326634e758c3bf42f0cc3869b8792f1e18cc9), [`f0443bd9`](https://github.com/thirdweb-dev/js/commit/f0443bd989dbba50d0836d1cf274bfb2f44a53fd), [`cb1c9937`](https://github.com/thirdweb-dev/js/commit/cb1c9937fadb2d06eb148cf9819f2b3601376308), [`588b2106`](https://github.com/thirdweb-dev/js/commit/588b21060139a7c0bf5805e2c629a16792ed2c76), [`269e68c0`](https://github.com/thirdweb-dev/js/commit/269e68c0a15e8f78cb5b68c9456ca8094b9e1f30)]:
|
||||
- @thirdweb-dev/storage@1.2.5
|
||||
- @thirdweb-dev/wallets@1.1.12
|
||||
- @thirdweb-dev/sdk@3.10.48
|
||||
- @thirdweb-dev/chains@0.1.43
|
||||
- @thirdweb-dev/react-core@3.14.29
|
||||
|
||||
## 0.2.47
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`4c37af49`](https://github.com/thirdweb-dev/js/commit/4c37af49aa4fa66beb8ffe8ef556068a29f3c5d4), [`4b0e63dc`](https://github.com/thirdweb-dev/js/commit/4b0e63dcc0ca871ce9cef76f8a41ff290316741c)]:
|
||||
- @thirdweb-dev/storage@1.2.4
|
||||
- @thirdweb-dev/react-core@3.14.28
|
||||
- @thirdweb-dev/wallets@1.1.11
|
||||
- @thirdweb-dev/sdk@3.10.47
|
||||
|
||||
## 0.2.46
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1452](https://github.com/thirdweb-dev/js/pull/1452) [`3ba8ba42`](https://github.com/thirdweb-dev/js/commit/3ba8ba428845f5b2ae90ca73855be275fc78373c) Thanks [@iketw](https://github.com/iketw)! - Upgrade Coinbase wallet SDK; it adds support for React Native 0.72.3
|
||||
|
||||
- Updated dependencies [[`262edc6a`](https://github.com/thirdweb-dev/js/commit/262edc6a46792da88f49ff6ef0a756a932a6a0cf), [`262edc6a`](https://github.com/thirdweb-dev/js/commit/262edc6a46792da88f49ff6ef0a756a932a6a0cf), [`dfd120a3`](https://github.com/thirdweb-dev/js/commit/dfd120a3a9d1582c8b174265c92bf43dbbaf5c86)]:
|
||||
- @thirdweb-dev/chains@0.1.42
|
||||
- @thirdweb-dev/sdk@3.10.46
|
||||
- @thirdweb-dev/react-core@3.14.27
|
||||
- @thirdweb-dev/wallets@1.1.10
|
||||
|
||||
## 0.2.45
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`2a91113a`](https://github.com/thirdweb-dev/js/commit/2a91113a760733fcff2aec90041f69e15de33905)]:
|
||||
- @thirdweb-dev/sdk@3.10.45
|
||||
- @thirdweb-dev/react-core@3.14.26
|
||||
- @thirdweb-dev/wallets@1.1.9
|
||||
|
||||
## 0.2.44
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1429](https://github.com/thirdweb-dev/js/pull/1429) [`ab36d84f`](https://github.com/thirdweb-dev/js/commit/ab36d84f1ce5647fa52475b4a35ea29d5007ad9b) Thanks [@iketw](https://github.com/iketw)! - Pass secretKey in the React SDK for server-side rendering
|
||||
|
||||
- Updated dependencies [[`a5d0be93`](https://github.com/thirdweb-dev/js/commit/a5d0be939a143095e769b68cf86360bfe4720744), [`c0a6d2f1`](https://github.com/thirdweb-dev/js/commit/c0a6d2f18231310d143c9b0cb1b2ff59315087a4), [`a9f2ff73`](https://github.com/thirdweb-dev/js/commit/a9f2ff73c9f83f05c3e2d3c53b23b2843e8a2576), [`fd981655`](https://github.com/thirdweb-dev/js/commit/fd9816556fe595b0c764e34dbcf15b0ad1677edb), [`becbb637`](https://github.com/thirdweb-dev/js/commit/becbb637367285ed3d8d7d131e1020bf23e38298), [`2283d210`](https://github.com/thirdweb-dev/js/commit/2283d21027503e047c25df5ebb21bdde0734be9e), [`fd981655`](https://github.com/thirdweb-dev/js/commit/fd9816556fe595b0c764e34dbcf15b0ad1677edb), [`ab36d84f`](https://github.com/thirdweb-dev/js/commit/ab36d84f1ce5647fa52475b4a35ea29d5007ad9b), [`c9bf4f05`](https://github.com/thirdweb-dev/js/commit/c9bf4f05c161707c6eb799ecef82f462e4a82405), [`67b145b9`](https://github.com/thirdweb-dev/js/commit/67b145b94dafb2fb1d90553ed4829f0ed22e2907), [`5ee700e8`](https://github.com/thirdweb-dev/js/commit/5ee700e80438650fa253c25c0bee6658ce68d2cf), [`9f5adc5c`](https://github.com/thirdweb-dev/js/commit/9f5adc5c5c2782ffb878759df481e5fb1e1740e5)]:
|
||||
- @thirdweb-dev/sdk@3.10.44
|
||||
- @thirdweb-dev/wallets@1.1.8
|
||||
- @thirdweb-dev/react-core@3.14.25
|
||||
- @thirdweb-dev/chains@0.1.41
|
||||
|
||||
## 0.2.43
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`3b6b0746`](https://github.com/thirdweb-dev/js/commit/3b6b0746b3fc792f4c5092814a7abfabcbc9801e), [`b0ec1d80`](https://github.com/thirdweb-dev/js/commit/b0ec1d80839efccad11b50afbf2216c2c132cf7e)]:
|
||||
- @thirdweb-dev/storage@1.2.3
|
||||
- @thirdweb-dev/wallets@1.1.7
|
||||
- @thirdweb-dev/sdk@3.10.43
|
||||
- @thirdweb-dev/react-core@3.14.24
|
||||
|
||||
## 0.2.42
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`fbde927a`](https://github.com/thirdweb-dev/js/commit/fbde927a0cb36a6269e045d8e577536f23164ef7)]:
|
||||
- @thirdweb-dev/wallets@1.1.6
|
||||
- @thirdweb-dev/react-core@3.14.23
|
||||
|
||||
## 0.2.41
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/react-native",
|
||||
"version": "0.2.41",
|
||||
"version": "0.2.48",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-native",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"license": "Apache-2.0",
|
||||
@@ -24,7 +24,7 @@
|
||||
"android"
|
||||
],
|
||||
"dependencies": {
|
||||
"@coinbase/wallet-mobile-sdk": "1.0.6",
|
||||
"@coinbase/wallet-mobile-sdk": "1.0.7",
|
||||
"@magic-sdk/provider": "17.2.0",
|
||||
"@magic-sdk/react-native-bare": "^18.5.0",
|
||||
"@shopify/restyle": "^2.4.2",
|
||||
|
||||
@@ -19,6 +19,13 @@ export type ConnectWalletProps = {
|
||||
* render custom rows in the Connect Wallet Details modal
|
||||
*/
|
||||
extraRows?: ConnectWalletDetailsProps["extraRows"];
|
||||
|
||||
/**
|
||||
* Hide option to request testnet funds for testnets in dropdown
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
hideTestnetFaucet?: boolean;
|
||||
} & ConnectWalletButtonProps;
|
||||
|
||||
export const ConnectWallet = ({
|
||||
@@ -27,6 +34,7 @@ export const ConnectWallet = ({
|
||||
buttonTitle,
|
||||
modalTitle,
|
||||
extraRows,
|
||||
hideTestnetFaucet,
|
||||
}: ConnectWalletProps) => {
|
||||
const fadeAnim = useRef(new Animated.Value(0)).current;
|
||||
const address = useAddress();
|
||||
@@ -47,6 +55,7 @@ export const ConnectWallet = ({
|
||||
address={address}
|
||||
detailsButton={detailsButton}
|
||||
extraRows={extraRows}
|
||||
hideTestnetFaucet={hideTestnetFaucet}
|
||||
/>
|
||||
) : (
|
||||
<ConnectWalletButton
|
||||
|
||||
+3
-1
@@ -32,11 +32,13 @@ export const ConnectWalletDetailsModal = ({
|
||||
onClosePress,
|
||||
extraRows,
|
||||
address,
|
||||
hideTestnetFaucet,
|
||||
}: {
|
||||
isVisible: boolean;
|
||||
onClosePress: () => void;
|
||||
extraRows?: React.FC;
|
||||
address?: string;
|
||||
hideTestnetFaucet?: boolean;
|
||||
}) => {
|
||||
const theme = useAppTheme();
|
||||
const [isExportModalVisible, setIsExportModalVisible] = useState(false);
|
||||
@@ -198,7 +200,7 @@ export const ConnectWalletDetailsModal = ({
|
||||
<Text variant="bodySmallSecondary">Current Network</Text>
|
||||
</View>
|
||||
<NetworkButton chain={chain} enableSwitchModal={true} />
|
||||
{chain?.testnet && chain?.faucets?.length ? (
|
||||
{!hideTestnetFaucet && chain?.testnet && chain?.faucets?.length ? (
|
||||
<IconTextButton
|
||||
mt="xs"
|
||||
text="Request Testnet Funds"
|
||||
|
||||
@@ -14,12 +14,14 @@ export type ConnectWalletDetailsProps = {
|
||||
address?: string;
|
||||
detailsButton?: React.FC<{ onPress: () => void }>;
|
||||
extraRows?: React.FC;
|
||||
hideTestnetFaucet?: boolean;
|
||||
};
|
||||
|
||||
export const WalletDetailsButton = ({
|
||||
address,
|
||||
detailsButton,
|
||||
extraRows,
|
||||
hideTestnetFaucet,
|
||||
}: ConnectWalletDetailsProps) => {
|
||||
const activeWallet = useWallet();
|
||||
const chain = useChain();
|
||||
@@ -46,6 +48,7 @@ export const WalletDetailsButton = ({
|
||||
onClosePress={onPress}
|
||||
extraRows={extraRows}
|
||||
address={address}
|
||||
hideTestnetFaucet={hideTestnetFaucet}
|
||||
/>
|
||||
{detailsButton ? (
|
||||
detailsButton({ onPress })
|
||||
|
||||
@@ -18,7 +18,10 @@ import { walletIds } from "@thirdweb-dev/wallets";
|
||||
import { ThirdwebStorage } from "../../core/storage/storage";
|
||||
|
||||
interface ThirdwebProviderProps<TChains extends Chain[]>
|
||||
extends Omit<ThirdwebProviderCoreProps<TChains>, "supportedWallets"> {
|
||||
extends Omit<
|
||||
ThirdwebProviderCoreProps<TChains>,
|
||||
"supportedWallets" | "secretKey"
|
||||
> {
|
||||
/**
|
||||
* Wallets that will be supported by the dApp
|
||||
* @defaultValue [MetaMaskWallet, CoinbaseWallet]
|
||||
|
||||
@@ -1,5 +1,80 @@
|
||||
# @thirdweb-dev/react
|
||||
|
||||
## 3.14.29
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1458](https://github.com/thirdweb-dev/js/pull/1458) [`588b2106`](https://github.com/thirdweb-dev/js/commit/588b21060139a7c0bf5805e2c629a16792ed2c76) Thanks [@kien-ngo](https://github.com/kien-ngo)! - Add `hideTestnetFaucet` to hide the "Request Testnet funds" button in ConnectWallet details dropdown in `@thirdweb-dev/react-native` and `@thirdweb-dev/react`.
|
||||
|
||||
```ts
|
||||
<ConnectWallet hideTestnetFaucet={true} />
|
||||
```
|
||||
|
||||
- Updated dependencies [[`73462ef1`](https://github.com/thirdweb-dev/js/commit/73462ef10800aeeb5976634e2bc6fb5d3e8501e4), [`cb1c9937`](https://github.com/thirdweb-dev/js/commit/cb1c9937fadb2d06eb148cf9819f2b3601376308), [`70c4a119`](https://github.com/thirdweb-dev/js/commit/70c4a119d691a37ec999d9f6087902d532cc82ed), [`a1732663`](https://github.com/thirdweb-dev/js/commit/a17326634e758c3bf42f0cc3869b8792f1e18cc9), [`f0443bd9`](https://github.com/thirdweb-dev/js/commit/f0443bd989dbba50d0836d1cf274bfb2f44a53fd), [`cb1c9937`](https://github.com/thirdweb-dev/js/commit/cb1c9937fadb2d06eb148cf9819f2b3601376308), [`588b2106`](https://github.com/thirdweb-dev/js/commit/588b21060139a7c0bf5805e2c629a16792ed2c76), [`269e68c0`](https://github.com/thirdweb-dev/js/commit/269e68c0a15e8f78cb5b68c9456ca8094b9e1f30)]:
|
||||
- @thirdweb-dev/wallets@1.1.12
|
||||
- @thirdweb-dev/sdk@3.10.48
|
||||
- @thirdweb-dev/chains@0.1.43
|
||||
- @thirdweb-dev/react-core@3.14.29
|
||||
|
||||
## 3.14.28
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`4b0e63dc`](https://github.com/thirdweb-dev/js/commit/4b0e63dcc0ca871ce9cef76f8a41ff290316741c)]:
|
||||
- @thirdweb-dev/react-core@3.14.28
|
||||
- @thirdweb-dev/wallets@1.1.11
|
||||
- @thirdweb-dev/sdk@3.10.47
|
||||
|
||||
## 3.14.27
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`262edc6a`](https://github.com/thirdweb-dev/js/commit/262edc6a46792da88f49ff6ef0a756a932a6a0cf), [`262edc6a`](https://github.com/thirdweb-dev/js/commit/262edc6a46792da88f49ff6ef0a756a932a6a0cf), [`dfd120a3`](https://github.com/thirdweb-dev/js/commit/dfd120a3a9d1582c8b174265c92bf43dbbaf5c86)]:
|
||||
- @thirdweb-dev/chains@0.1.42
|
||||
- @thirdweb-dev/sdk@3.10.46
|
||||
- @thirdweb-dev/react-core@3.14.27
|
||||
- @thirdweb-dev/wallets@1.1.10
|
||||
|
||||
## 3.14.26
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`2a91113a`](https://github.com/thirdweb-dev/js/commit/2a91113a760733fcff2aec90041f69e15de33905)]:
|
||||
- @thirdweb-dev/sdk@3.10.45
|
||||
- @thirdweb-dev/react-core@3.14.26
|
||||
- @thirdweb-dev/wallets@1.1.9
|
||||
|
||||
## 3.14.25
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1429](https://github.com/thirdweb-dev/js/pull/1429) [`ab36d84f`](https://github.com/thirdweb-dev/js/commit/ab36d84f1ce5647fa52475b4a35ea29d5007ad9b) Thanks [@iketw](https://github.com/iketw)! - Pass secretKey in the React SDK for server-side rendering
|
||||
|
||||
- [#1430](https://github.com/thirdweb-dev/js/pull/1430) [`a9f2ff73`](https://github.com/thirdweb-dev/js/commit/a9f2ff73c9f83f05c3e2d3c53b23b2843e8a2576) Thanks [@MananTank](https://github.com/MananTank)! - - Add base-gor as a valid safe address prefix
|
||||
- Log failed to autoconnect error on react-core too
|
||||
- Updated dependencies [[`a5d0be93`](https://github.com/thirdweb-dev/js/commit/a5d0be939a143095e769b68cf86360bfe4720744), [`c0a6d2f1`](https://github.com/thirdweb-dev/js/commit/c0a6d2f18231310d143c9b0cb1b2ff59315087a4), [`a9f2ff73`](https://github.com/thirdweb-dev/js/commit/a9f2ff73c9f83f05c3e2d3c53b23b2843e8a2576), [`fd981655`](https://github.com/thirdweb-dev/js/commit/fd9816556fe595b0c764e34dbcf15b0ad1677edb), [`becbb637`](https://github.com/thirdweb-dev/js/commit/becbb637367285ed3d8d7d131e1020bf23e38298), [`2283d210`](https://github.com/thirdweb-dev/js/commit/2283d21027503e047c25df5ebb21bdde0734be9e), [`fd981655`](https://github.com/thirdweb-dev/js/commit/fd9816556fe595b0c764e34dbcf15b0ad1677edb), [`ab36d84f`](https://github.com/thirdweb-dev/js/commit/ab36d84f1ce5647fa52475b4a35ea29d5007ad9b), [`c9bf4f05`](https://github.com/thirdweb-dev/js/commit/c9bf4f05c161707c6eb799ecef82f462e4a82405), [`67b145b9`](https://github.com/thirdweb-dev/js/commit/67b145b94dafb2fb1d90553ed4829f0ed22e2907), [`5ee700e8`](https://github.com/thirdweb-dev/js/commit/5ee700e80438650fa253c25c0bee6658ce68d2cf), [`9f5adc5c`](https://github.com/thirdweb-dev/js/commit/9f5adc5c5c2782ffb878759df481e5fb1e1740e5)]:
|
||||
- @thirdweb-dev/sdk@3.10.44
|
||||
- @thirdweb-dev/wallets@1.1.8
|
||||
- @thirdweb-dev/react-core@3.14.25
|
||||
- @thirdweb-dev/chains@0.1.41
|
||||
|
||||
## 3.14.24
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`3b6b0746`](https://github.com/thirdweb-dev/js/commit/3b6b0746b3fc792f4c5092814a7abfabcbc9801e), [`b0ec1d80`](https://github.com/thirdweb-dev/js/commit/b0ec1d80839efccad11b50afbf2216c2c132cf7e)]:
|
||||
- @thirdweb-dev/wallets@1.1.7
|
||||
- @thirdweb-dev/sdk@3.10.43
|
||||
- @thirdweb-dev/react-core@3.14.24
|
||||
|
||||
## 3.14.23
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`fbde927a`](https://github.com/thirdweb-dev/js/commit/fbde927a0cb36a6269e045d8e577536f23164ef7)]:
|
||||
- @thirdweb-dev/wallets@1.1.6
|
||||
- @thirdweb-dev/react-core@3.14.23
|
||||
|
||||
## 3.14.22
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/react",
|
||||
"version": "3.14.22",
|
||||
"version": "3.14.29",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -56,7 +56,6 @@ interface ThirdwebProviderProps<TChains extends Chain[]>
|
||||
export const ThirdwebProvider = <
|
||||
TChains extends Chain[] = typeof defaultChains,
|
||||
>({
|
||||
clientId: clientId,
|
||||
supportedWallets,
|
||||
theme,
|
||||
children,
|
||||
@@ -69,7 +68,6 @@ export const ThirdwebProvider = <
|
||||
<ThemeProvider theme={theme === "dark" ? darkTheme : lightTheme}>
|
||||
<ThirdwebProviderCore
|
||||
theme={theme}
|
||||
clientId={clientId}
|
||||
supportedWallets={wallets}
|
||||
{...restProps}
|
||||
>
|
||||
|
||||
@@ -47,6 +47,13 @@ type ConnectWalletProps = {
|
||||
};
|
||||
style?: React.CSSProperties;
|
||||
networkSelector?: Omit<NetworkSelectorProps, "theme" | "onClose" | "chains">;
|
||||
|
||||
/**
|
||||
* Hide option to request testnet funds for testnets in dropdown
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
hideTestnetFaucet?: boolean;
|
||||
};
|
||||
|
||||
const TW_CONNECT_WALLET = "tw-connect-wallet";
|
||||
@@ -163,6 +170,7 @@ export const ConnectWallet: React.FC<ConnectWalletProps> = (props) => {
|
||||
theme={theme}
|
||||
style={props.style}
|
||||
detailsBtn={props.detailsBtn}
|
||||
hideTestnetFaucet={props.hideTestnetFaucet}
|
||||
onDisconnect={() => {
|
||||
if (authConfig?.authUrl) {
|
||||
logout();
|
||||
|
||||
@@ -65,6 +65,7 @@ export const ConnectedWalletDetails: React.FC<{
|
||||
networkSelector?: Omit<NetworkSelectorProps, "theme" | "onClose" | "chains">;
|
||||
className?: string;
|
||||
detailsBtn?: () => JSX.Element;
|
||||
hideTestnetFaucet?: boolean;
|
||||
}> = (props) => {
|
||||
const disconnect = useDisconnect();
|
||||
const chains = useSupportedChains();
|
||||
@@ -322,32 +323,33 @@ export const ConnectedWalletDetails: React.FC<{
|
||||
)}
|
||||
|
||||
{/* Request Testnet funds */}
|
||||
{((chain?.faucets && chain.faucets.length > 0) ||
|
||||
chain?.chainId === Localhost.chainId) && (
|
||||
<MenuLink
|
||||
href={chain?.faucets ? chain.faucets[0] : "#"}
|
||||
target="_blank"
|
||||
as="a"
|
||||
onClick={async (e) => {
|
||||
if (chain.chainId === Localhost.chainId) {
|
||||
e.preventDefault();
|
||||
setOpen(false);
|
||||
await sdk?.wallet.requestFunds(10);
|
||||
await balanceQuery.refetch();
|
||||
}
|
||||
}}
|
||||
style={{
|
||||
textDecoration: "none",
|
||||
color: "inherit",
|
||||
fontSize: fontSize.sm,
|
||||
}}
|
||||
>
|
||||
<SecondaryIconContainer>
|
||||
<FundsIcon size={iconSize.sm} />
|
||||
</SecondaryIconContainer>
|
||||
Request Testnet Funds
|
||||
</MenuLink>
|
||||
)}
|
||||
{!props.hideTestnetFaucet &&
|
||||
((chain?.faucets && chain.faucets.length > 0) ||
|
||||
chain?.chainId === Localhost.chainId) && (
|
||||
<MenuLink
|
||||
href={chain?.faucets ? chain.faucets[0] : "#"}
|
||||
target="_blank"
|
||||
as="a"
|
||||
onClick={async (e) => {
|
||||
if (chain.chainId === Localhost.chainId) {
|
||||
e.preventDefault();
|
||||
setOpen(false);
|
||||
await sdk?.wallet.requestFunds(10);
|
||||
await balanceQuery.refetch();
|
||||
}
|
||||
}}
|
||||
style={{
|
||||
textDecoration: "none",
|
||||
color: "inherit",
|
||||
fontSize: fontSize.sm,
|
||||
}}
|
||||
>
|
||||
<SecondaryIconContainer>
|
||||
<FundsIcon size={iconSize.sm} />
|
||||
</SecondaryIconContainer>
|
||||
Request Testnet Funds
|
||||
</MenuLink>
|
||||
)}
|
||||
|
||||
{/* Export Wallet */}
|
||||
{activeWallet?.walletId === walletIds.localWallet && (
|
||||
|
||||
@@ -39,6 +39,7 @@ export const gnosisAddressPrefixToChainId = {
|
||||
bnb: 56,
|
||||
oeth: 10,
|
||||
gor: 5,
|
||||
"base-gor": 84531,
|
||||
} as const;
|
||||
|
||||
export const SelectAccount: React.FC<{
|
||||
|
||||
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user