Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
6621237
reimplement signers, add crypto utils, add wallet-connectors and acco…
ertemann Oct 13, 2025
08b69e8
more cleanup of the moved code
ertemann Oct 13, 2025
3dbe993
Dev status - Working demo app for wallet direct mode, packages still …
ertemann Oct 15, 2025
2842c25
fix conditional envs
ertemann Oct 17, 2025
c0c6ed1
small demo cleanup
ertemann Oct 24, 2025
049cc21
externalise many defaults, re-implement indexer strategies, create RP…
ertemann Oct 26, 2025
fba7dfe
add auto-connect modal flow into abstraxion
ertemann Oct 26, 2025
2ceb06d
externalise walletmodal with proper hook, basically finish browser/re…
ertemann Oct 27, 2025
42e5c64
first full working version of turnkey flow
ertemann Oct 29, 2025
8575e18
finalize signer mode demo app, separate send demo util, integrate sub…
ertemann Oct 30, 2025
ae60e8f
add xion to package
ertemann Oct 30, 2025
62a4a9f
remove some logs, solve personal_sign issues with the raw method for …
ertemann Oct 30, 2025
c14b8a9
cleanup subquery and adding comments to demo
ertemann Oct 30, 2025
ec2635c
solve race conditions and cleanup state in abstraxion context
ertemann Oct 30, 2025
086511d
make logout promise async
ertemann Nov 6, 2025
e650693
migrate utility functions to core
ertemann Nov 6, 2025
709733a
Move to AA api V2, integrate AuthenticatorType Enum all throughout xi…
ertemann Nov 6, 2025
2f208a0
add test for salt and crypto utils as comparison to the AA api used. …
ertemann Nov 6, 2025
e358b2d
refactor: migrate to connector-based architecture with state machine
ertemann Nov 10, 2025
b7981df
linting
ertemann Nov 10, 2025
c8ccf69
remove direct mode, commit externalsigner implementation
ertemann Nov 10, 2025
9fd9231
remove link to direct mode
ertemann Nov 10, 2025
5a2ed4a
cleanup docs, types, unused etc.
ertemann Nov 10, 2025
a1be4d1
fully remove UI remainders
ertemann Nov 10, 2025
2c35c88
add changelogs
ertemann Nov 10, 2025
4f84855
format/lint
ertemann Nov 10, 2025
95a683f
add extra validation for eth signatures and hexmessages
ertemann Nov 10, 2025
a521968
add error mangement for failed session restore and more
ertemann Nov 14, 2025
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
9 changes: 9 additions & 0 deletions .changeset/clear-papers-greet.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@burnt-labs/account-management": minor
"@burnt-labs/abstraxion-core": minor
"@burnt-labs/abstraxion": minor
"@burnt-labs/constants": minor
"@burnt-labs/signers": minor
---

This release introduces **Signer Mode**, allowing users to connect with external wallets (MetaMask, Keplr, OKX, Turnkey, etc.) without requiring dashboard redirects. We've also refactored Abstraxion with a new connector-based architecture for better flexibility and extensibility. The release includes automatic configuration defaults (rpcUrl, restUrl, gasPrice are now inferred from chainId), migration to AA API V2, and two new packages: `@burnt-labs/account-management` and `@burnt-labs/signers`. Indexer support has been added for fast account discovery using Numia, Subquery, and DaoDao indexers. The Direct Signer Mode has been removed in favor of the new Signer Mode. Existing redirect mode users require no changes, while signer mode users need to add an `authentication` config with `type: "signer"`, `aaApiUrl`, `getSignerConfig()`, and `smartAccountContract` settings.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ yarn-error.log*
.env.development.local
.env.test.local
.env.production.local
# .env.test is now committed with non-sensitive defaults
# Use .env.test.local to override sensitive values locally (gitignored)
.env.test.local

# 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": {},
},
};
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
43 changes: 2 additions & 41 deletions apps/demo-app/src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,55 +1,16 @@
"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,
}: {
children: React.ReactNode;
}): JSX.Element {
return (
<html lang="en">
<body className={inter.className}>
<AbstraxionProvider config={treasuryConfig}>
{children}
</AbstraxionProvider>
</body>
<html lang="en" suppressHydrationWarning>
<body className={inter.className}>{children}</body>
</html>
);
}
29 changes: 29 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,29 @@
"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>
);
}
97 changes: 55 additions & 42 deletions apps/demo-app/src/app/loading-states/page.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
"use client";
import { useEffect } from "react";
import { useAbstraxionAccount } from "@burnt-labs/abstraxion";
import {
useAbstraxionAccount,
useAbstraxionSigningClient,
} from "@burnt-labs/abstraxion";
import { Button } from "@burnt-labs/ui";
import "@burnt-labs/ui/dist/index.css";
import Link from "next/link";
import { StateTooltip } from "../../components/StateTooltip";
import { SendTokens } from "@/components/SendTokens";

export default function UILessPage(): JSX.Element {
const {
Expand All @@ -18,6 +22,7 @@ export default function UILessPage(): JSX.Element {
isConnecting,
isReturningFromAuth,
} = useAbstraxionAccount();
const { client } = useAbstraxionSigningClient();

// Log state changes to show how your Dapp reacts
useEffect(() => {
Expand Down Expand Up @@ -47,28 +52,28 @@ export default function UILessPage(): JSX.Element {
};

return (
<main className="m-auto flex min-h-screen max-w-lg flex-col items-center justify-center gap-4 p-4">
<main className="m-auto flex min-h-screen max-w-lg flex-col items-center justify-center gap-6 p-6">
<div className="text-center">
<h1 className="mb-2 text-2xl font-bold tracking-tighter text-white">
<h1 className="mb-3 text-2xl font-bold tracking-tighter text-white">
Enhanced Loading States Demo
</h1>
<p className="max-w-md text-sm text-gray-400">
This demo showcases how to setup a connection flow for your dApp
throug Abstraxion.
through Abstraxion.
</p>
</div>

{/* Enhanced Debug Panel */}
<div className="w-full rounded border border-white/10 bg-gray-900/50 p-4 text-xs backdrop-blur-sm">
<div className="mb-3 flex items-center gap-2">
<div className="w-full rounded-lg border border-white/10 bg-gray-900/50 p-5 text-xs backdrop-blur-sm">
<div className="mb-4 flex items-center gap-2">
<div className="h-2 w-2 animate-pulse rounded-full bg-cyan-400"></div>
<p className="font-mono font-semibold text-cyan-400">
Authentication States
</p>
</div>

{/* There is a short period before the UI knows the actual connected state of the user. Consider it the mounting of the UI */}
<div className="grid grid-cols-2 gap-x-4 gap-y-2">
<div className="grid grid-cols-2 gap-x-6 gap-y-3">
<div className="flex items-center justify-between">
<div className="flex items-center gap-1">
<span className="font-mono text-gray-400">isInitializing:</span>
Expand Down Expand Up @@ -180,7 +185,7 @@ export default function UILessPage(): JSX.Element {
</div>
</div>

<div className="w-full space-y-4">
<div className="w-full space-y-5">
<Button
fullWidth
onClick={
Expand Down Expand Up @@ -235,8 +240,8 @@ export default function UILessPage(): JSX.Element {
</Button>

{/* State Flow Indicator */}
<div className="w-full rounded border border-gray-600/30 bg-gray-800/50 p-3">
<p className="mb-2 text-xs font-semibold text-gray-400">
<div className="w-full rounded-lg border border-gray-600/30 bg-gray-800/50 p-4">
<p className="mb-3 text-xs font-semibold text-gray-400">
Authentication Flow:
</p>
<div className="flex items-center justify-between text-xs">
Expand Down Expand Up @@ -329,6 +334,15 @@ export default function UILessPage(): JSX.Element {
</div>
</div>
</div>

{/* Account Info and Send Tokens - Only show when connected */}
{isConnected && account.bech32Address && (
<SendTokens
accountAddress={account.bech32Address}
client={client}
memo="Send XION via Abstraxion"
/>
)}
</div>

<Link
Expand All @@ -338,79 +352,78 @@ export default function UILessPage(): JSX.Element {
← Back to examples
</Link>

{/* Loading Overlays and UI Lock */}
{isLoading && <div className="fixed inset-0 z-40 bg-black/10" />}

{/* Loading Overlays - Show for initialization, login flows, and Auth callbacks */}
{(isInitializing ||
isConnecting ||
isReturningFromAuth ||
isLoggingIn) && (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-sm">
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/70 backdrop-blur-lg">
{/* Priority order: Auth callback > logging in > regular connecting > isInitializing */}
{isReturningFromAuth ? (
<div className="mx-4 max-w-sm rounded-lg border border-purple-500/30 bg-purple-500/10 p-6 text-center backdrop-blur-md">
<div className="mb-4">
<div className="mx-auto flex h-12 w-12 animate-pulse items-center justify-center rounded-full border-4 border-purple-500/30 bg-purple-500/20">
<div className="h-6 w-6 animate-spin rounded-full border-2 border-solid border-purple-400 border-r-transparent"></div>
<div className="mx-4 max-w-sm rounded-lg border border-purple-500/50 bg-black/80 p-8 text-center shadow-2xl backdrop-blur-xl">
<div className="mb-6">
<div className="mx-auto flex h-16 w-16 animate-pulse items-center justify-center rounded-full border-4 border-purple-500/40 bg-purple-500/20">
<div className="border-3 h-8 w-8 animate-spin rounded-full border-solid border-purple-400 border-r-transparent"></div>
</div>
</div>
<p className="font-bold text-purple-400">
<p className="text-lg font-bold text-purple-400">
Completing Authentication
</p>
<p className="mt-2 text-sm text-gray-400">
<p className="mt-3 text-sm text-gray-300">
Processing authentication from authorization server
</p>
</div>
) : isLoggingIn ? (
<div className="mx-4 max-w-sm rounded-lg border border-blue-500/30 bg-blue-500/10 p-6 text-center backdrop-blur-md">
<div className="mb-4">
<div className="mx-auto flex h-12 w-12 animate-pulse items-center justify-center rounded-full border-4 border-blue-500/30 bg-blue-500/20">
<div className="h-6 w-6 animate-spin rounded-full border-2 border-solid border-blue-400 border-r-transparent"></div>
<div className="mx-4 max-w-sm rounded-lg border border-blue-500/50 bg-black/80 p-8 text-center shadow-2xl backdrop-blur-xl">
<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="border-3 h-8 w-8 animate-spin rounded-full border-solid border-blue-400 border-r-transparent"></div>
</div>
</div>
<p className="font-bold text-blue-400">
<p className="text-lg font-bold text-blue-400">
Redirecting to Authorization
</p>
<p className="mt-2 text-sm text-gray-400">
<p className="mt-3 text-sm text-gray-300">
Opening XION dashboard for secure authentication
</p>
<div className="mt-4 flex items-center justify-center gap-2">
<div className="mt-5 flex items-center justify-center gap-2">
<div className="inline-block h-2 w-2 animate-bounce rounded-full bg-blue-400 [animation-delay:-0.3s]"></div>
<div className="inline-block h-2 w-2 animate-bounce rounded-full bg-blue-400 [animation-delay:-0.15s]"></div>
<div className="inline-block h-2 w-2 animate-bounce rounded-full bg-blue-400"></div>
</div>
<p className="mt-4 text-xs text-gray-500">
<p className="mt-5 text-xs text-gray-400">
You'll be redirected back here after authentication
</p>
</div>
) : isConnecting && !isReturningFromAuth ? (
<div className="mx-4 max-w-sm rounded-lg border border-blue-500/30 bg-blue-500/10 p-6 text-center backdrop-blur-md">
<div className="mb-4">
<div className="mx-auto flex h-12 w-12 animate-pulse items-center justify-center rounded-full border-4 border-blue-500/30 bg-blue-500/20">
<div className="h-6 w-6 animate-spin rounded-full border-2 border-solid border-blue-400 border-r-transparent"></div>
<div className="mx-4 max-w-sm rounded-lg border border-blue-500/50 bg-black/80 p-8 text-center shadow-2xl backdrop-blur-xl">
<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="border-3 h-8 w-8 animate-spin rounded-full border-solid border-blue-400 border-r-transparent"></div>
</div>
</div>
<p className="font-bold text-blue-400">Establishing Connection</p>
<p className="mt-2 text-sm text-gray-400">
<p className="text-lg font-bold text-blue-400">
Establishing Connection
</p>
<p className="mt-3 text-sm text-gray-300">
Connecting to your XION account and verifying permissions
</p>
</div>
) : isInitializing ? (
<div className="mx-4 max-w-sm rounded-lg border border-yellow-500/30 bg-yellow-500/10 p-6 text-center backdrop-blur-md">
<div className="mb-4">
<div className="mx-auto flex h-12 w-12 animate-pulse items-center justify-center rounded-full border-4 border-yellow-500/30 bg-yellow-500/20">
<div className="h-6 w-6 animate-spin rounded-full border-2 border-solid border-yellow-400 border-r-transparent"></div>
<div className="mx-4 max-w-sm rounded-lg border border-yellow-500/50 bg-black/80 p-8 text-center shadow-2xl backdrop-blur-xl">
<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="border-3 h-8 w-8 animate-spin rounded-full border-solid border-yellow-400 border-r-transparent"></div>
</div>
</div>
<p className="font-bold text-yellow-400">
<p className="text-lg font-bold text-yellow-400">
Initializing Application
</p>
<p className="mt-2 text-sm text-gray-400">
<p className="mt-3 text-sm text-gray-300">
Checking for existing authentication and restoring session
</p>
<div className="mt-4">
<div className="h-2 w-full rounded-full bg-gray-700">
<div className="mt-5">
<div className="h-2 w-full rounded-full bg-gray-700/50">
<div
className="h-2 animate-pulse rounded-full bg-yellow-400"
style={{ width: "60%" }}
Expand Down
16 changes: 14 additions & 2 deletions apps/demo-app/src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,23 @@ export default function Page(): JSX.Element {
</h1>
<div className="flex w-full flex-col gap-2">
<Link href="/loading-states">
<Button fullWidth structure="outlined">
Connect with Abstraxion
<Button fullWidth structure="base">
LOADING STATES
</Button>
</Link>
<Link href="/signer-mode">
<Button fullWidth structure="base">
SIGNER MODE
</Button>
</Link>
</div>
<p className="mt-4 text-center text-xs text-gray-500">
<strong>Direct Mode</strong> allows wallet connections without dashboard
redirect,
<br />
<strong>Loading States</strong> shows how the app reacts to state
changes in standard redirect mode.
</p>
</main>
);
}
Loading
Loading