Compare commits
41
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
d275493c59 | ||
|
|
256ee0d5ec |
@@ -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,5 +1,58 @@
|
||||
# @thirdweb-dev/auth
|
||||
|
||||
## 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
|
||||
|
||||
- [#1415](https://github.com/thirdweb-dev/js/pull/1415) [`256ee0d5`](https://github.com/thirdweb-dev/js/commit/256ee0d5ec9c8598aa79cd4cb1fd839c6cc7d390) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Downgrade preconstruct to 2.7.0
|
||||
|
||||
- Updated dependencies [[`256ee0d5`](https://github.com/thirdweb-dev/js/commit/256ee0d5ec9c8598aa79cd4cb1fd839c6cc7d390)]:
|
||||
- @thirdweb-dev/wallets@1.1.5
|
||||
|
||||
## 3.2.21
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/auth",
|
||||
"version": "3.2.21",
|
||||
"version": "3.2.28",
|
||||
"main": "dist/thirdweb-dev-auth.cjs.js",
|
||||
"module": "dist/thirdweb-dev-auth.esm.js",
|
||||
"browser": {
|
||||
@@ -86,7 +86,7 @@
|
||||
"@microsoft/api-documenter": "^7.22.30",
|
||||
"@microsoft/api-extractor": "^7.36.3",
|
||||
"@microsoft/tsdoc": "^0.14.1",
|
||||
"@preconstruct/cli": "^2.8.1",
|
||||
"@preconstruct/cli": "2.7.0",
|
||||
"@solana/web3.js": "^1.62.0",
|
||||
"@swc-node/register": "^1.6.6",
|
||||
"@swc/core": "^1.3.71",
|
||||
|
||||
+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,25 @@
|
||||
# @thirdweb-dev/chains
|
||||
|
||||
## 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
|
||||
|
||||
- [#1415](https://github.com/thirdweb-dev/js/pull/1415) [`256ee0d5`](https://github.com/thirdweb-dev/js/commit/256ee0d5ec9c8598aa79cd4cb1fd839c6cc7d390) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Downgrade preconstruct to 2.7.0
|
||||
|
||||
## 0.1.39
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Mintara Mainnet",
|
||||
"title": "Mintara Mainnet",
|
||||
"chain": "Mintara",
|
||||
"icon": {
|
||||
"url": "ipfs://bafybeie7jzlzlpz7c3a3oh4x5joej23dj2qf3cexmchjyc72hv3fblcaja",
|
||||
"width": 256,
|
||||
"height": 256,
|
||||
"format": "png"
|
||||
},
|
||||
"rpc": [
|
||||
"https://mintara.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://subnets.avax.network/mintara/mainnet/rpc"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "MINTARA",
|
||||
"symbol": "MNTR",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://playthink.co.jp",
|
||||
"shortName": "mintara",
|
||||
"chainId": 1080,
|
||||
"networkId": 1080,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "explorer",
|
||||
"url": "https://subnets.avax.network/mintara",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "mintara"
|
||||
} 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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -0,0 +1,42 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "PEER Testnet",
|
||||
"chain": "PEER",
|
||||
"rpc": [
|
||||
"https://peer-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"http://testnet-polka-host-232813573.us-west-1.elb.amazonaws.com"
|
||||
],
|
||||
"faucets": [
|
||||
"https://testnet.peer.inc"
|
||||
],
|
||||
"nativeCurrency": {
|
||||
"name": "PEER Token",
|
||||
"symbol": "PEER",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://peer.inc",
|
||||
"shortName": "PEER",
|
||||
"chainId": 601,
|
||||
"networkId": 601,
|
||||
"icon": {
|
||||
"url": "ipfs://QmPKKCdjEhP6CHekLD8YnhR2VsdjzprHapapDj7Wzqm52b",
|
||||
"width": 1363,
|
||||
"height": 760,
|
||||
"format": "png"
|
||||
},
|
||||
"explorers": [
|
||||
{
|
||||
"name": "PEER Explorer",
|
||||
"url": "https://testnet.peer.inc",
|
||||
"standard": "none",
|
||||
"icon": {
|
||||
"url": "ipfs://QmPKKCdjEhP6CHekLD8YnhR2VsdjzprHapapDj7Wzqm52b",
|
||||
"width": 1363,
|
||||
"height": 760,
|
||||
"format": "png"
|
||||
}
|
||||
}
|
||||
],
|
||||
"testnet": true,
|
||||
"slug": "peer-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;
|
||||
@@ -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,39 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "IMPERIUM TESTNET",
|
||||
"chain": "tIMP",
|
||||
"rpc": [],
|
||||
"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,39 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "IMPERIUM MAINNET",
|
||||
"chain": "IMP",
|
||||
"rpc": [],
|
||||
"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": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/chains",
|
||||
"version": "0.1.39",
|
||||
"version": "0.1.42",
|
||||
"main": "dist/thirdweb-dev-chains.cjs.js",
|
||||
"module": "dist/thirdweb-dev-chains.esm.js",
|
||||
"browser": {
|
||||
@@ -27,7 +27,7 @@
|
||||
"@babel/preset-env": "^7.22.9",
|
||||
"@babel/preset-typescript": "^7.22.5",
|
||||
"@babel/runtime": "^7.22.6",
|
||||
"@preconstruct/cli": "^2.8.1",
|
||||
"@preconstruct/cli": "2.7.0",
|
||||
"@thirdweb-dev/tsconfig": "workspace:*",
|
||||
"@types/jest": "^29.5.3",
|
||||
"axios": "^1.4.0",
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,5 +1,59 @@
|
||||
# thirdweb
|
||||
|
||||
## 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
|
||||
|
||||
- Updated dependencies [[`256ee0d5`](https://github.com/thirdweb-dev/js/commit/256ee0d5ec9c8598aa79cd4cb1fd839c6cc7d390)]:
|
||||
- @thirdweb-dev/storage@1.2.2
|
||||
- @thirdweb-dev/chains@0.1.40
|
||||
- @thirdweb-dev/sdk@3.10.42
|
||||
|
||||
## 0.11.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "thirdweb",
|
||||
"main": "dist/cli/index.js",
|
||||
"version": "0.11.5",
|
||||
"version": "0.11.11",
|
||||
"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,11 @@
|
||||
# @thirdweb-dev/pay
|
||||
|
||||
## 0.1.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1415](https://github.com/thirdweb-dev/js/pull/1415) [`256ee0d5`](https://github.com/thirdweb-dev/js/commit/256ee0d5ec9c8598aa79cd4cb1fd839c6cc7d390) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Downgrade preconstruct to 2.7.0
|
||||
|
||||
## 0.1.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/pay",
|
||||
"version": "0.1.3",
|
||||
"version": "0.1.4",
|
||||
"main": "dist/thirdweb-dev-pay.cjs.js",
|
||||
"module": "dist/thirdweb-dev-pay.esm.js",
|
||||
"exports": {
|
||||
@@ -36,7 +36,7 @@
|
||||
"@coinbase/cbpay-js": "^1.7.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@preconstruct/cli": "^2.8.1",
|
||||
"@preconstruct/cli": "2.7.0",
|
||||
"@thirdweb-dev/tsconfig": "workspace:*",
|
||||
"eslint-config-thirdweb": "workspace:*",
|
||||
"typescript": "^5.1.6"
|
||||
|
||||
@@ -1,5 +1,80 @@
|
||||
# @thirdweb-dev/react-core
|
||||
|
||||
## 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
|
||||
|
||||
- [#1415](https://github.com/thirdweb-dev/js/pull/1415) [`256ee0d5`](https://github.com/thirdweb-dev/js/commit/256ee0d5ec9c8598aa79cd4cb1fd839c6cc7d390) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Downgrade preconstruct to 2.7.0
|
||||
|
||||
- Updated dependencies [[`256ee0d5`](https://github.com/thirdweb-dev/js/commit/256ee0d5ec9c8598aa79cd4cb1fd839c6cc7d390)]:
|
||||
- @thirdweb-dev/storage@1.2.2
|
||||
- @thirdweb-dev/wallets@1.1.5
|
||||
- @thirdweb-dev/chains@0.1.40
|
||||
- @thirdweb-dev/sdk@3.10.42
|
||||
|
||||
## 3.14.21
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/react-core",
|
||||
"version": "3.14.21",
|
||||
"version": "3.14.28",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-core",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"license": "Apache-2.0",
|
||||
@@ -74,7 +74,7 @@
|
||||
"@microsoft/api-documenter": "^7.22.30",
|
||||
"@microsoft/api-extractor": "^7.36.3",
|
||||
"@microsoft/tsdoc": "^0.14.1",
|
||||
"@preconstruct/cli": "^2.8.1",
|
||||
"@preconstruct/cli": "2.7.0",
|
||||
"@solana/wallet-adapter-react": "^0.15.19",
|
||||
"@solana/web3.js": "^1.62.0",
|
||||
"@thirdweb-dev/auth": "workspace:*",
|
||||
@@ -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.47
|
||||
|
||||
## 0.2.46
|
||||
|
||||
## 0.2.45
|
||||
|
||||
## 0.2.44
|
||||
|
||||
## 0.2.43
|
||||
|
||||
## 0.2.42
|
||||
|
||||
## 0.2.41
|
||||
|
||||
## 0.2.40
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/react-native-compat",
|
||||
"description": "Shims for Thirdweb in React Native Projects",
|
||||
"version": "0.2.40",
|
||||
"version": "0.2.47",
|
||||
"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,77 @@
|
||||
# @thirdweb-dev/react-native
|
||||
|
||||
## 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
|
||||
|
||||
- Updated dependencies [[`256ee0d5`](https://github.com/thirdweb-dev/js/commit/256ee0d5ec9c8598aa79cd4cb1fd839c6cc7d390)]:
|
||||
- @thirdweb-dev/react-core@3.14.22
|
||||
- @thirdweb-dev/storage@1.2.2
|
||||
- @thirdweb-dev/wallets@1.1.5
|
||||
- @thirdweb-dev/chains@0.1.40
|
||||
- @thirdweb-dev/sdk@3.10.42
|
||||
|
||||
## 0.2.40
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/react-native",
|
||||
"version": "0.2.40",
|
||||
"version": "0.2.47",
|
||||
"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",
|
||||
|
||||
@@ -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,76 @@
|
||||
# @thirdweb-dev/react
|
||||
|
||||
## 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
|
||||
|
||||
- [#1415](https://github.com/thirdweb-dev/js/pull/1415) [`256ee0d5`](https://github.com/thirdweb-dev/js/commit/256ee0d5ec9c8598aa79cd4cb1fd839c6cc7d390) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Downgrade preconstruct to 2.7.0
|
||||
|
||||
- Updated dependencies [[`256ee0d5`](https://github.com/thirdweb-dev/js/commit/256ee0d5ec9c8598aa79cd4cb1fd839c6cc7d390)]:
|
||||
- @thirdweb-dev/react-core@3.14.22
|
||||
- @thirdweb-dev/wallets@1.1.5
|
||||
- @thirdweb-dev/chains@0.1.40
|
||||
- @thirdweb-dev/sdk@3.10.42
|
||||
|
||||
## 3.14.21
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/react",
|
||||
"version": "3.14.21",
|
||||
"version": "3.14.28",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"license": "Apache-2.0",
|
||||
@@ -89,7 +89,7 @@
|
||||
"@microsoft/api-documenter": "^7.22.30",
|
||||
"@microsoft/api-extractor": "^7.36.3",
|
||||
"@microsoft/tsdoc": "^0.14.1",
|
||||
"@preconstruct/cli": "^2.8.1",
|
||||
"@preconstruct/cli": "2.7.0",
|
||||
"@solana/wallet-adapter-base": "^0.9.17",
|
||||
"@solana/wallet-adapter-phantom": "^0.9.17",
|
||||
"@solana/wallet-adapter-react": "^0.15.19",
|
||||
|
||||
@@ -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}
|
||||
>
|
||||
|
||||
@@ -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
@@ -1,5 +1,66 @@
|
||||
# @thirdweb-dev/sdk
|
||||
|
||||
## 3.10.47
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`4c37af49`](https://github.com/thirdweb-dev/js/commit/4c37af49aa4fa66beb8ffe8ef556068a29f3c5d4)]:
|
||||
- @thirdweb-dev/storage@1.2.4
|
||||
|
||||
## 3.10.46
|
||||
|
||||
### 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)! - Sanitize description strings for OpenEdition sharedMetadata
|
||||
|
||||
- Updated dependencies [[`262edc6a`](https://github.com/thirdweb-dev/js/commit/262edc6a46792da88f49ff6ef0a756a932a6a0cf)]:
|
||||
- @thirdweb-dev/chains@0.1.42
|
||||
|
||||
## 3.10.45
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1449](https://github.com/thirdweb-dev/js/pull/1449) [`2a91113a`](https://github.com/thirdweb-dev/js/commit/2a91113a760733fcff2aec90041f69e15de33905) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Revert sanitizing inputs
|
||||
|
||||
## 3.10.44
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1444](https://github.com/thirdweb-dev/js/pull/1444) [`a5d0be93`](https://github.com/thirdweb-dev/js/commit/a5d0be939a143095e769b68cf86360bfe4720744) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Optimize claimConditions.getAll()
|
||||
|
||||
- [#1438](https://github.com/thirdweb-dev/js/pull/1438) [`c0a6d2f1`](https://github.com/thirdweb-dev/js/commit/c0a6d2f18231310d143c9b0cb1b2ff59315087a4) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Add sdk.deployer.deployOpenEdition() convenience function
|
||||
|
||||
- [#1441](https://github.com/thirdweb-dev/js/pull/1441) [`becbb637`](https://github.com/thirdweb-dev/js/commit/becbb637367285ed3d8d7d131e1020bf23e38298) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Sanitize NFT description input strings
|
||||
|
||||
- [#1433](https://github.com/thirdweb-dev/js/pull/1433) [`c9bf4f05`](https://github.com/thirdweb-dev/js/commit/c9bf4f05c161707c6eb799ecef82f462e4a82405) Thanks [@iketw](https://github.com/iketw)! - Pass empty string when clientId is undefined
|
||||
|
||||
- [#1439](https://github.com/thirdweb-dev/js/pull/1439) [`67b145b9`](https://github.com/thirdweb-dev/js/commit/67b145b94dafb2fb1d90553ed4829f0ed22e2907) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Expose deployPublishContract alias
|
||||
|
||||
- [#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 [[`fd981655`](https://github.com/thirdweb-dev/js/commit/fd9816556fe595b0c764e34dbcf15b0ad1677edb), [`9f5adc5c`](https://github.com/thirdweb-dev/js/commit/9f5adc5c5c2782ffb878759df481e5fb1e1740e5), [`9f5adc5c`](https://github.com/thirdweb-dev/js/commit/9f5adc5c5c2782ffb878759df481e5fb1e1740e5)]:
|
||||
- @thirdweb-dev/chains@0.1.41
|
||||
- @thirdweb-dev/contracts-js@1.3.11
|
||||
|
||||
## 3.10.43
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1411](https://github.com/thirdweb-dev/js/pull/1411) [`3b6b0746`](https://github.com/thirdweb-dev/js/commit/3b6b0746b3fc792f4c5092814a7abfabcbc9801e) Thanks [@jnsdls](https://github.com/jnsdls)! - add auth token
|
||||
|
||||
- Updated dependencies [[`3b6b0746`](https://github.com/thirdweb-dev/js/commit/3b6b0746b3fc792f4c5092814a7abfabcbc9801e)]:
|
||||
- @thirdweb-dev/storage@1.2.3
|
||||
|
||||
## 3.10.42
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1415](https://github.com/thirdweb-dev/js/pull/1415) [`256ee0d5`](https://github.com/thirdweb-dev/js/commit/256ee0d5ec9c8598aa79cd4cb1fd839c6cc7d390) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Downgrade preconstruct to 2.7.0
|
||||
|
||||
- Updated dependencies [[`256ee0d5`](https://github.com/thirdweb-dev/js/commit/256ee0d5ec9c8598aa79cd4cb1fd839c6cc7d390)]:
|
||||
- @thirdweb-dev/storage@1.2.2
|
||||
- @thirdweb-dev/chains@0.1.40
|
||||
|
||||
## 3.10.41
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/sdk",
|
||||
"version": "3.10.41",
|
||||
"version": "3.10.47",
|
||||
"description": "The main thirdweb SDK.",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/sdk",
|
||||
"license": "Apache-2.0",
|
||||
@@ -107,7 +107,7 @@
|
||||
"@microsoft/api-extractor": "^7.36.3",
|
||||
"@microsoft/tsdoc": "^0.14.1",
|
||||
"@nomiclabs/hardhat-ethers": "^2.2.3",
|
||||
"@preconstruct/cli": "^2.8.1",
|
||||
"@preconstruct/cli": "2.7.0",
|
||||
"@project-serum/anchor": "^0.25.0",
|
||||
"@solana/spl-token": "^0.3.5",
|
||||
"@solana/web3.js": "^1.62.0",
|
||||
|
||||
@@ -60,7 +60,7 @@ export function getChainProvider(
|
||||
// if we still don't have an url fall back to just using the chainId or slug in the rpc and try that
|
||||
if (!rpcUrl) {
|
||||
rpcUrl = `https://${chainId || network}.rpc.thirdweb.com/${
|
||||
options.clientId
|
||||
options.clientId || ""
|
||||
}`;
|
||||
}
|
||||
|
||||
@@ -158,7 +158,7 @@ export function getProviderFromRpcUrl(
|
||||
chainId?: number,
|
||||
) {
|
||||
try {
|
||||
const headers: Record<string, string> = {};
|
||||
const headers: HeadersInit = {};
|
||||
if (isTwUrl(rpcUrl)) {
|
||||
if (sdkOptions?.clientId) {
|
||||
headers["x-client-id"] = sdkOptions?.clientId;
|
||||
@@ -173,6 +173,12 @@ export function getProviderFromRpcUrl(
|
||||
} else if (sdkOptions?.secretKey) {
|
||||
headers["x-secret-key"] = sdkOptions?.secretKey;
|
||||
}
|
||||
// if we have a tw auth token on global context add it to the headers
|
||||
if (typeof globalThis !== "undefined" && "TW_AUTH_TOKEN" in globalThis) {
|
||||
headers["authorization"] = `Bearer ${
|
||||
(globalThis as any).TW_AUTH_TOKEN as string
|
||||
}`;
|
||||
}
|
||||
}
|
||||
const match = rpcUrl.match(/^(ws|http)s?:/i);
|
||||
// Try the JSON batch provider if available
|
||||
|
||||
@@ -270,6 +270,39 @@ export class Account<TContract extends IAccountCore>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all admins and non-admin signers with permissions to use the account.
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* const allAdminsAndSigners = await contract.account.getAllAdminsAndSigners();
|
||||
* ```
|
||||
*
|
||||
* @returns all admins and non-admin signers with permissions to use the account.
|
||||
*
|
||||
* @twfeature Account
|
||||
*/
|
||||
public async getAllAdminsAndSigners(): Promise<SignerWithPermissions[]> {
|
||||
const allAdmins = await this.getAllAdmins();
|
||||
const transformedAdmins: SignerWithPermissions[] = allAdmins.map(
|
||||
(admin) => {
|
||||
return {
|
||||
isAdmin: true,
|
||||
signer: admin,
|
||||
permissions: {
|
||||
startDate: new Date(0),
|
||||
expirationDate: new Date(0),
|
||||
nativeTokenLimitPerTransaction: BigNumber.from(0),
|
||||
approvedCallTargets: [],
|
||||
},
|
||||
};
|
||||
},
|
||||
);
|
||||
const allSigners = await this.getAllSigners();
|
||||
|
||||
return [...transformedAdmins, ...allSigners];
|
||||
}
|
||||
|
||||
/*********************************
|
||||
* WRITE FUNCTIONS
|
||||
********************************/
|
||||
|
||||
@@ -158,14 +158,17 @@ export class DropClaimConditions<
|
||||
await this.contractWrapper.readContract.claimCondition();
|
||||
const startId = currentStartId.toNumber();
|
||||
const count = countBn.toNumber();
|
||||
const conditions: AbstractClaimConditionContractStruct[] = [];
|
||||
const conditions: Promise<AbstractClaimConditionContractStruct>[] = [];
|
||||
for (let i = startId; i < startId + count; i++) {
|
||||
conditions.push(await this.get(i));
|
||||
conditions.push(this.get(i));
|
||||
}
|
||||
const metadata = await this.metadata.get();
|
||||
const decimals = await this.getTokenDecimals();
|
||||
const [metadata, decimals, ...fetchedConditions] = await Promise.all([
|
||||
this.metadata.get(),
|
||||
this.getTokenDecimals(),
|
||||
...conditions,
|
||||
]);
|
||||
return Promise.all(
|
||||
conditions.map((c) =>
|
||||
fetchedConditions.map((c) =>
|
||||
transformResultToClaimCondition(
|
||||
c,
|
||||
decimals,
|
||||
|
||||
@@ -87,6 +87,10 @@ export class Erc721SharedMetadata implements DetectableFeature {
|
||||
metadata: BasicNFTInput,
|
||||
): Promise<Transaction<TransactionResult>> => {
|
||||
const parsedMetadata = BasicNFTInput.parse(metadata);
|
||||
// cleanup description
|
||||
parsedMetadata.description = this.sanitizeJSONString(
|
||||
parsedMetadata.description,
|
||||
);
|
||||
|
||||
// take the input and upload image and animation if it is not a URI already
|
||||
const batch = [];
|
||||
@@ -122,4 +126,12 @@ export class Erc721SharedMetadata implements DetectableFeature {
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
private sanitizeJSONString(val: string | undefined | null) {
|
||||
if (!val) {
|
||||
return val;
|
||||
}
|
||||
const sanitized = JSON.stringify(val);
|
||||
return sanitized.slice(1, sanitized.length - 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,6 +89,7 @@ import type {
|
||||
DeployOptions,
|
||||
DeployMetadata,
|
||||
DeployEvent,
|
||||
OpenEditionContractDeployMetadata,
|
||||
} from "../types/deploy";
|
||||
import type { ContractWithMetadata } from "../types/registry";
|
||||
import { DeploySchemaForPrebuiltContractType } from "../contracts";
|
||||
@@ -113,6 +114,7 @@ import { LoyaltyCardContractDeploy } from "../schema/contracts/loyalty-card";
|
||||
import { getDefaultTrustedForwarders } from "../constants";
|
||||
import { checkClientIdOrSecretKey } from "../../core/utils/apiKey";
|
||||
import { getProcessEnv } from "../../core/utils/process";
|
||||
import { DropErc721ContractSchema } from "../schema";
|
||||
|
||||
/**
|
||||
* The main entry point for the thirdweb SDK
|
||||
@@ -263,11 +265,15 @@ export class ThirdwebSDK extends RPCConnectionHandler {
|
||||
storage?: IThirdwebStorage,
|
||||
) {
|
||||
const apiKeyType = typeof window !== "undefined" ? "clientId" : "secretKey";
|
||||
checkClientIdOrSecretKey(
|
||||
`No ${apiKeyType} provided in ThirdwebSDK. You will have limited access to thirdweb's services for storage, RPC, and account abstraction. You can get a ${apiKeyType} from https://thirdweb.com/create-api-key`,
|
||||
options.clientId,
|
||||
options.secretKey,
|
||||
);
|
||||
let warnMessage = `No API key. Please provide a ${apiKeyType}. It is required to access thirdweb's services. You can create a key at https://thirdweb.com/create-api-key`;
|
||||
if (
|
||||
typeof window === "undefined" &&
|
||||
!options.secretKey &&
|
||||
options.clientId
|
||||
) {
|
||||
warnMessage = `Please provide a secret key instead of the clientId. Create a new API Key at https://thirdweb.com/create-api-key`;
|
||||
}
|
||||
checkClientIdOrSecretKey(warnMessage, options.clientId, options.secretKey);
|
||||
|
||||
if (isChainConfig(network)) {
|
||||
options = {
|
||||
@@ -1021,6 +1027,63 @@ export class ContractDeployer extends RPCConnectionHandler {
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* Deploys a new OpenEditionERC721 contract
|
||||
*
|
||||
* @remarks Deploys a OpenEdition contract and returns the address of the deployed contract
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* const contractAddress = await sdk.deployer.deployOpenEdition({
|
||||
* name: "My Open Edition",
|
||||
* primary_sale_recipient: "your-address",
|
||||
* });
|
||||
* ```
|
||||
* @param metadata - the contract metadata
|
||||
* @returns the address of the deployed contract
|
||||
*/
|
||||
deployOpenEdition = /* @__PURE__ */ buildDeployTransactionFunction(
|
||||
async (
|
||||
metadata: OpenEditionContractDeployMetadata,
|
||||
options?: DeployOptions,
|
||||
): Promise<DeployTransaction> => {
|
||||
const parsedMetadata = await DropErc721ContractSchema.deploy.parseAsync(
|
||||
metadata,
|
||||
);
|
||||
const contractURI = await this.storage.upload(parsedMetadata);
|
||||
|
||||
const chainId = (await this.getProvider().getNetwork()).chainId;
|
||||
const trustedForwarders = getDefaultTrustedForwarders(chainId);
|
||||
// add default forwarders to any custom forwarders passed in
|
||||
if (
|
||||
metadata.trusted_forwarders &&
|
||||
metadata.trusted_forwarders.length > 0
|
||||
) {
|
||||
trustedForwarders.push(...metadata.trusted_forwarders);
|
||||
}
|
||||
|
||||
const signerAddress = await this.getSigner()?.getAddress();
|
||||
|
||||
const deployArgs = [
|
||||
signerAddress,
|
||||
parsedMetadata.name,
|
||||
parsedMetadata.symbol,
|
||||
contractURI,
|
||||
trustedForwarders,
|
||||
parsedMetadata.primary_sale_recipient,
|
||||
parsedMetadata.fee_recipient,
|
||||
parsedMetadata.seller_fee_basis_points,
|
||||
];
|
||||
|
||||
return await this.deployReleasedContract.prepare(
|
||||
THIRDWEB_DEPLOYER,
|
||||
"OpenEditionERC721",
|
||||
deployArgs,
|
||||
options,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* Deploys a new SignatureDrop contract
|
||||
*
|
||||
@@ -1457,6 +1520,8 @@ export class ContractDeployer extends RPCConnectionHandler {
|
||||
* @param publisherAddress the address of the publisher
|
||||
* @param contractName the name of the contract to deploy
|
||||
* @param constructorParams the constructor params to pass to the contract
|
||||
*
|
||||
* @deprecated use deployPublishedContract instead
|
||||
*/
|
||||
deployReleasedContract = /* @__PURE__ */ buildDeployTransactionFunction(
|
||||
async (
|
||||
@@ -1479,6 +1544,16 @@ export class ContractDeployer extends RPCConnectionHandler {
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* Deploy any published contract by its name
|
||||
* @param publisherAddress the address of the publisher
|
||||
* @param contractName the name of the contract to deploy
|
||||
* @param constructorParams the constructor params to pass to the contract
|
||||
* @param version Optional: the version of the contract to deploy or "latest"
|
||||
* @param options Optional: the deploy options
|
||||
*/
|
||||
deployPublishedContract = this.deployReleasedContract;
|
||||
|
||||
/**
|
||||
* Deploy a proxy contract of a given implementation via the given factory
|
||||
* @param factoryAddress
|
||||
@@ -2123,7 +2198,10 @@ export class ContractDeployer extends RPCConnectionHandler {
|
||||
version: string,
|
||||
) {
|
||||
const address = await resolveAddress(publisherAddress);
|
||||
const publishedContract = await new ThirdwebSDK("polygon")
|
||||
const publishedContract = await new ThirdwebSDK("polygon", {
|
||||
clientId: this.options.clientId,
|
||||
secretKey: this.options.secretKey,
|
||||
})
|
||||
.getPublisher()
|
||||
.getVersion(address, contractName, version);
|
||||
if (!publishedContract) {
|
||||
|
||||
@@ -23,6 +23,7 @@ export type SignerPermissionsInput = z.input<typeof SignerPermissionsSchema>;
|
||||
export type SignerPermissionsOutput = z.output<typeof SignerPermissionsSchema>;
|
||||
|
||||
export type SignerWithPermissions = {
|
||||
isAdmin?: boolean;
|
||||
signer: string;
|
||||
permissions: SignerPermissions;
|
||||
};
|
||||
|
||||
@@ -58,6 +58,53 @@ export interface NFTContractDeployMetadata {
|
||||
app_uri?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Options for deploying an OpenEdition contract
|
||||
* @public
|
||||
*/
|
||||
export interface OpenEditionContractDeployMetadata {
|
||||
/**
|
||||
* name of the contract
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* Optional description of the contract
|
||||
*/
|
||||
description?: string;
|
||||
/**
|
||||
* Optional image for the contract
|
||||
*/
|
||||
image?: FileOrBufferOrString;
|
||||
/**
|
||||
* Optional url for the contract
|
||||
*/
|
||||
external_link?: string;
|
||||
/**
|
||||
* Symbol for the NFTs
|
||||
*/
|
||||
symbol?: string;
|
||||
/**
|
||||
* Custom gasless trusted forwarder addresses
|
||||
*/
|
||||
trusted_forwarders?: AddressOrEns[];
|
||||
/**
|
||||
* The address that will receive the proceeds from primary sales
|
||||
*/
|
||||
primary_sale_recipient: AddressOrEns;
|
||||
/**
|
||||
* The address that will receive the proceeds from secondary sales (royalties)
|
||||
*/
|
||||
fee_recipient?: AddressOrEns;
|
||||
/**
|
||||
* The percentage (in basis points) of royalties for secondary sales
|
||||
*/
|
||||
seller_fee_basis_points?: number;
|
||||
/**
|
||||
* The default app for this contract
|
||||
*/
|
||||
app_uri?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Options for deploying a Token contract
|
||||
* @public
|
||||
|
||||
@@ -7,6 +7,8 @@ describe("Error Handling", async () => {
|
||||
it("should throw proper error on account with no balance", async () => {
|
||||
const newSdk = ThirdwebSDK.fromSigner(
|
||||
Wallet.createRandom().connect(sdk.getProvider()),
|
||||
undefined,
|
||||
{ secretKey: process.env.TW_SECRET_KEY },
|
||||
);
|
||||
|
||||
try {
|
||||
|
||||
@@ -1,5 +1,61 @@
|
||||
# @thirdweb-dev/service-utils
|
||||
|
||||
## 0.4.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1454](https://github.com/thirdweb-dev/js/pull/1454) [`6979810d`](https://github.com/thirdweb-dev/js/commit/6979810de5c3fc700c7b5b91ac1567d9cdf50607) Thanks [@nessup](https://github.com/nessup)! - Update error message
|
||||
|
||||
## 0.4.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#1448](https://github.com/thirdweb-dev/js/pull/1448) [`3e1c4045`](https://github.com/thirdweb-dev/js/commit/3e1c4045e7c58e2fe58e2ab6a7f767c8f5e206e9) Thanks [@arcoraven](https://github.com/arcoraven)! - Add logHttpRequest helper func
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1453](https://github.com/thirdweb-dev/js/pull/1453) [`0647f124`](https://github.com/thirdweb-dev/js/commit/0647f12498ed1cdd5aca4dcea5bd3cf0d5d3a23b) Thanks [@arcoraven](https://github.com/arcoraven)! - Remove clientId from logRequest
|
||||
|
||||
## 0.3.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1447](https://github.com/thirdweb-dev/js/pull/1447) [`b103872d`](https://github.com/thirdweb-dev/js/commit/b103872daff87b032082a433713d16b9dee13082) Thanks [@nessup](https://github.com/nessup)! - Export extractAuthorizationData for CF Workers
|
||||
|
||||
## 0.3.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#1424](https://github.com/thirdweb-dev/js/pull/1424) [`d01e6396`](https://github.com/thirdweb-dev/js/commit/d01e6396d176a162aaacb10792f0d9abade62a1f) Thanks [@arcoraven](https://github.com/arcoraven)! - Add helper to publish usage events from backend services
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1440](https://github.com/thirdweb-dev/js/pull/1440) [`5ec0f064`](https://github.com/thirdweb-dev/js/commit/5ec0f064d27acbd5225934dfe8ea2cd2c5af3997) Thanks [@arcoraven](https://github.com/arcoraven)! - [service-utils] Switch to aws4fetch to call AWS services
|
||||
|
||||
- [#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
|
||||
|
||||
- [#1435](https://github.com/thirdweb-dev/js/pull/1435) [`2a3cd62d`](https://github.com/thirdweb-dev/js/commit/2a3cd62dc9af6accae5c2c48ef4956d139a637e4) Thanks [@arcoraven](https://github.com/arcoraven)! - Use string type for gasPricePerUnit
|
||||
|
||||
## 0.2.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1411](https://github.com/thirdweb-dev/js/pull/1411) [`3b6b0746`](https://github.com/thirdweb-dev/js/commit/3b6b0746b3fc792f4c5092814a7abfabcbc9801e) Thanks [@jnsdls](https://github.com/jnsdls)! - allow account level auth via jwt
|
||||
|
||||
## 0.2.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1420](https://github.com/thirdweb-dev/js/pull/1420) [`952009cd`](https://github.com/thirdweb-dev/js/commit/952009cd73a1851dfef7a8f8c29ab6d73d580508) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Handle \* domain as public
|
||||
|
||||
- [#1417](https://github.com/thirdweb-dev/js/pull/1417) [`580e77b1`](https://github.com/thirdweb-dev/js/commit/580e77b17088a439208bd1411c71e9fb0c2cbb79) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Return accountId from authorize service call
|
||||
|
||||
## 0.2.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1415](https://github.com/thirdweb-dev/js/pull/1415) [`256ee0d5`](https://github.com/thirdweb-dev/js/commit/256ee0d5ec9c8598aa79cd4cb1fd839c6cc7d390) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Downgrade preconstruct to 2.7.0
|
||||
|
||||
## 0.2.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1 +1,7 @@
|
||||
### todo
|
||||
# Service Utils
|
||||
|
||||
This repository contains utilities that handle common requirements for thirdweb services.
|
||||
|
||||
- `/cf-worker`: for use only in Cloudflare Worker services
|
||||
- `/node`: for use in self-hosted services
|
||||
- `/core`: for use in any service
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/service-utils",
|
||||
"version": "0.2.2",
|
||||
"version": "0.4.1",
|
||||
"main": "dist/thirdweb-dev-service-utils.cjs.js",
|
||||
"module": "dist/thirdweb-dev-service-utils.esm.js",
|
||||
"exports": {
|
||||
@@ -40,7 +40,8 @@
|
||||
"sideEffects": false,
|
||||
"devDependencies": {
|
||||
"@cloudflare/workers-types": "^4.20230724.0",
|
||||
"@preconstruct/cli": "^2.8.1",
|
||||
"@preconstruct/cli": "2.7.0",
|
||||
"@smithy/types": "^2.0.2",
|
||||
"@thirdweb-dev/tsconfig": "workspace:*",
|
||||
"@types/jest": "^29.5.3",
|
||||
"@types/node": "^18.17.1",
|
||||
@@ -61,5 +62,9 @@
|
||||
"build": "tsc && preconstruct build",
|
||||
"push": "yalc push",
|
||||
"test": "jest"
|
||||
},
|
||||
"dependencies": {
|
||||
"aws4fetch": "^1.0.17",
|
||||
"zod": "^3.20.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
import type { ExecutionContext, KVNamespace } from "@cloudflare/workers-types";
|
||||
import type { ApiKeyMetadata, CoreServiceConfig } from "../core/api";
|
||||
import type {
|
||||
ExecutionContext,
|
||||
KVNamespace,
|
||||
Response,
|
||||
} from "@cloudflare/workers-types";
|
||||
import type {
|
||||
ApiKeyMetadata,
|
||||
AccountMetadata,
|
||||
CoreServiceConfig,
|
||||
} from "../core/api";
|
||||
import { authorize } from "../core/authorize";
|
||||
|
||||
import type { Request } from "@cloudflare/workers-types";
|
||||
@@ -8,6 +16,7 @@ import type { AuthorizationResult } from "../core/authorize/types";
|
||||
import type { CoreAuthInput } from "../core/types";
|
||||
|
||||
export * from "../core/services";
|
||||
export * from "./usage";
|
||||
|
||||
type WorkerServiceConfig = CoreServiceConfig & {
|
||||
kvStore: KVNamespace;
|
||||
@@ -47,7 +56,7 @@ export async function authorizeWorker(
|
||||
|
||||
return await authorize(authData, serviceConfig, {
|
||||
get: async (clientId: string) => serviceConfig.kvStore.get(clientId),
|
||||
put: (clientId: string, apiKeyMeta: ApiKeyMetadata) =>
|
||||
put: (clientId: string, apiKeyMeta: ApiKeyMetadata | AccountMetadata) =>
|
||||
serviceConfig.ctx.waitUntil(
|
||||
serviceConfig.kvStore.put(
|
||||
clientId,
|
||||
@@ -68,7 +77,7 @@ export async function authorizeWorker(
|
||||
});
|
||||
}
|
||||
|
||||
async function extractAuthorizationData(
|
||||
export async function extractAuthorizationData(
|
||||
authInput: AuthInput,
|
||||
): Promise<AuthorizationInput> {
|
||||
const requestUrl = new URL(authInput.req.url);
|
||||
@@ -124,7 +133,20 @@ async function extractAuthorizationData(
|
||||
clientId = derivedClientId;
|
||||
}
|
||||
|
||||
let jwt: string | null = null;
|
||||
if (headers.has("authorization")) {
|
||||
const authHeader = headers.get("authorization");
|
||||
if (authHeader) {
|
||||
const [type, token] = authHeader.split(" ");
|
||||
if (type.toLowerCase() === "bearer") {
|
||||
jwt = token;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
jwt,
|
||||
hashedJWT: jwt ? await hashSecretKey(jwt) : null,
|
||||
secretKey,
|
||||
clientId,
|
||||
origin,
|
||||
@@ -149,3 +171,33 @@ function bufferToHex(buffer: ArrayBuffer) {
|
||||
.map((x) => x.toString(16).padStart(2, "0"))
|
||||
.join("");
|
||||
}
|
||||
|
||||
export async function logHttpRequest({
|
||||
source,
|
||||
clientId,
|
||||
req,
|
||||
res,
|
||||
isAuthed,
|
||||
statusMessage,
|
||||
}: AuthInput & {
|
||||
source: string;
|
||||
res: Response;
|
||||
isAuthed?: boolean;
|
||||
statusMessage?: Error | string;
|
||||
}) {
|
||||
const authorizationData = await extractAuthorizationData({ req, clientId });
|
||||
|
||||
console.log(
|
||||
JSON.stringify({
|
||||
source,
|
||||
pathname: req.url,
|
||||
hasSecretKey: !!authorizationData.secretKey,
|
||||
hasClientId: !!authorizationData.clientId,
|
||||
hasJwt: !!authorizationData.jwt,
|
||||
clientId: authorizationData.clientId,
|
||||
isAuthed: !!isAuthed ?? null,
|
||||
status: res.status,
|
||||
}),
|
||||
);
|
||||
console.log(`statusMessage=${statusMessage ?? res.statusText}`);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
import { AwsClient } from "aws4fetch";
|
||||
import { z } from "zod";
|
||||
|
||||
// Initialize a singleton for aws usage.
|
||||
let _aws: AwsClient | undefined;
|
||||
function getAws(options: ConstructorParameters<typeof AwsClient>[0]) {
|
||||
if (!_aws) {
|
||||
_aws = new AwsClient(options);
|
||||
}
|
||||
return _aws;
|
||||
}
|
||||
|
||||
/**
|
||||
* Types
|
||||
*/
|
||||
const usageEventSchema = z.object({
|
||||
source: z.enum([
|
||||
"wallet",
|
||||
"rpc",
|
||||
"storage",
|
||||
"bundler",
|
||||
"paymaster",
|
||||
"relayer",
|
||||
]),
|
||||
action: z.string(),
|
||||
accountId: z.string(),
|
||||
|
||||
// Optional
|
||||
apiKeyId: z.string().optional(),
|
||||
creatorWalletAddress: z.string().optional(),
|
||||
clientId: z.string().optional(),
|
||||
walletAddress: z.string().optional(),
|
||||
chainId: z.number().int().positive().optional(),
|
||||
provider: z.string().optional(),
|
||||
mimeType: z.string().optional(),
|
||||
fileSize: z.number().int().nonnegative().optional(),
|
||||
fileCid: z.string().optional(),
|
||||
transactionHash: z.string().optional(),
|
||||
gasLimit: z.number().nonnegative().optional(),
|
||||
gasPricePerUnit: z.string().optional(),
|
||||
});
|
||||
export type UsageEvent = z.infer<typeof usageEventSchema>;
|
||||
|
||||
/**
|
||||
* Publish usage events. Provide the relevant fields for your application.
|
||||
*
|
||||
* Usage in Cloudflare Workers:
|
||||
* ctx.waitUntil(
|
||||
* publishUsageEvents(
|
||||
* [event1, event2],
|
||||
* { queueUrl, accessKeyId, secretAccessKey },
|
||||
* )
|
||||
* )
|
||||
*
|
||||
* @param usageEvents
|
||||
* @param config
|
||||
*/
|
||||
export async function publishUsageEvents(
|
||||
usageEvents: UsageEvent[],
|
||||
config: {
|
||||
queueUrl: string;
|
||||
accessKeyId: string;
|
||||
secretAccessKey: string;
|
||||
region?: string;
|
||||
},
|
||||
): Promise<string> {
|
||||
const {
|
||||
queueUrl,
|
||||
accessKeyId,
|
||||
secretAccessKey,
|
||||
region = "us-west-2",
|
||||
} = config;
|
||||
|
||||
const entries = usageEvents.map((event) => ({
|
||||
Id: crypto.randomUUID(),
|
||||
MessageBody: JSON.stringify(event),
|
||||
}));
|
||||
|
||||
const aws = getAws({
|
||||
accessKeyId,
|
||||
secretAccessKey,
|
||||
region,
|
||||
});
|
||||
const res = await aws.fetch(`https://sqs.${region}.amazonaws.com`, {
|
||||
headers: {
|
||||
"X-Amz-Target": "AmazonSQS.SendMessageBatch",
|
||||
"X-Amz-Date": new Date().toISOString(),
|
||||
"Content-Type": "application/x-amz-json-1.0",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
QueueUrl: queueUrl,
|
||||
Entries: entries,
|
||||
}),
|
||||
});
|
||||
return await res.text();
|
||||
}
|
||||
@@ -11,6 +11,7 @@ export type CoreServiceConfig = {
|
||||
export type ApiKeyMetadata = {
|
||||
id: string;
|
||||
key: string;
|
||||
accountId: string;
|
||||
creatorWalletAddress: string;
|
||||
secretHash: string;
|
||||
walletAddresses: string[];
|
||||
@@ -23,6 +24,12 @@ export type ApiKeyMetadata = {
|
||||
}[];
|
||||
};
|
||||
|
||||
export type AccountMetadata = {
|
||||
id: string;
|
||||
name: string;
|
||||
creatorWalletAddress: string;
|
||||
};
|
||||
|
||||
export type ApiResponse = {
|
||||
data: ApiKeyMetadata | null;
|
||||
error: {
|
||||
@@ -32,6 +39,15 @@ export type ApiResponse = {
|
||||
};
|
||||
};
|
||||
|
||||
export type ApiAccountResponse = {
|
||||
data: AccountMetadata | null;
|
||||
error: {
|
||||
code: string;
|
||||
statusCode: number;
|
||||
message: string;
|
||||
};
|
||||
};
|
||||
|
||||
export async function fetchKeyMetadataFromApi(
|
||||
clientId: string,
|
||||
config: CoreServiceConfig,
|
||||
@@ -52,3 +68,23 @@ export async function fetchKeyMetadataFromApi(
|
||||
}
|
||||
return (await response.json()) as ApiResponse;
|
||||
}
|
||||
|
||||
export async function fetchAccountFromApi(
|
||||
jwt: string,
|
||||
config: CoreServiceConfig,
|
||||
): Promise<ApiAccountResponse> {
|
||||
const { apiUrl, serviceApiKey } = config;
|
||||
const url = `${apiUrl}/v1/account/me`;
|
||||
const response = await fetch(url, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"x-service-api-key": serviceApiKey,
|
||||
"content-type": "application/json",
|
||||
authorization: `Bearer ${jwt}`,
|
||||
},
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`Error fetching account from API: ${response.statusText}`);
|
||||
}
|
||||
return (await response.json()) as ApiAccountResponse;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@ describe("authorizeClient", () => {
|
||||
origin: null,
|
||||
bundleId: null,
|
||||
secretKeyHash: null,
|
||||
hashedJWT: null,
|
||||
jwt: null,
|
||||
},
|
||||
validServiceConfig,
|
||||
)) as any;
|
||||
@@ -33,6 +35,8 @@ describe("authorizeClient", () => {
|
||||
origin: null,
|
||||
bundleId: null,
|
||||
secretKeyHash: null,
|
||||
hashedJWT: null,
|
||||
jwt: null,
|
||||
},
|
||||
{ ...validServiceConfig, enforceAuth: true },
|
||||
)) as any;
|
||||
|
||||
@@ -11,6 +11,7 @@ describe("authorizeClient", () => {
|
||||
domains: ["example.com", "*.example.com"],
|
||||
bundleIds: ["com.example.app"],
|
||||
services: [],
|
||||
accountId: "test-account-id",
|
||||
};
|
||||
|
||||
const validAuthOptions: ClientAuthorizationPayload = {
|
||||
@@ -40,6 +41,26 @@ describe("authorizeClient", () => {
|
||||
expect(result.apiKeyMeta).toEqual(validApiKeyMeta);
|
||||
});
|
||||
|
||||
it("should authorize client with any domain w/o origin check", () => {
|
||||
const authOptionsWithAnyDomain: ClientAuthorizationPayload = {
|
||||
secretKeyHash: null,
|
||||
bundleId: null,
|
||||
origin: null,
|
||||
};
|
||||
|
||||
const validApiKeyMetaAnyDomain = {
|
||||
...validApiKeyMeta,
|
||||
domains: ["*"],
|
||||
};
|
||||
|
||||
const result = authorizeClient(
|
||||
authOptionsWithAnyDomain,
|
||||
validApiKeyMetaAnyDomain,
|
||||
) as any;
|
||||
expect(result.authorized).toBe(true);
|
||||
expect(result.apiKeyMeta).toEqual(validApiKeyMetaAnyDomain);
|
||||
});
|
||||
|
||||
it("should not authorize client with non-matching bundle id", () => {
|
||||
const authOptionsWithBundleId: ClientAuthorizationPayload = {
|
||||
secretKeyHash: null,
|
||||
@@ -53,7 +74,7 @@ describe("authorizeClient", () => {
|
||||
) as any;
|
||||
expect(result.authorized).toBe(false);
|
||||
expect(result.errorMessage).toBe(
|
||||
"The bundleId: com.foo.bar, is not authorized for this key. Please update your key permissions on the thirdweb dashboard",
|
||||
"Invalid request: Unauthorized Bundle ID: com.foo.bar. You can view the restrictions on this API key at https://thirdweb.com/create-api-key",
|
||||
);
|
||||
expect(result.errorCode).toBe("BUNDLE_UNAUTHORIZED");
|
||||
expect(result.status).toBe(401);
|
||||
@@ -72,7 +93,7 @@ describe("authorizeClient", () => {
|
||||
) as any;
|
||||
expect(result.authorized).toBe(false);
|
||||
expect(result.errorMessage).toBe(
|
||||
"The secret is invalid. Please check you secret-key",
|
||||
"Incorrect key provided. You can view your active API keys at https://thirdweb.com/dashboard/settings",
|
||||
);
|
||||
expect(result.errorCode).toBe("SECRET_INVALID");
|
||||
expect(result.status).toBe(401);
|
||||
@@ -91,7 +112,7 @@ describe("authorizeClient", () => {
|
||||
) as any;
|
||||
expect(result.authorized).toBe(false);
|
||||
expect(result.errorMessage).toBe(
|
||||
"The domain: unauthorized.com, is not authorized for this key. Please update your key permissions on the thirdweb dashboard",
|
||||
"Invalid request: Unauthorized domain: unauthorized.com. You can view the restrictions on this API key at https://thirdweb.com/create-api-key",
|
||||
);
|
||||
expect(result.errorCode).toBe("ORIGIN_UNAUTHORIZED");
|
||||
expect(result.status).toBe(401);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user