@devvmichael/create-stacks-app 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/templates/frontends/nextjs/template/app/providers.tsx +5 -23
- package/templates/frontends/nextjs/template/components/wallet/connect-button.tsx +6 -16
- package/templates/frontends/nextjs/template/hooks/use-contract-call.ts +20 -19
- package/templates/frontends/nextjs/template/hooks/use-stacks.ts +34 -11
- package/templates/frontends/nextjs/template/lib/contracts.ts +8 -6
- package/templates/frontends/nextjs/template/lib/stacks.ts +50 -11
- package/templates/frontends/nextjs/template/package.json +11 -12
- package/templates/frontends/react/template/package.json +13 -13
- package/templates/frontends/vue/template/package.json +11 -11
package/package.json
CHANGED
|
@@ -1,31 +1,13 @@
|
|
|
1
|
-
|
|
1
|
+
"use client";
|
|
2
2
|
|
|
3
|
-
import { ReactNode } from
|
|
4
|
-
import { Connect } from '@stacks/connect-react';
|
|
5
|
-
import { userSession } from '@/lib/stacks';
|
|
3
|
+
import { ReactNode } from "react";
|
|
6
4
|
|
|
7
5
|
interface ProvidersProps {
|
|
8
6
|
children: ReactNode;
|
|
9
7
|
}
|
|
10
8
|
|
|
9
|
+
// With Stacks Connect v8, no provider wrapper is needed
|
|
10
|
+
// The connect() function handles wallet connection directly
|
|
11
11
|
export function Providers({ children }: ProvidersProps) {
|
|
12
|
-
|
|
13
|
-
name: 'Stacks App',
|
|
14
|
-
icon: typeof window !== 'undefined' ? window.location.origin + '/logo.svg' : '/logo.svg',
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
return (
|
|
18
|
-
<Connect
|
|
19
|
-
authOptions={{
|
|
20
|
-
appDetails,
|
|
21
|
-
redirectTo: '/',
|
|
22
|
-
onFinish: () => {
|
|
23
|
-
window.location.reload();
|
|
24
|
-
},
|
|
25
|
-
userSession,
|
|
26
|
-
}}
|
|
27
|
-
>
|
|
28
|
-
{children}
|
|
29
|
-
</Connect>
|
|
30
|
-
);
|
|
12
|
+
return <>{children}</>;
|
|
31
13
|
}
|
|
@@ -1,19 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
"use client";
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import { useStacks } from '@/hooks/use-stacks';
|
|
3
|
+
import { useStacks } from "@/hooks/use-stacks";
|
|
5
4
|
|
|
6
5
|
export function ConnectButton() {
|
|
7
|
-
const {
|
|
8
|
-
const { userSession, address, isLoading } = useStacks();
|
|
9
|
-
|
|
10
|
-
const handleConnect = () => {
|
|
11
|
-
authenticate();
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
const handleDisconnect = () => {
|
|
15
|
-
userSession.signUserOut('/');
|
|
16
|
-
};
|
|
6
|
+
const { address, isLoading, isConnected, connect, disconnect } = useStacks();
|
|
17
7
|
|
|
18
8
|
if (isLoading) {
|
|
19
9
|
return (
|
|
@@ -23,13 +13,13 @@ export function ConnectButton() {
|
|
|
23
13
|
);
|
|
24
14
|
}
|
|
25
15
|
|
|
26
|
-
if (address) {
|
|
16
|
+
if (isConnected && address) {
|
|
27
17
|
return (
|
|
28
18
|
<div className="flex items-center gap-3">
|
|
29
19
|
<span className="text-sm bg-gray-100 dark:bg-gray-800 px-3 py-1 rounded-full">
|
|
30
20
|
{address.slice(0, 6)}...{address.slice(-4)}
|
|
31
21
|
</span>
|
|
32
|
-
<button onClick={
|
|
22
|
+
<button onClick={disconnect} className="btn-secondary text-sm">
|
|
33
23
|
Disconnect
|
|
34
24
|
</button>
|
|
35
25
|
</div>
|
|
@@ -37,7 +27,7 @@ export function ConnectButton() {
|
|
|
37
27
|
}
|
|
38
28
|
|
|
39
29
|
return (
|
|
40
|
-
<button onClick={
|
|
30
|
+
<button onClick={connect} className="btn-primary">
|
|
41
31
|
Connect Wallet
|
|
42
32
|
</button>
|
|
43
33
|
);
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
|
|
1
|
+
"use client";
|
|
2
2
|
|
|
3
|
-
import { useState } from
|
|
4
|
-
import {
|
|
5
|
-
import { useStacks } from
|
|
6
|
-
import type { ContractConfig } from
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { request } from "@/lib/stacks";
|
|
5
|
+
import { useStacks } from "./use-stacks";
|
|
6
|
+
import type { ContractConfig } from "@/lib/contracts";
|
|
7
7
|
|
|
8
|
-
export function useContractCall(
|
|
8
|
+
export function useContractCall(
|
|
9
|
+
contract: ContractConfig,
|
|
10
|
+
functionName: string,
|
|
11
|
+
) {
|
|
9
12
|
const [isLoading, setIsLoading] = useState(false);
|
|
10
13
|
const [error, setError] = useState<Error | null>(null);
|
|
11
14
|
const [txId, setTxId] = useState<string | null>(null);
|
|
@@ -13,28 +16,26 @@ export function useContractCall(contract: ContractConfig, functionName: string)
|
|
|
13
16
|
|
|
14
17
|
const call = async (functionArgs: any[] = []) => {
|
|
15
18
|
if (!address) {
|
|
16
|
-
throw new Error(
|
|
19
|
+
throw new Error("Wallet not connected");
|
|
17
20
|
}
|
|
18
21
|
|
|
19
22
|
setIsLoading(true);
|
|
20
23
|
setError(null);
|
|
21
24
|
|
|
22
25
|
try {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
+
// Using Stacks Connect v8 request API
|
|
27
|
+
const result = await request("stx_callContract", {
|
|
28
|
+
contract: `${contract.address}.${contract.name}`,
|
|
26
29
|
functionName,
|
|
27
30
|
functionArgs,
|
|
28
|
-
network: contract.network,
|
|
29
|
-
postConditions: [],
|
|
30
|
-
onFinish: (data) => {
|
|
31
|
-
setTxId(data.txId);
|
|
32
|
-
console.log('Transaction submitted:', data.txId);
|
|
33
|
-
},
|
|
34
|
-
onCancel: () => {
|
|
35
|
-
setIsLoading(false);
|
|
36
|
-
},
|
|
37
31
|
});
|
|
32
|
+
|
|
33
|
+
if (result?.txId) {
|
|
34
|
+
setTxId(result.txId);
|
|
35
|
+
console.log("Transaction submitted:", result.txId);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return result;
|
|
38
39
|
} catch (err) {
|
|
39
40
|
setError(err as Error);
|
|
40
41
|
throw err;
|
|
@@ -1,26 +1,49 @@
|
|
|
1
|
-
|
|
1
|
+
"use client";
|
|
2
2
|
|
|
3
|
-
import { useEffect, useState } from
|
|
4
|
-
import {
|
|
3
|
+
import { useEffect, useState, useCallback } from "react";
|
|
4
|
+
import {
|
|
5
|
+
getConnectedAddress,
|
|
6
|
+
checkIsConnected,
|
|
7
|
+
connectWallet,
|
|
8
|
+
disconnectWallet,
|
|
9
|
+
} from "@/lib/stacks";
|
|
5
10
|
|
|
6
11
|
export function useStacks() {
|
|
7
12
|
const [address, setAddress] = useState<string | null>(null);
|
|
8
13
|
const [isLoading, setIsLoading] = useState(true);
|
|
9
14
|
|
|
15
|
+
// Check connection status on mount
|
|
10
16
|
useEffect(() => {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
+
const connectedAddress = getConnectedAddress();
|
|
18
|
+
setAddress(connectedAddress);
|
|
19
|
+
setIsLoading(false);
|
|
20
|
+
}, []);
|
|
21
|
+
|
|
22
|
+
// Connect handler
|
|
23
|
+
const connect = useCallback(async () => {
|
|
24
|
+
setIsLoading(true);
|
|
25
|
+
const connectedAddress = await connectWallet();
|
|
26
|
+
setAddress(connectedAddress);
|
|
17
27
|
setIsLoading(false);
|
|
28
|
+
|
|
29
|
+
// Reload to sync state
|
|
30
|
+
if (connectedAddress) {
|
|
31
|
+
window.location.reload();
|
|
32
|
+
}
|
|
33
|
+
}, []);
|
|
34
|
+
|
|
35
|
+
// Disconnect handler
|
|
36
|
+
const disconnect = useCallback(() => {
|
|
37
|
+
disconnectWallet();
|
|
38
|
+
setAddress(null);
|
|
39
|
+
window.location.reload();
|
|
18
40
|
}, []);
|
|
19
41
|
|
|
20
42
|
return {
|
|
21
|
-
userSession,
|
|
22
43
|
address,
|
|
23
44
|
isLoading,
|
|
24
|
-
isConnected: !!address,
|
|
45
|
+
isConnected: !!address && checkIsConnected(),
|
|
46
|
+
connect,
|
|
47
|
+
disconnect,
|
|
25
48
|
};
|
|
26
49
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { network } from
|
|
2
|
-
import type { StacksNetwork } from
|
|
1
|
+
import { network } from "./stacks";
|
|
2
|
+
import type { StacksNetwork } from "@stacks/network";
|
|
3
3
|
|
|
4
4
|
export interface ContractConfig {
|
|
5
5
|
address: string;
|
|
@@ -8,22 +8,24 @@ export interface ContractConfig {
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
// Contract address from environment or default devnet address
|
|
11
|
-
const contractAddress =
|
|
11
|
+
const contractAddress =
|
|
12
|
+
process.env.NEXT_PUBLIC_CONTRACT_ADDRESS ||
|
|
13
|
+
"ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM";
|
|
12
14
|
|
|
13
15
|
export const counterContract: ContractConfig = {
|
|
14
16
|
address: contractAddress,
|
|
15
|
-
name:
|
|
17
|
+
name: "counter",
|
|
16
18
|
network,
|
|
17
19
|
};
|
|
18
20
|
|
|
19
21
|
export const tokenContract: ContractConfig = {
|
|
20
22
|
address: contractAddress,
|
|
21
|
-
name:
|
|
23
|
+
name: "token",
|
|
22
24
|
network,
|
|
23
25
|
};
|
|
24
26
|
|
|
25
27
|
export const nftContract: ContractConfig = {
|
|
26
28
|
address: contractAddress,
|
|
27
|
-
name:
|
|
29
|
+
name: "nft",
|
|
28
30
|
network,
|
|
29
31
|
};
|
|
@@ -1,18 +1,57 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import {
|
|
2
|
+
connect,
|
|
3
|
+
disconnect,
|
|
4
|
+
isConnected,
|
|
5
|
+
getLocalStorage,
|
|
6
|
+
request,
|
|
7
|
+
} from "@stacks/connect";
|
|
8
|
+
import { STACKS_TESTNET, STACKS_MAINNET } from "@stacks/network";
|
|
6
9
|
|
|
10
|
+
// Network configuration
|
|
7
11
|
export const network =
|
|
8
|
-
process.env.NEXT_PUBLIC_NETWORK ===
|
|
9
|
-
?
|
|
10
|
-
:
|
|
12
|
+
process.env.NEXT_PUBLIC_NETWORK === "mainnet"
|
|
13
|
+
? STACKS_MAINNET
|
|
14
|
+
: STACKS_TESTNET;
|
|
15
|
+
|
|
16
|
+
// Get the connected user's address from local storage
|
|
17
|
+
export function getConnectedAddress(): string | null {
|
|
18
|
+
const storage = getLocalStorage();
|
|
19
|
+
if (!storage) return null;
|
|
20
|
+
|
|
21
|
+
const networkType =
|
|
22
|
+
process.env.NEXT_PUBLIC_NETWORK === "mainnet" ? "mainnet" : "testnet";
|
|
23
|
+
return storage.addresses?.[networkType] || null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Check if user is connected
|
|
27
|
+
export function checkIsConnected(): boolean {
|
|
28
|
+
return isConnected();
|
|
29
|
+
}
|
|
11
30
|
|
|
31
|
+
// Connect wallet
|
|
32
|
+
export async function connectWallet(): Promise<string | null> {
|
|
33
|
+
try {
|
|
34
|
+
const response = await connect();
|
|
35
|
+
return response.addresses?.[0]?.address || null;
|
|
36
|
+
} catch (error) {
|
|
37
|
+
console.error("Failed to connect wallet:", error);
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Disconnect wallet
|
|
43
|
+
export function disconnectWallet(): void {
|
|
44
|
+
disconnect();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Get explorer link
|
|
12
48
|
export function getExplorerLink(txId: string): string {
|
|
13
49
|
const baseUrl =
|
|
14
|
-
process.env.NEXT_PUBLIC_NETWORK ===
|
|
15
|
-
?
|
|
16
|
-
:
|
|
50
|
+
process.env.NEXT_PUBLIC_NETWORK === "mainnet"
|
|
51
|
+
? "https://explorer.stacks.co"
|
|
52
|
+
: "https://explorer.stacks.co/?chain=testnet";
|
|
17
53
|
return `${baseUrl}/txid/${txId}`;
|
|
18
54
|
}
|
|
55
|
+
|
|
56
|
+
// Export request for contract calls
|
|
57
|
+
export { request };
|
|
@@ -9,21 +9,20 @@
|
|
|
9
9
|
"lint": "next lint"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@stacks/connect": "^
|
|
13
|
-
"@stacks/
|
|
14
|
-
"@stacks/
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"react": "^18.
|
|
18
|
-
"react-dom": "^18.2.0"
|
|
12
|
+
"@stacks/connect": "^8.2.4",
|
|
13
|
+
"@stacks/network": "^7.3.1",
|
|
14
|
+
"@stacks/transactions": "^7.3.1",
|
|
15
|
+
"next": "^14.2.21",
|
|
16
|
+
"react": "^18.3.1",
|
|
17
|
+
"react-dom": "^18.3.1"
|
|
19
18
|
},
|
|
20
19
|
"devDependencies": {
|
|
21
|
-
"@types/node": "^
|
|
20
|
+
"@types/node": "^22",
|
|
22
21
|
"@types/react": "^18",
|
|
23
22
|
"@types/react-dom": "^18",
|
|
24
|
-
"autoprefixer": "^10.
|
|
25
|
-
"postcss": "^8",
|
|
26
|
-
"tailwindcss": "^3.
|
|
27
|
-
"typescript": "^5"
|
|
23
|
+
"autoprefixer": "^10.4.20",
|
|
24
|
+
"postcss": "^8.4.49",
|
|
25
|
+
"tailwindcss": "^3.4.17",
|
|
26
|
+
"typescript": "^5.7.2"
|
|
28
27
|
}
|
|
29
28
|
}
|
|
@@ -10,20 +10,20 @@
|
|
|
10
10
|
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@stacks/connect": "^
|
|
14
|
-
"@stacks/network": "^
|
|
15
|
-
"@stacks/transactions": "^
|
|
16
|
-
"react": "^18.
|
|
17
|
-
"react-dom": "^18.
|
|
13
|
+
"@stacks/connect": "^8.2.4",
|
|
14
|
+
"@stacks/network": "^7.3.1",
|
|
15
|
+
"@stacks/transactions": "^7.3.1",
|
|
16
|
+
"react": "^18.3.1",
|
|
17
|
+
"react-dom": "^18.3.1"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
|
-
"@types/react": "^18.
|
|
21
|
-
"@types/react-dom": "^18.
|
|
22
|
-
"@vitejs/plugin-react": "^4.
|
|
23
|
-
"autoprefixer": "^10.4.
|
|
24
|
-
"postcss": "^8.4.
|
|
25
|
-
"tailwindcss": "^3.
|
|
26
|
-
"typescript": "^5.
|
|
27
|
-
"vite": "^
|
|
20
|
+
"@types/react": "^18.3.18",
|
|
21
|
+
"@types/react-dom": "^18.3.5",
|
|
22
|
+
"@vitejs/plugin-react": "^4.3.4",
|
|
23
|
+
"autoprefixer": "^10.4.20",
|
|
24
|
+
"postcss": "^8.4.49",
|
|
25
|
+
"tailwindcss": "^3.4.17",
|
|
26
|
+
"typescript": "^5.7.2",
|
|
27
|
+
"vite": "^6.1.0"
|
|
28
28
|
}
|
|
29
29
|
}
|
|
@@ -10,18 +10,18 @@
|
|
|
10
10
|
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@stacks/connect": "^
|
|
14
|
-
"@stacks/network": "^
|
|
15
|
-
"@stacks/transactions": "^
|
|
16
|
-
"vue": "^3.
|
|
13
|
+
"@stacks/connect": "^8.2.4",
|
|
14
|
+
"@stacks/network": "^7.3.1",
|
|
15
|
+
"@stacks/transactions": "^7.3.1",
|
|
16
|
+
"vue": "^3.5.13"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
|
-
"@vitejs/plugin-vue": "^
|
|
20
|
-
"autoprefixer": "^10.4.
|
|
21
|
-
"postcss": "^8.4.
|
|
22
|
-
"tailwindcss": "^3.
|
|
23
|
-
"typescript": "^5.
|
|
24
|
-
"vite": "^
|
|
25
|
-
"vue-tsc": "^
|
|
19
|
+
"@vitejs/plugin-vue": "^5.2.1",
|
|
20
|
+
"autoprefixer": "^10.4.20",
|
|
21
|
+
"postcss": "^8.4.49",
|
|
22
|
+
"tailwindcss": "^3.4.17",
|
|
23
|
+
"typescript": "^5.7.2",
|
|
24
|
+
"vite": "^6.1.0",
|
|
25
|
+
"vue-tsc": "^2.2.0"
|
|
26
26
|
}
|
|
27
27
|
}
|