Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 7 additions & 0 deletions packages/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,20 @@
"@mosaic/sdk": "workspace:*",
"@radix-ui/react-dropdown-menu": "^2.0.6",
"@radix-ui/react-slot": "^1.0.2",
"@solana/react": "^2.3.0",
"@solana/signers": "^2.3.0",
"@solana/wallet-adapter-base": "^0.9.27",
"@solana/wallet-adapter-react": "^0.15.39",
"@solana/wallet-adapter-react-ui": "^0.9.39",
"@solana/wallet-adapter-wallets": "^0.19.37",
"@tanstack/react-query": "^5.83.0",
"@wallet-standard/core": "^1.1.1",
"@wallet-standard/react": "^1.0.1",
"bs58": "^6.0.0",
"class-variance-authority": "^0.7.0",
"clsx": "^2.0.0",
"gill": "^0.10.2",
"gill-react": "^0.4.4",
"lucide-react": "^0.294.0",
"next": "15.4.5",
"next-themes": "^0.2.1",
Expand Down
10 changes: 5 additions & 5 deletions packages/ui/src/app/dashboard/create/arcade-token/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use client';

import { useState } from 'react';
import { useContext, useState } from 'react';
import { Button } from '@/components/ui/button';
import {
Card,
Expand All @@ -14,10 +14,10 @@ import Link from 'next/link';
import { ArcadeTokenOptions, ArcadeTokenCreationResult } from '@/types/token';
// import { createArcadeTokenForUI } from '@/lib/arcadeToken';
import { mockCreateArcadeTokenForUI } from '@/lib/mockFunctions';
import { useWallet } from '@solana/wallet-adapter-react';
import { SelectedWalletAccountContext } from '@/context/SelectedWalletAccountContext';

export default function ArcadeTokenCreatePage() {
const { publicKey, connected } = useWallet();
const [selectedWalletAccount] = useContext(SelectedWalletAccountContext);
const [arcadeTokenOptions, setArcadeTokenOptions] =
useState<ArcadeTokenOptions>({
name: '',
Expand All @@ -38,7 +38,7 @@ export default function ArcadeTokenCreatePage() {
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();

if (!connected || !publicKey) {
if (!selectedWalletAccount) {
alert('Please connect your wallet first');
return;
}
Expand All @@ -48,7 +48,7 @@ export default function ArcadeTokenCreatePage() {

try {
const result = await mockCreateArcadeTokenForUI(arcadeTokenOptions, {
publicKey,
publicKey: selectedWalletAccount.address,
connected: true,
});
setResult(result);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import { useState } from 'react';
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from '@/components/ui/card';
import { ChevronDown, ChevronUp } from 'lucide-react';
import { StablecoinOptions } from '@/types/token';

interface StablecoinAuthorityParamsProps {
options: StablecoinOptions;
onInputChange: (field: string, value: string) => void;
}

export function StablecoinAuthorityParams({
options,
onInputChange,
}: StablecoinAuthorityParamsProps) {
const [showOptionalParams, setShowOptionalParams] = useState(false);

return (
<Card>
<CardHeader>
<button
type="button"
onClick={() => setShowOptionalParams(!showOptionalParams)}
className="flex items-center gap-2 text-left"
>
<CardTitle>Authority Parameters (Optional)</CardTitle>
{showOptionalParams ? (
<ChevronUp className="h-4 w-4" />
) : (
<ChevronDown className="h-4 w-4" />
)}
</button>
<CardDescription>
Configure authorities for advanced token management
</CardDescription>
</CardHeader>
{showOptionalParams && (
<CardContent className="space-y-4">
<div>
<label className="block text-sm font-medium mb-2">
Mint Authority
</label>
<input
type="text"
className="w-full p-3 border rounded-lg"
placeholder="Public key or leave empty for connected wallet"
value={options.mintAuthority}
onChange={e => onInputChange('mintAuthority', e.target.value)}
/>
</div>
<div>
<label className="block text-sm font-medium mb-2">
Metadata Authority
</label>
<input
type="text"
className="w-full p-3 border rounded-lg"
placeholder="Public key or leave empty for connected wallet"
value={options.metadataAuthority}
onChange={e => onInputChange('metadataAuthority', e.target.value)}
/>
</div>
<div>
<label className="block text-sm font-medium mb-2">
Pausable Authority
</label>
<input
type="text"
className="w-full p-3 border rounded-lg"
placeholder="Public key or leave empty for connected wallet"
value={options.pausableAuthority}
onChange={e => onInputChange('pausableAuthority', e.target.value)}
/>
</div>
<div>
<label className="block text-sm font-medium mb-2">
Confidential Balances Authority
</label>
<input
type="text"
className="w-full p-3 border rounded-lg"
placeholder="Public key or leave empty for connected wallet"
value={options.confidentialBalancesAuthority}
onChange={e =>
onInputChange('confidentialBalancesAuthority', e.target.value)
}
/>
</div>
<div>
<label className="block text-sm font-medium mb-2">
Permanent Delegate Authority
</label>
<input
type="text"
className="w-full p-3 border rounded-lg"
placeholder="Public key or leave empty for connected wallet"
value={options.permanentDelegateAuthority}
onChange={e =>
onInputChange('permanentDelegateAuthority', e.target.value)
}
/>
</div>
</CardContent>
)}
</Card>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from '@/components/ui/card';
import { StablecoinOptions } from '@/types/token';

interface StablecoinBasicParamsProps {
options: StablecoinOptions;
onInputChange: (field: string, value: string) => void;
}

export function StablecoinBasicParams({
options,
onInputChange,
}: StablecoinBasicParamsProps) {
return (
<Card>
<CardHeader>
<CardTitle>Basic Parameters</CardTitle>
<CardDescription>
Configure the fundamental properties of your stablecoin
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="grid grid-cols-2 gap-4">
<div>
<label className="block text-sm font-medium mb-2">
Token Name *
</label>
<input
type="text"
className="w-full p-3 border rounded-lg"
placeholder="e.g., USD Coin"
value={options.name}
onChange={e => onInputChange('name', e.target.value)}
required
/>
</div>
<div>
<label className="block text-sm font-medium mb-2">Symbol *</label>
<input
type="text"
className="w-full p-3 border rounded-lg"
placeholder="e.g., USDC"
value={options.symbol}
onChange={e => onInputChange('symbol', e.target.value)}
required
/>
</div>
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<label className="block text-sm font-medium mb-2">Decimals *</label>
<input
type="number"
className="w-full p-3 border rounded-lg"
placeholder="6"
value={options.decimals}
onChange={e => onInputChange('decimals', e.target.value)}
min="0"
max="9"
required
/>
</div>
<div>
<label className="block text-sm font-medium mb-2">
Metadata URI
</label>
<input
type="url"
className="w-full p-3 border rounded-lg"
placeholder="https://example.com/metadata.json"
value={options.uri}
onChange={e => onInputChange('uri', e.target.value)}
/>
</div>
</div>
</CardContent>
</Card>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import { useState } from 'react';
import { Button } from '@/components/ui/button';
import { StablecoinOptions, StablecoinCreationResult } from '@/types/token';
import { StablecoinBasicParams } from './StablecoinBasicParams';
import { StablecoinAuthorityParams } from './StablecoinAuthorityParams';
import { StablecoinCreationResultDisplay } from '@/app/dashboard/create/stablecoin/StablecoinCreationResult';
import { createStablecoin } from '@/lib/stablecoin';
import { TransactionSendingSigner } from '@solana/signers';

interface StablecoinCreateFormProps {
transactionSendingSigner: TransactionSendingSigner<string>;
}

export function StablecoinCreateForm({
transactionSendingSigner,
}: StablecoinCreateFormProps) {
const [stablecoinOptions, setStablecoinOptions] = useState<StablecoinOptions>(
{
name: '',
symbol: '',
decimals: '6',
uri: '',
mintAuthority: '',
metadataAuthority: '',
pausableAuthority: '',
confidentialBalancesAuthority: '',
permanentDelegateAuthority: '',
}
);
const [isCreating, setIsCreating] = useState(false);
const [result, setResult] = useState<StablecoinCreationResult | null>(null);

const handleInputChange = (field: string, value: string) => {
setStablecoinOptions(prev => ({ ...prev, [field]: value }));
};

const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();

setIsCreating(true);
setResult(null);

try {
const result = await createStablecoin(
stablecoinOptions,
transactionSendingSigner
);
setResult({
success: true,
mintAddress: result.mintAddress,
transactionSignature: result.transactionSignature,
details: {
...stablecoinOptions,
decimals: parseInt(stablecoinOptions.decimals),
mintAuthority: stablecoinOptions.mintAuthority || '',
metadataAuthority: stablecoinOptions.metadataAuthority || '',
pausableAuthority: stablecoinOptions.pausableAuthority || '',
confidentialBalancesAuthority:
stablecoinOptions.confidentialBalancesAuthority || '',
permanentDelegateAuthority:
stablecoinOptions.permanentDelegateAuthority || '',
extensions: ['stablecoin'],
},
});
} catch (error) {
setResult({
success: false,
error:
error instanceof Error ? error.message : 'Unknown error occurred',
});
} finally {
setIsCreating(false);
}
};

const handleReset = () => {
setStablecoinOptions({
name: '',
symbol: '',
decimals: '6',
uri: '',
mintAuthority: '',
metadataAuthority: '',
pausableAuthority: '',
confidentialBalancesAuthority: '',
permanentDelegateAuthority: '',
});
setResult(null);
};

return (
<>
<form onSubmit={handleSubmit} className="space-y-6">
<StablecoinBasicParams
options={stablecoinOptions}
onInputChange={handleInputChange}
/>

<StablecoinAuthorityParams
options={stablecoinOptions}
onInputChange={handleInputChange}
/>

{result && <StablecoinCreationResultDisplay result={result} />}

<div className="flex gap-4">
<Button
type="submit"
className="flex-1"
disabled={
isCreating ||
!stablecoinOptions.name ||
!stablecoinOptions.symbol ||
!stablecoinOptions.decimals
}
>
{isCreating ? 'Creating Stablecoin...' : 'Create Stablecoin'}
</Button>
<Button type="button" variant="outline" onClick={handleReset}>
Reset
</Button>
</div>
</form>
</>
);
}
Loading