Compare commits

...
Author SHA1 Message Date
Jonas DanielsGitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
7ff46a50d2 Version Packages (#4694)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-09-19 22:08:29 +12:00
Joaquim VergesandGitHub 0c97d7965e Handle default chain when connecting via redirect URL (#4696) 2024-09-19 22:00:25 +12:00
jnsdls 4a87109289 Fix getClaimConditions for ERC20, ERC721, and ERC1155 (#4693)
FIXES: DASH-249
2024-09-19 06:35:12 +00:00
jnsdls dddf95daca v2 auth endpoints (#4689)
<!-- start pr-codex -->

## PR-Codex overview
The focus of this PR is to add a new API server secret variable and update authentication actions to use it securely.

### Detailed summary
- Added `API_SERVER_SECRET` variable in `.env.example`
- Updated authentication actions to use `API_SERVER_SECRET` securely
- Replaced `json.token` with `jwt` for better security

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2024-09-19 05:55:18 +00:00
jnsdls 06cd6a62d9 fix split deployments (#4690)
FIXES: DASH-253
2024-09-19 05:29:13 +00:00
18 changed files with 153 additions and 61 deletions
+4 -1
View File
@@ -93,4 +93,7 @@ UNTHREAD_GROWTH_TIER_ID=""
UNTHREAD_PRO_TIER_ID=""
# Demo Engine
NEXT_PUBLIC_DEMO_ENGINE_URL=""
NEXT_PUBLIC_DEMO_ENGINE_URL=""
# API server secret (required for thirdweb.com SIWE login)
API_SERVER_SECRET=""
+25 -11
View File
@@ -13,34 +13,46 @@ import type {
const THIRDWEB_API_HOST =
process.env.NEXT_PUBLIC_THIRDWEB_API_HOST || "https://api.thirdweb.com";
const THIRDWEB_API_SECRET = process.env.API_SERVER_SECRET || "";
export async function getLoginPayload(
params: GenerateLoginPayloadParams,
): Promise<LoginPayload> {
const res = await fetch(`${THIRDWEB_API_HOST}/v1/auth/payload`, {
if (!THIRDWEB_API_SECRET) {
throw new Error("API_SERVER_SECRET is not set");
}
const res = await fetch(`${THIRDWEB_API_HOST}/v2/siwe/payload`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-service-api-key": THIRDWEB_API_SECRET,
},
body: JSON.stringify({
address: params.address,
chainId: params.chainId?.toString(),
}),
headers: {
"Content-Type": "application/json",
},
});
if (!res.ok) {
console.error("Failed to fetch login payload", res.status, res.statusText);
throw new Error("Failed to fetch login payload");
}
return (await res.json()).payload;
return (await res.json()).data.payload;
}
export async function doLogin(payload: VerifyLoginPayloadParams) {
if (!THIRDWEB_API_SECRET) {
throw new Error("API_SERVER_SECRET is not set");
}
// forward the request to the API server
const res = await fetch(`${THIRDWEB_API_HOST}/v1/auth/login`, {
const res = await fetch(`${THIRDWEB_API_HOST}/v2/siwe/login`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-service-api-key": THIRDWEB_API_SECRET,
},
body: JSON.stringify({ payload }),
body: JSON.stringify(payload),
});
if (!res.ok) {
@@ -67,7 +79,9 @@ export async function doLogin(payload: VerifyLoginPayloadParams) {
const json = await res.json();
if (!json.token) {
const jwt = json.data.jwt;
if (!jwt) {
console.error("Failed to login - invalid json", json);
throw new Error("Failed to login - invalid json");
}
@@ -77,7 +91,7 @@ export async function doLogin(payload: VerifyLoginPayloadParams) {
method: "GET",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${json.token}`,
Authorization: `Bearer ${jwt}`,
},
});
// if we do not have a user, create one
@@ -85,7 +99,7 @@ export async function doLogin(payload: VerifyLoginPayloadParams) {
const newUserRes = await fetch(`${THIRDWEB_API_HOST}/v1/account/create`, {
method: "POST",
headers: {
Authorization: `Bearer ${json.token}`,
Authorization: `Bearer ${jwt}`,
},
});
@@ -104,7 +118,7 @@ export async function doLogin(payload: VerifyLoginPayloadParams) {
// set the token cookie
cookieStore.set(
COOKIE_PREFIX_TOKEN + getAddress(payload.payload.address),
json.token,
jwt,
{
httpOnly: true,
secure: true,
@@ -394,6 +394,16 @@ export const CustomContractForm: React.FC<CustomContractFormProps> = ({
});
}
// handle split things
const payees: string[] = [];
const shares: string[] = [];
if (isSplit && params.recipients?.length) {
for (const recipient of params.recipients) {
payees.push(recipient.address);
shares.push(recipient.sharesBps.toString());
}
}
if (metadata.name === "MarketplaceV3") {
// special case for marketplace
return await deployMarketplaceContract({
@@ -416,6 +426,8 @@ export const CustomContractForm: React.FC<CustomContractFormProps> = ({
const initializeParams = {
...params.contractMetadata,
...params.deployParams,
payees,
shares,
_contractURI,
};
@@ -3,7 +3,6 @@ import ThirdwebProvider from "@/components/thirdweb-provider";
import { metadataBase } from "@/lib/constants";
import type { Metadata } from "next";
import { APIHeader } from "../../../components/blocks/APIHeader";
import { SponsoredInAppTxPreview } from "../../../components/in-app-wallet/sponsored-tx";
import { StyledConnectEmbed } from "../../../components/styled-connect-embed";
export const metadata: Metadata = {
@@ -35,9 +34,10 @@ export default function Page() {
<div className="h-14" />
<section className="space-y-8">
{/* TODO: put this in its own section with inapp smart wallet enabled
<section className="space-y-8">
<SponsoredInAppTx />
</section>
</section> */}
</main>
</ThirdwebProvider>
);
@@ -85,44 +85,43 @@ function AnyAuth() {
);
}
function SponsoredInAppTx() {
return (
<>
<div className="space-y-2">
<h2 className="text-2xl sm:text-3xl font-semibold tracking-tight">
Signless Sponsored Transactions
</h2>
<p className="max-w-[600px]">
With in-app wallets, users don&apos;t need to confirm every
transaction.
<br />
Combine it with smart account flag to cover gas costs for the best UX.
</p>
</div>
<CodeExample
preview={<SponsoredInAppTxPreview />}
code={`import { inAppWallet } from "thirdweb/wallets";
import { claimTo } from "thirdweb/extensions/erc1155";
import { ConnectButton, TransactionButton } from "thirdweb/react";
// function SponsoredInAppTx() {
// return (
// <>
// <div className="space-y-2">
// <h2 className="text-2xl sm:text-3xl font-semibold tracking-tight">
// Signless Sponsored Transactions
// </h2>
// <p className="max-w-[600px]">
// With in-app wallets, users don&apos;t need to confirm every
// transaction.
// <br />
// Combine it with smart account flag to cover gas costs for the best UX.
// </p>
// </div>
// <CodeExample
// preview={<SponsoredInAppTxPreview />}
// code={`import { inAppWallet } from "thirdweb/wallets";
// import { claimTo } from "thirdweb/extensions/erc1155";
// import { ConnectButton, TransactionButton } from "thirdweb/react";
// const wallets = [
// inAppWallet(
// // turn on gas sponsorship for in-app wallets
// { smartAccount: { chain, sponsorGas: true }}
// )
// ];
const wallets = [
inAppWallet(
// turn on gas sponsorship for in-app wallets
{ smartAccount: { chain, sponsorGas: true }}
)
];
// function App(){
// return (<>
// <ConnectButton client={client} wallets={wallets} />
function App(){
return (<>
<ConnectButton client={client} wallets={wallets} />
{/* signless, sponsored transactions */}
<TransactionButton transaction={() => claimTo({ contract, to: "0x123...", tokenId: 0n, quantity: 1n })}>Mint</TransactionButton>
</>);
};`}
lang="tsx"
/>
</>
);
}
// {/* signless, sponsored transactions */}
// <TransactionButton transaction={() => claimTo({ contract, to: "0x123...", tokenId: 0n, quantity: 1n })}>Mint</TransactionButton>
// </>);
// };`}
// lang="tsx"
// />
// </>
// );
// }
@@ -2,6 +2,13 @@
import { THIRDWEB_CLIENT } from "@/lib/client";
import { useTheme } from "next-themes";
import {
arbitrumSepolia,
baseSepolia,
optimismSepolia,
polygonAmoy,
sepolia,
} from "thirdweb/chains";
import { ConnectButton } from "thirdweb/react";
import type { ConnectButtonProps } from "thirdweb/react";
import { WALLETS } from "../lib/constants";
@@ -13,6 +20,13 @@ export function StyledConnectButton(
return (
<ConnectButton
chains={[
sepolia,
baseSepolia,
optimismSepolia,
polygonAmoy,
arbitrumSepolia,
]}
wallets={WALLETS}
supportedNFTs={{
"84532": ["0x638263e3eAa3917a53630e61B1fBa685308024fa"],
@@ -2,6 +2,13 @@
import { THIRDWEB_CLIENT } from "@/lib/client";
import { useTheme } from "next-themes";
import {
arbitrumSepolia,
baseSepolia,
optimismSepolia,
polygonAmoy,
sepolia,
} from "thirdweb/chains";
import {
ConnectEmbed,
type ConnectEmbedProps,
@@ -22,6 +29,13 @@ export function StyledConnectEmbed(
</div>
) : (
<ConnectEmbed
chains={[
sepolia,
baseSepolia,
optimismSepolia,
polygonAmoy,
arbitrumSepolia,
]}
wallets={WALLETS}
client={THIRDWEB_CLIENT}
theme={theme === "light" ? "light" : "dark"}
+10
View File
@@ -14,6 +14,15 @@ const getDomain = () => {
return undefined;
};
// const getEcosystem = () => {
// if (process.env.NEXT_PUBLIC_IN_APP_WALLET_URL?.endsWith(".thirdweb.com")) {
// // prod ecosystem
// return "ecosystem.new-age";
// }
// // dev ecosystem
// return "ecosystem.bonfire-development";
// };
export const WALLETS = [
createWallet("inApp", {
auth: {
@@ -31,6 +40,7 @@ export const WALLETS = [
passkeyDomain: getDomain(),
},
}),
// ecosystemWallet(getEcosystem()), TODO put this in its own section
createWallet("io.metamask"),
createWallet("com.coinbase.wallet"),
createWallet("io.rabby"),
+8
View File
@@ -1,5 +1,13 @@
# thirdweb
## 5.57.3
### Patch Changes
- [#4696](https://github.com/thirdweb-dev/js/pull/4696) [`0c97d79`](https://github.com/thirdweb-dev/js/commit/0c97d7965e3f681cd1fe2e1c79ecc6897ad52b9c) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Fix default chain when using redirect mode + default to first passed chains if available
- [#4693](https://github.com/thirdweb-dev/js/pull/4693) [`4a87109`](https://github.com/thirdweb-dev/js/commit/4a87109289e6ece5f6f08c55160e5d4e11e034e4) Thanks [@jnsdls](https://github.com/jnsdls)! - fix `getClaimConditions` extension for erc20, erc721 and erc1155
## 5.57.2
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "thirdweb",
"version": "5.57.2",
"version": "5.57.3",
"repository": {
"type": "git",
"url": "git+https://github.com/thirdweb-dev/js.git#main"
@@ -27,7 +27,7 @@ export async function getClaimConditions(
const conditionPromises: Array<
ReturnType<typeof MultiById.getClaimConditionById>
> = [];
for (let i = startId; i < count; i++) {
for (let i = startId; i < startId + count; i++) {
conditionPromises.push(
MultiById.getClaimConditionById({
...options,
@@ -24,7 +24,7 @@ export async function getClaimConditions(
const conditionPromises: Array<
ReturnType<typeof MultiById.getClaimConditionById>
> = [];
for (let i = startId; i < count; i++) {
for (let i = startId; i < startId + count; i++) {
conditionPromises.push(
MultiById.getClaimConditionById({
...options,
@@ -24,7 +24,7 @@ export async function getClaimConditions(
const conditionPromises: Array<
ReturnType<typeof MultiById.getClaimConditionById>
> = [];
for (let i = startId; i < count; i++) {
for (let i = startId; i < startId + count; i++) {
conditionPromises.push(
MultiById.getClaimConditionById({
...options,
@@ -1,3 +1,4 @@
import type { Chain } from "../../../../chains/types.js";
import type { ThirdwebClient } from "../../../../client/client.js";
import type { Wallet } from "../../../../wallets/interfaces/wallet.js";
import type { SmartWalletOptions } from "../../../../wallets/smart/types.js";
@@ -107,4 +108,9 @@ export type AutoConnectProps = {
* ```
*/
onConnect?: (wallet: Wallet) => void;
/**
* Optional chain to autoconnect to
*/
chain?: Chain;
};
@@ -56,7 +56,10 @@ export function useAutoConnectCore(
return autoConnected;
}
const lastConnectedChain = await getLastConnectedChain(storage);
// this flow can actually be used for a first connection in the case of a redirect
// in that case, we default to the passed chain to connect to
const lastConnectedChain =
(await getLastConnectedChain(storage)) || props.chain;
async function handleWalletConnection(wallet: Wallet) {
return wallet.autoConnect({
@@ -293,8 +293,12 @@ export function ConnectButton(props: ConnectButtonProps) {
: props.connectModal?.size || "compact";
}, [wallets.length, props.connectModal?.size]);
const preferredChain =
props.accountAbstraction?.chain || props.chain || props.chains?.[0];
const autoConnectComp = props.autoConnect !== false && (
<AutoConnect
chain={preferredChain}
appMetadata={props.appMetadata}
client={props.client}
wallets={wallets}
@@ -336,7 +340,7 @@ export function ConnectButton(props: ConnectButtonProps) {
shouldSetActive={true}
accountAbstraction={props.accountAbstraction}
auth={props.auth}
chain={props.chain || props.accountAbstraction?.chain}
chain={preferredChain}
chains={props.chains}
client={props.client}
connectLocale={localeQuery.data}
@@ -1073,7 +1073,7 @@ function InAppWalletUserInfo(props: {
}
return walletInfo?.name;
},
enabled: !!activeWallet?.id,
enabled: !!activeWallet?.id && !!walletInfo,
});
const userInfoQuery = useQuery({
@@ -238,8 +238,12 @@ export function ConnectEmbed(props: ConnectEmbedProps) {
props.requireApproval,
]);
const preferredChain =
props.accountAbstraction?.chain || props.chain || props.chains?.[0];
const autoConnectComp = props.autoConnect !== false && (
<AutoConnect
chain={preferredChain}
appMetadata={props.appMetadata}
client={props.client}
wallets={wallets}
@@ -272,7 +276,7 @@ export function ConnectEmbed(props: ConnectEmbedProps) {
<ConnectEmbedContent
auth={props.auth}
accountAbstraction={props.accountAbstraction}
chain={props.chain || props.accountAbstraction?.chain}
chain={preferredChain}
chains={props.chains}
client={props.client}
connectLocale={localeQuery.data}
@@ -104,6 +104,7 @@ export function createInAppWallet(args: {
createOptions,
connector,
);
// set the states
client = options.client;
account = connectedAccount;