Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ yarn-error.log*
.env.development.local
.env.test.local
.env.production.local
.env.test

# turbo
.turbo
Expand Down
9 changes: 6 additions & 3 deletions apps/demo-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,24 +22,27 @@
"@cosmjs/crypto": "^0.36.0",
"@heroicons/react": "^2.1.4",
"@noble/hashes": "1.8.0",
"@turnkey/react-wallet-kit": "^1.4.1",
"@turnkey/viem": "^0.14.10",
"cosmjs-types": "^0.9.0",
"next": "^14.0.3",
"react": "^18.2.0",
"react-dom": "^18.2.0"
"react-dom": "^18.2.0",
"viem": "^2.38.5"
},
"devDependencies": {
"@burnt-labs/eslint-config-custom": "workspace:*",
"@burnt-labs/tailwind-config": "workspace:*",
"@burnt-labs/tsconfig": "workspace:*",
"@next/eslint-plugin-next": "^13.4.19",
"@opennextjs/cloudflare": "^1.0.4",
"@tailwindcss/postcss": "^4.0.0",
"@types/node": "^20",
"@types/react": "^18.2.47",
"@types/react-dom": "^18.2.18",
"autoprefixer": "^10.4.13",
"eslint-config-next": "14.0.4",
"postcss": "^8.4.20",
"tailwindcss": "^3.2.4",
"tailwindcss": "^4.0.0",
"typescript": "^5.2.2",
"wrangler": "^4.16.0"
}
Expand Down
4 changes: 2 additions & 2 deletions apps/demo-app/postcss.config.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// Tailwind CSS v4 - PostCSS plugin includes autoprefixer automatically
// If you want to use other PostCSS plugins, see the following:
// https://tailwindcss.com/docs/using-with-preprocessors

module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
"@tailwindcss/postcss": {},
},
};
87 changes: 87 additions & 0 deletions apps/demo-app/src/app/direct-mode/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
"use client";
import { useMemo } from "react";
import {
AbstraxionProvider,
type AbstraxionConfig,
type BrowserWalletAuthentication,
BUILT_IN_WALLETS,
} from "@burnt-labs/abstraxion";
import { WalletModal } from "../../components/WalletModal";

export default function DirectModeLayout({
children,
}: {
children: React.ReactNode;
}): JSX.Element {
// Browser wallet authentication configuration
const directModeConfig: AbstraxionConfig = useMemo(() => ({
// REQUIRED: Chain ID
chainId: "xion-testnet-2",

// REQUIRED: RPC URL for blockchain connection
rpcUrl: process.env.NEXT_PUBLIC_RPC_URL!,

// REQUIRED: REST API endpoint
restUrl: process.env.NEXT_PUBLIC_REST_URL!,

// REQUIRED: Gas price
gasPrice: process.env.NEXT_PUBLIC_GAS_PRICE || "0.001uxion",

// Treasury contract address (optional - for dynamic grant configs)
treasury: process.env.NEXT_PUBLIC_TREASURY_ADDRESS,

// Fee granter address (optional - pays transaction fees for grant creation)
feeGranter: process.env.NEXT_PUBLIC_FEE_GRANTER_ADDRESS,

// Indexer configuration for account lookup (optional but recommended)
// Only include if BOTH url and authToken are provided
...(process.env.NEXT_PUBLIC_INDEXER_URL && process.env.NEXT_PUBLIC_INDEXER_TOKEN && {
indexer: {
url: process.env.NEXT_PUBLIC_INDEXER_URL,
authToken: process.env.NEXT_PUBLIC_INDEXER_TOKEN,
},
}),

// Treasury indexer configuration for fetching grant configs (optional but recommended)
...(process.env.NEXT_PUBLIC_TREASURY_INDEXER_URL && {
treasuryIndexer: {
url: process.env.NEXT_PUBLIC_TREASURY_INDEXER_URL,
},
}),

// Local configuration for RPC fallback (required for direct chain queries)
...(process.env.NEXT_PUBLIC_CHECKSUM && process.env.NEXT_PUBLIC_FEE_GRANTER_ADDRESS && {
localConfig: {
codeId: Number(process.env.NEXT_PUBLIC_CODE_ID) || 1,
checksum: process.env.NEXT_PUBLIC_CHECKSUM,
feeGranter: process.env.NEXT_PUBLIC_FEE_GRANTER_ADDRESS,
addressPrefix: process.env.NEXT_PUBLIC_ADDRESS_PREFIX || "xion",
},
}),

authentication: {
type: "browser",
aaApiUrl: process.env.NEXT_PUBLIC_AA_API_URL,
autoConnect: false, // Show wallet selection UI

// Use built-in wallet definitions
wallets: [
BUILT_IN_WALLETS.metamask,
BUILT_IN_WALLETS.keplr,
BUILT_IN_WALLETS.okx,
],
},
}), []);

return (
<AbstraxionProvider config={directModeConfig}>
{children}
{/* Wallet modal - renders when login() is called */}
(
<WalletModal
authentication={directModeConfig.authentication as BrowserWalletAuthentication}
/>
)
</AbstraxionProvider>
);
}
124 changes: 124 additions & 0 deletions apps/demo-app/src/app/direct-mode/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
"use client";
import {
useAbstraxionAccount,
useAbstraxionSigningClient,
} from "@burnt-labs/abstraxion";
import { Button } from "@burnt-labs/ui";
import "@burnt-labs/ui/dist/index.css";
import "@burnt-labs/abstraxion/dist/index.css";
import Link from "next/link";
import { SendTokens } from "@/components/SendTokens";

export default function DirectModePage(): JSX.Element {
const {
data: account,
login,
isConnected,
isConnecting,
isInitializing,
isLoading
} = useAbstraxionAccount();
const { client, logout } = useAbstraxionSigningClient();

return (
<main className="m-auto flex min-h-screen max-w-lg flex-col items-center justify-center gap-4 p-4">
{/* Initialization Loading Overlay */}
{isInitializing && (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/70 backdrop-blur-lg">
<div className="mx-4 max-w-sm rounded-lg border border-yellow-500/50 bg-black/80 backdrop-blur-xl p-8 text-center shadow-2xl">
<div className="mb-6">
<div className="mx-auto flex h-16 w-16 animate-pulse items-center justify-center rounded-full border-4 border-yellow-500/40 bg-yellow-500/20">
<div className="h-8 w-8 animate-spin rounded-full border-3 border-solid border-yellow-400 border-r-transparent"></div>
</div>
</div>
<p className="text-lg font-bold text-yellow-400">Initializing</p>
<p className="mt-3 text-sm text-gray-300">
Checking for existing session...
</p>
</div>
</div>
)}

{/* Wallet Connection Loading Overlay */}
{isConnecting && !isInitializing && (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/70 backdrop-blur-lg">
<div className="mx-4 max-w-sm rounded-lg border border-blue-500/50 bg-black/80 backdrop-blur-xl p-8 text-center shadow-2xl">
<div className="mb-6">
<div className="mx-auto flex h-16 w-16 animate-pulse items-center justify-center rounded-full border-4 border-blue-500/40 bg-blue-500/20">
<div className="h-8 w-8 animate-spin rounded-full border-3 border-solid border-blue-400 border-r-transparent"></div>
</div>
</div>
<p className="text-lg font-bold text-blue-400">Connecting Wallet</p>
<p className="mt-3 text-sm text-gray-300">
Please approve the connection in your wallet
</p>
</div>
</div>
)}

<h1 className="text-2xl font-bold tracking-tighter text-white">
Direct Mode Abstraxion Example
</h1>
<p className="text-center text-gray-400">
This example uses the new <strong>direct mode</strong> which allows in-app wallet
connections without redirecting to the dashboard. Connect with MetaMask,
Keplr, Leap, or OKX directly in this app.
</p>

<div className="w-full space-y-4">
{!account.bech32Address && (
<Button
fullWidth
onClick={() => login()}
structure="base"
disabled={isLoading || isConnecting}
>
{isLoading || isConnecting ? (
<div className="flex items-center justify-center gap-2">
<div className="inline-block h-4 w-4 animate-spin rounded-full border-2 border-solid border-current border-r-transparent"></div>
<span>
{isConnecting ? "CONNECTING..." : "LOADING..."}
</span>
</div>
) : (
"CONNECT WALLET (DIRECT MODE)"
)}
</Button>
)}

{account.bech32Address && (
<>
<div className="rounded border border-green-500/20 bg-green-500/10 p-4">
<p className="text-sm text-green-400">
✓ Successfully connected using direct mode! No dashboard redirect needed.
</p>
</div>

<SendTokens
accountAddress={account.bech32Address}
client={client}
memo="Send XION via Abstraxion Direct Mode"
/>

<Button
fullWidth
onClick={() => {
if (logout) logout();
}}
structure="outlined"
>
DISCONNECT
</Button>
</>
)}
</div>

<Link
href="/"
className="mt-4 inline-block text-sm text-gray-400 underline hover:text-gray-300"
>
← Back to examples
</Link>
</main>
);
}
9 changes: 6 additions & 3 deletions apps/demo-app/src/app/globals.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@import "tailwindcss";

@theme {
/* Custom background image for glow-conic */
--background-image-glow-conic: conic-gradient(from 180deg at 50% 50%, #2a8af6 0deg, #a853ba 180deg, #e92a67 360deg);
}

body {
color: white;
Expand Down
39 changes: 1 addition & 38 deletions apps/demo-app/src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,43 +1,8 @@
"use client";
import "./globals.css";
import { Inter } from "next/font/google";
import { AbstraxionProvider } from "@burnt-labs/abstraxion";

const inter = Inter({ subsets: ["latin"] });

// Example XION seat contract
const seatContractAddress =
"xion1z70cvc08qv5764zeg3dykcyymj5z6nu4sqr7x8vl4zjef2gyp69s9mmdka";

const legacyConfig = {
contracts: [
// Usually, you would have a list of different contracts here
seatContractAddress,
{
address: seatContractAddress,
amounts: [{ denom: "uxion", amount: "1000000" }],
},
],
stake: true,
bank: [
{
denom: "uxion",
amount: "1000000",
},
],
// Optional params to activate mainnet config
// rpcUrl: "https://rpc.xion-mainnet-1.burnt.com:443",
// restUrl: "https://api.xion-mainnet-1.burnt.com:443",
};

const treasuryConfig = {
treasury: "xion13uwmwzdes7urtjyv7mye8ty6uk0vsgdrh2a2k94tp0yxx9vv3e9qazapyu", // Example XION treasury instance for instantiating smart contracts
gasPrice: "0.001uxion", // If you feel the need to change the gasPrice when connecting to signer, set this value. Please stick to the string format seen in example
// Optional params to activate mainnet config
// rpcUrl: "https://rpc.xion-mainnet-1.burnt.com:443",
// restUrl: "https://api.xion-mainnet-1.burnt.com:443",
};

export default function RootLayout({
children,
}: {
Expand All @@ -46,9 +11,7 @@ export default function RootLayout({
return (
<html lang="en">
<body className={inter.className}>
<AbstraxionProvider config={treasuryConfig}>
{children}
</AbstraxionProvider>
{children}
</body>
</html>
);
Expand Down
26 changes: 26 additions & 0 deletions apps/demo-app/src/app/loading-states/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
"use client";
import { AbstraxionProvider } from "@burnt-labs/abstraxion";

// Redirect mode configuration (OAuth dashboard flow)
const redirectModeConfig = {
chainId: "xion-testnet-2",
treasury: process.env.NEXT_PUBLIC_TREASURY_ADDRESS,
rpcUrl: process.env.NEXT_PUBLIC_RPC_URL || "https://rpc.xion-testnet-2.burnt.com:443",
restUrl: process.env.NEXT_PUBLIC_REST_URL || "https://api.xion-testnet-2.burnt.com",
gasPrice: process.env.NEXT_PUBLIC_GAS_PRICE || "0.001uxion",

// Authentication defaults to redirect mode if not specified
// This demonstrates the traditional OAuth flow through the dashboard
};

export default function LoadingStatesLayout({
children,
}: {
children: React.ReactNode;
}): JSX.Element {
return (
<AbstraxionProvider config={redirectModeConfig}>
{children}
</AbstraxionProvider>
);
}
Loading
Loading