From f79b9c0d488d99c46ebf60569bfe05ee23d8e758 Mon Sep 17 00:00:00 2001 From: Joaquim Verges Date: Mon, 28 Jul 2025 15:03:19 +1200 Subject: [PATCH] [Dashboard] Add thirdweb API option alongside Engine API --- .../analytics/send-test-tx.client.tsx | 2 +- .../explorer/components/scalar.tsx | 30 +- .../(sidebar)/transactions/explorer/page.tsx | 42 ++- .../(sidebar)/transactions/layout.tsx | 6 +- .../server-wallets/components/try-it-out.tsx | 329 ++++++++++++++---- 5 files changed, 326 insertions(+), 83 deletions(-) diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/analytics/send-test-tx.client.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/analytics/send-test-tx.client.tsx index 7fb5d6f62dd..a83f3c62869 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/analytics/send-test-tx.client.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/analytics/send-test-tx.client.tsx @@ -292,7 +292,7 @@ export function SendTestTransaction(props: { return (
- +
diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/explorer/components/scalar.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/explorer/components/scalar.tsx index 3575646e063..6a7a1925be5 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/explorer/components/scalar.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/explorer/components/scalar.tsx @@ -1,22 +1,40 @@ "use client"; import { ApiReferenceReact } from "@scalar/api-reference-react"; import "@scalar/api-reference-react/style.css"; -import { NEXT_PUBLIC_ENGINE_CLOUD_URL } from "@/constants/public-envs"; +import { + NEXT_PUBLIC_ENGINE_CLOUD_URL, + NEXT_PUBLIC_THIRDWEB_API_HOST, +} from "@/constants/public-envs"; + +interface ScalarProps { + useEngineAPI: boolean; +} + +export function Scalar({ useEngineAPI }: ScalarProps) { + const apiUrl = useEngineAPI + ? NEXT_PUBLIC_ENGINE_CLOUD_URL + : NEXT_PUBLIC_THIRDWEB_API_HOST; + const openApiUrl = useEngineAPI + ? `${apiUrl}/openapi` + : `${apiUrl}/openapi.json`; + const apiName = useEngineAPI ? "Engine API (advanced)" : "thirdweb API"; + const serverDescription = useEngineAPI ? "Engine Cloud" : "thirdweb API"; -export function Scalar() { return (
-

Full API Reference

+

+ Full API Reference - {apiName} +

diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/explorer/page.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/explorer/page.tsx index c9fcb32347b..709246fb149 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/explorer/page.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/explorer/page.tsx @@ -1,11 +1,47 @@ +"use client"; +import { useState } from "react"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; import { TryItOut } from "../server-wallets/components/try-it-out"; import { Scalar } from "./components/scalar"; -export default async function TransactionsExplorerPage() { +export default function TransactionsExplorerPage() { + const [apiMode, setApiMode] = useState<"thirdweb" | "engine">("thirdweb"); + const useEngineAPI = apiMode === "engine"; + return (
- - +
+
+

Select API Mode

+

+ Choose between thirdweb API (recommended) or Engine API (advanced) +

+
+
+ +
+
+ +
); } diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/layout.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/layout.tsx index 1f0d5294b76..a3838dfbc39 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/layout.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/layout.tsx @@ -2,7 +2,7 @@ import Link from "next/link"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { TabPathLinks } from "@/components/ui/tabs"; -import { NEXT_PUBLIC_ENGINE_CLOUD_URL } from "@/constants/public-envs"; +import { NEXT_PUBLIC_THIRDWEB_API_HOST } from "@/constants/public-envs"; export default async function Page(props: { params: Promise<{ team_slug: string; project_slug: string }>; @@ -45,11 +45,11 @@ function TransactionsLayout(props: {
- {NEXT_PUBLIC_ENGINE_CLOUD_URL} + {NEXT_PUBLIC_THIRDWEB_API_HOST}
diff --git a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/server-wallets/components/try-it-out.tsx b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/server-wallets/components/try-it-out.tsx index 984d61da7c0..af7fbecfe21 100644 --- a/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/server-wallets/components/try-it-out.tsx +++ b/apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/transactions/server-wallets/components/try-it-out.tsx @@ -3,23 +3,34 @@ import Link from "next/link"; import { useState } from "react"; import { CodeClient } from "@/components/ui/code/code.client"; import { TabButtons } from "@/components/ui/tabs"; -import { NEXT_PUBLIC_ENGINE_CLOUD_URL } from "@/constants/public-envs"; +import { + NEXT_PUBLIC_ENGINE_CLOUD_URL, + NEXT_PUBLIC_THIRDWEB_API_HOST, +} from "@/constants/public-envs"; -export function TryItOut() { +interface TryItOutProps { + useEngineAPI: boolean; +} + +export function TryItOut({ useEngineAPI }: TryItOutProps) { const [activeTab, setActiveTab] = useState("curl"); + const apiTitle = useEngineAPI + ? "Engine API (advanced)" + : "thirdweb API (recommended)"; + const apiDescription = useEngineAPI + ? "Send transactions from your server wallets using the thirdweb SDK or the Engine HTTP API directly.." + : "Send transactions from your server wallets using the thirdweb SDK or the thirdweb HTTP API directly."; + return ( <>

- Usage from your backend + Usage from your backend - {apiTitle}

-

- Send transactions from your server wallets using the thirdweb SDK - or the HTTP API directly. -

+

{apiDescription}

@@ -90,28 +101,30 @@ export function TryItOut() { {activeTab === "curl" && ( )} {activeTab === "js" && (
-

- A lightweight, type safe wrapper package of the Engine HTTP API is - available on{" "} - - NPM - - . -

+ {useEngineAPI && ( +

+ A lightweight, type safe wrapper package of the Engine HTTP API + is available on{" "} + + NPM + + . +

+ )}
@@ -119,17 +132,25 @@ export function TryItOut() { {activeTab === "python" && ( )} {activeTab === "go" && ( - + )} {activeTab === "csharp" && ( )} @@ -138,54 +159,175 @@ export function TryItOut() { ); } -const sdkExample = () => `\ -import { createThirdwebClient, sendTransaction, getContract, Engine } from "thirdweb"; -import { baseSepolia } from "thirdweb/chains"; -import { claimTo } from "thirdweb/extensions/erc1155"; +// thirdweb API examples +const thirdwebCurlExample = () => `\ +curl -X POST "${NEXT_PUBLIC_THIRDWEB_API_HOST}/v1/transactions" \\ + -H "Content-Type: application/json" \\ + -H "x-secret-key: " \\ + -d '{ + "chainId": "84532", + "from": "", + "transactions": [ + { + "type": "contractCall", + "contractAddress": "0x...", + "method": "function mintTo(address to, uint256 amount)", + "params": ["0x...", "100"] + } + ] + }'`; -// Create a thirdweb client -const client = createThirdwebClient({ - secretKey: "", -}); +const thirdwebJsExample = () => `\ +const response = await fetch( + "${NEXT_PUBLIC_THIRDWEB_API_HOST}/v1/transactions", + { + method: "POST", + headers: { + "Content-Type": "application/json", + "x-secret-key": "", + }, + body: JSON.stringify({ + "chainId": "84532", + "from": "", + "transactions": [ + { + "type": "contractCall", + "contractAddress": "0x...", + "method": "function mintTo(address to, uint256 amount)", + "params": ["0x...", "100"] + } + ] + }) + } +);`; -// Create a server wallet -const serverWallet = Engine.serverWallet({ - client, - address: "", -}); +const thirdwebPythonExample = () => `\ +import requests +import json -// Prepare the transaction -const transaction = claimTo({ - contract: getContract({ - client, - address: "0x...", // Address of the ERC1155 token contract - chain: baseSepolia, // Chain of the ERC1155 token contract - }), - to: "0x...", // The address of the user to mint to - tokenId: 0n, // The token ID of the NFT to mint - quantity: 1n, // The quantity of NFTs to mint -}); +url = "${NEXT_PUBLIC_THIRDWEB_API_HOST}/v1/transactions" +headers = { + "Content-Type": "application/json", + "x-secret-key": "", +} +payload = { + "chainId": "84532", + "from": "", + "transactions": [ + { + "type": "contractCall", + "contractAddress": "0x...", + "method": "function mintTo(address to, uint256 amount)", + "params": ["0x...", "100"] + } + ] +} -// Enqueue the transaction via Engine -const { transactionId } = await serverWallet.enqueueTransaction({ - transaction, -}); +response = requests.post(url, headers=headers, json=payload) +result = response.json()`; -// Get the execution status of the transaction at any point in time -const executionResult = await Engine.getTransactionStatus({ - client, - transactionId, -}); +const thirdwebGoExample = () => `\ +package main -// Utility function to poll for the transaction to be submitted onchain -const txHash = await Engine.waitForTransactionHash({ - client, - transactionId, -}); -console.log("Transaction hash:", txHash); -`; +import ( + "bytes" + "encoding/json" + "fmt" + "net/http" +) + +func main() { + url := "${NEXT_PUBLIC_THIRDWEB_API_HOST}/v1/transactions" + + type Transaction struct { + Type string \`json:"type"\` + ContractAddress string \`json:"contractAddress"\` + Method string \`json:"method"\` + Params []string \`json:"params"\` + } + + type RequestBody struct { + ChainId string \`json:"chainId"\` + From string \`json:"from"\` + Transactions []Transaction \`json:"transactions"\` + } + + requestBody := RequestBody{ + ChainId: "84532", + From: "", + Transactions: []Transaction{ + { + Type: "contractCall", + ContractAddress: "0x...", + Method: "function mintTo(address to, uint256 amount)", + Params: []string{"0x...", "100"}, + }, + }, + } + + jsonData, _ := json.Marshal(requestBody) + + req, _ := http.NewRequest("POST", url, bytes.NewBuffer(jsonData)) + req.Header.Set("Content-Type", "application/json") + req.Header.Set("x-secret-key", "") + + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + fmt.Println("Error:", err) + return + } + defer resp.Body.Close() + + var result map[string]interface{} + json.NewDecoder(resp.Body).Decode(&result) + fmt.Println("Response:", result) +}`; + +const thirdwebCsharpExample = () => `\ +using System; +using System.Net.Http; +using System.Text; +using System.Text.Json; +using System.Threading.Tasks; + +class Program +{ + static async Task Main() + { + var url = "${NEXT_PUBLIC_THIRDWEB_API_HOST}/v1/transactions"; + + var requestData = new + { + chainId = "84532", + from = "", + transactions = new[] + { + new + { + type = "contractCall", + contractAddress = "0x...", + method = "function mintTo(address to, uint256 amount)", + @params = new[] { "0x...", "100" } + } + } + }; + + var json = JsonSerializer.Serialize(requestData); + var content = new StringContent(json, Encoding.UTF8, "application/json"); + + using var httpClient = new HttpClient(); + httpClient.DefaultRequestHeaders.Add("x-secret-key", ""); + + var response = await httpClient.PostAsync(url, content); + var responseContent = await response.Content.ReadAsStringAsync(); + + Console.WriteLine(responseContent); + } +}`; -const curlExample = () => `\ +// Engine API examples (original examples) +const engineCurlExample = () => `\ curl -X POST "${NEXT_PUBLIC_ENGINE_CLOUD_URL}/v1/write/contract" \\ -H "Content-Type: application/json" \\ -H "x-secret-key: " \\ @@ -203,7 +345,7 @@ curl -X POST "${NEXT_PUBLIC_ENGINE_CLOUD_URL}/v1/write/contract" \\ ] }'`; -const jsExample = () => `\ +const engineJsExample = () => `\ const response = await fetch( "${NEXT_PUBLIC_ENGINE_CLOUD_URL}/v1/write/contract", { @@ -228,7 +370,7 @@ const response = await fetch( } );`; -const pythonExample = () => `\ +const enginePythonExample = () => `\ import requests import json @@ -254,7 +396,7 @@ payload = { response = requests.post(url, headers=headers, json=payload) result = response.json()`; -const goExample = () => `\ +const engineGoExample = () => `\ package main import ( @@ -316,7 +458,7 @@ func main() { fmt.Println("Response:", result) }`; -const csharpExample = () => `\ +const engineCsharpExample = () => `\ using System; using System.Net.Http; using System.Text; @@ -359,3 +501,50 @@ class Program Console.WriteLine(responseContent); } }`; + +const sdkExample = () => `\ +import { createThirdwebClient, sendTransaction, getContract, Engine } from "thirdweb"; +import { baseSepolia } from "thirdweb/chains"; +import { claimTo } from "thirdweb/extensions/erc1155"; + +// Create a thirdweb client +const client = createThirdwebClient({ + secretKey: "", +}); + +// Create a server wallet +const serverWallet = Engine.serverWallet({ + client, + address: "", +}); + +// Prepare the transaction +const transaction = claimTo({ + contract: getContract({ + client, + address: "0x...", // Address of the ERC1155 token contract + chain: baseSepolia, // Chain of the ERC1155 token contract + }), + to: "0x...", // The address of the user to mint to + tokenId: 0n, // The token ID of the NFT to mint + quantity: 1n, // The quantity of NFTs to mint +}); + +// Enqueue the transaction via Engine +const { transactionId } = await serverWallet.enqueueTransaction({ + transaction, +}); + +// Get the execution status of the transaction at any point in time +const executionResult = await Engine.getTransactionStatus({ + client, + transactionId, +}); + +// Utility function to poll for the transaction to be submitted onchain +const txHash = await Engine.waitForTransactionHash({ + client, + transactionId, +}); +console.log("Transaction hash:", txHash); +`;