(null);
+
+ useEffect(() => {
+ const checkConnection = async () => {
+ try {
+ const address = await getPublicKey();
+ if (address) {
+ setWalletAddress(address);
+ toast.success("Wallet Reconnected", {
+ description: `Welcome back! Address: ${address}`,
+ });
+ }
+ } catch (error) {
+ console.log("No wallet connected.", error);
+ } finally {
+ setIsChecking(false);
+ }
+ };
+
+ checkConnection();
+ }, []);
+
+ const connectWallet = async () => {
+ try {
+ setIsConnecting(true);
+ await connect(async () => {
+ const address = await getPublicKey();
+ if (!address) throw new Error("Failed to retrieve wallet address");
+
+ setWalletAddress(address);
+ toast.success("Wallet Connected", {
+ description: `Connected. Address: ${address}`,
+ });
+ });
+ } catch (error) {
+ console.log(error);
+ toast.error("Connection Failed", {
+ description: "Failed to connect to the wallet.",
+ });
+ } finally {
+ setIsConnecting(false);
+ }
+ };
+
+ const disconnectWallet = async () => {
+ await disconnect();
+ setWalletAddress(null);
+ toast.info("Wallet Disconnected", {
+ description: "You have been disconnected.",
+ });
+ };
+
+ return (
+
+
+
+ {walletAddress && (
+
+ )}
+
+ );
+};
+
+export default ConnectWalletButton;
diff --git a/components/dashboard/index.tsx b/components/dashboard/index.tsx
index 10a671c4..48af2a0d 100644
--- a/components/dashboard/index.tsx
+++ b/components/dashboard/index.tsx
@@ -2,7 +2,6 @@
import { useState } from "react";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
-import { Button } from "@/components/ui/button";
import { Wallet, TrendingUp, Compass, CheckCircle } from "lucide-react";
import { AnimatePresence } from "framer-motion";
@@ -20,6 +19,7 @@ import MyProjectsTab from "./tabs/my-projects-tab";
import TrendingTab from "./tabs/trending-tab";
import ExploreTab from "./tabs/explore-tab";
import CompletedTab from "./tabs/completed-tab";
+import ConnectWalletButton from "../connect-wallet";
export default function Dashboard() {
const [exploreFilter, setExploreFilter] = useState("newest");
@@ -81,10 +81,12 @@ export default function Dashboard() {
Dashboard
- */}
diff --git a/components/ui/sonner.tsx b/components/ui/sonner.tsx
new file mode 100644
index 00000000..c5ba1bfe
--- /dev/null
+++ b/components/ui/sonner.tsx
@@ -0,0 +1,31 @@
+"use client";
+
+import { useTheme } from "next-themes";
+import { Toaster as Sonner } from "sonner";
+
+type ToasterProps = React.ComponentProps;
+
+const Toaster = ({ ...props }: ToasterProps) => {
+ const { theme = "system" } = useTheme();
+
+ return (
+
+ );
+};
+
+export { Toaster };
diff --git a/hooks/useStellarWallet.tsx b/hooks/useStellarWallet.tsx
new file mode 100644
index 00000000..f4e2242b
--- /dev/null
+++ b/hooks/useStellarWallet.tsx
@@ -0,0 +1,55 @@
+import {
+ allowAllModules,
+ FREIGHTER_ID,
+ StellarWalletsKit,
+ WalletNetwork,
+} from "@creit.tech/stellar-wallets-kit";
+
+const SELECTED_WALLET_ID = "selectedWalletId";
+
+function getSelectedWalletId() {
+ if (typeof window === "undefined") return null;
+ return localStorage.getItem(SELECTED_WALLET_ID);
+}
+
+const kit = new StellarWalletsKit({
+ modules: allowAllModules(),
+ network: WalletNetwork.TESTNET,
+ selectedWalletId: getSelectedWalletId() ?? FREIGHTER_ID,
+});
+
+export const signTransaction = kit.signTransaction.bind(kit);
+
+export async function getPublicKey() {
+ if (!getSelectedWalletId()) return null;
+ const { address } = await kit.getAddress();
+ return address;
+}
+
+export async function setWallet(walletId: string) {
+ if (typeof window === "undefined") return;
+ localStorage.setItem(SELECTED_WALLET_ID, walletId);
+ kit.setWallet(walletId);
+}
+
+export async function disconnect(callback?: () => Promise) {
+ if (typeof window !== "undefined") {
+ localStorage.removeItem(SELECTED_WALLET_ID);
+ }
+ kit.disconnect();
+ if (callback) await callback();
+}
+
+export async function connect(callback?: () => Promise) {
+ await kit.openModal({
+ onWalletSelected: async (option) => {
+ try {
+ await setWallet(option.id);
+ if (callback) await callback();
+ } catch (e) {
+ console.error(e);
+ }
+ return option.id;
+ },
+ });
+}
diff --git a/initialize.js b/initialize.js
new file mode 100644
index 00000000..a3b9f265
--- /dev/null
+++ b/initialize.js
@@ -0,0 +1,134 @@
+import "dotenv/config";
+import { mkdirSync, writeFileSync, rmSync, readFileSync } from "node:fs";
+import { execSync } from "node:child_process";
+import path from "node:path";
+import { fileURLToPath } from "node:url";
+import { sync as glob } from "glob";
+
+// Load environment variables starting with PUBLIC_ into the environment,
+// so we don't need to specify duplicate variables in .env
+for (const key in process.env) {
+ if (key.startsWith("PUBLIC_")) {
+ process.env[key.substring(7)] = process.env[key];
+ }
+}
+
+console.log("###################### Initializing ########################");
+
+// Get dirname (equivalent to the Bash version)
+const __filename = fileURLToPath(import.meta.url);
+const dirname = path.dirname(__filename);
+const contractsDir = `${dirname}/.stellar/contract-ids`;
+
+// variable for later setting pinned version of soroban in "$(dirname/target/bin/soroban)"
+const cli = "stellar";
+
+// Function to execute and log shell commands
+function exe(command) {
+ console.log(command);
+ execSync(command, { stdio: "inherit" });
+}
+
+function fundAll() {
+ exe(`${cli} keys generate --fund ${process.env.STELLAR_ACCOUNT} | true`);
+}
+
+function removeFiles(pattern) {
+ console.log(`remove ${pattern}`);
+ for (const entry of glob(pattern)) {
+ rmSync(entry);
+ }
+}
+
+function buildAll() {
+ removeFiles(`${dirname}/target/wasm32-unknown-unknown/release/*.wasm`);
+ removeFiles(`${dirname}/target/wasm32-unknown-unknown/release/*.d`);
+ exe(`${cli} contract build`);
+}
+
+function filenameNoExtension(filename) {
+ return path.basename(filename, path.extname(filename));
+}
+
+function deploy(wasm) {
+ exe(
+ `${cli} contract deploy --wasm ${wasm} --ignore-checks --alias ${filenameNoExtension(
+ wasm,
+ )}`,
+ );
+}
+
+function deployAll() {
+ mkdirSync(contractsDir, { recursive: true });
+
+ const wasmFiles = glob(
+ `${dirname}/target/wasm32-unknown-unknown/release/*.wasm`,
+ );
+
+ wasmFiles.forEach(deploy);
+}
+
+function contracts() {
+ const contractFiles = glob(`${contractsDir}/*.json`);
+
+ return contractFiles
+ .map((path) => ({
+ alias: filenameNoExtension(path),
+ ...JSON.parse(readFileSync(path)),
+ }))
+ .filter((data) => data.ids[process.env.STELLAR_NETWORK_PASSPHRASE])
+ .map((data) => ({
+ alias: data.alias,
+ id: data.ids[process.env.STELLAR_NETWORK_PASSPHRASE],
+ }));
+}
+
+function bind({ alias, id }) {
+ exe(
+ `${cli} contract bindings typescript --contract-id ${id} --output-dir ${dirname}/packages/${alias} --overwrite`,
+ );
+ exe(`(cd ${dirname}/packages/${alias} && npm i && npm run build)`);
+}
+
+function bindAll() {
+ contracts().forEach(bind);
+}
+
+function importContract({ alias }) {
+ const outputDir = `${dirname}/src/contracts/`;
+
+ mkdirSync(outputDir, { recursive: true });
+
+ const importContent = `
+ import * as Client from '${alias}';
+ import { rpcUrl } from './util';
+
+ export default new Client.Client({
+ ...Client.networks.${process.env.STELLAR_NETWORK},
+ rpcUrl,
+ ${
+ process.env.STELLAR_NETWORK === "local" ||
+ process.env.STELLAR_NETWORK === "standalone"
+ ? "allowHttp: true,"
+ : ""
+ }
+ });
+`;
+
+ const outputPath = `${outputDir}/${alias}.ts`;
+
+ writeFileSync(outputPath, importContent);
+
+ console.log(`Created import for ${alias}`);
+}
+
+function importAll() {
+ contracts().forEach(importContract);
+}
+
+// Calling the functions (equivalent to the last part of your bash script)
+fundAll();
+buildAll();
+deployAll();
+bindAll();
+importAll();
diff --git a/package-lock.json b/package-lock.json
index 6d53d986..ac95697f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -7,6 +7,10 @@
"": {
"name": "boundless",
"version": "0.1.0",
+ "hasInstallScript": true,
+ "workspaces": [
+ "packages/*"
+ ],
"dependencies": {
"@auth/prisma-adapter": "^2.7.4",
"@creit.tech/stellar-wallets-kit": "^1.4.1",
@@ -24,6 +28,7 @@
"@radix-ui/react-slot": "^1.1.2",
"@radix-ui/react-tabs": "^1.1.3",
"@radix-ui/react-tooltip": "^1.1.7",
+ "@stellar/freighter-api": "^3.1.0",
"@stellar/stellar-sdk": "^13.1.0",
"@tanstack/react-query": "^5.66.11",
"@types/pg": "^8.11.11",
@@ -31,18 +36,20 @@
"bcrypt": "^5.1.1",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
+ "dotenv": "^16.4.7",
"framer-motion": "^12.4.2",
+ "glob": "^11.0.1",
"lucide-react": "^0.474.0",
"next": "^15.1.6",
"next-auth": "^4.24.11",
+ "next-themes": "^0.4.4",
"pg": "^8.13.1",
"react": "^18",
"react-dom": "^18",
"react-hook-form": "^7.54.2",
"recharts": "^2.15.1",
"resend": "^4.1.2",
- "sonner": "^2.0.0",
- "stellar-sdk": "^13.1.0",
+ "sonner": "^2.0.1",
"tailwind-merge": "^2.6.0",
"tailwindcss-animate": "^1.0.7",
"zod": "^3.24.2"
@@ -901,6 +908,12 @@
"@stellar/stellar-base": "^12.1.1"
}
},
+ "node_modules/@creit.tech/stellar-wallets-kit/node_modules/@stellar/freighter-api": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/@stellar/freighter-api/-/freighter-api-3.0.0.tgz",
+ "integrity": "sha512-AI1AeHnCPLMcM8d6182FScOJjCFd1tLZcNuu5M10NmtuLfNzavw+f991dWBoz6h41mOKjauIaojR+7VfU2nULg==",
+ "license": "Apache-2.0"
+ },
"node_modules/@creit.tech/stellar-wallets-kit/node_modules/@stellar/stellar-sdk": {
"version": "12.3.0",
"resolved": "https://registry.npmjs.org/@stellar/stellar-sdk/-/stellar-sdk-12.3.0.tgz",
@@ -4431,10 +4444,14 @@
}
},
"node_modules/@stellar/freighter-api": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/@stellar/freighter-api/-/freighter-api-3.0.0.tgz",
- "integrity": "sha512-AI1AeHnCPLMcM8d6182FScOJjCFd1tLZcNuu5M10NmtuLfNzavw+f991dWBoz6h41mOKjauIaojR+7VfU2nULg==",
- "license": "Apache-2.0"
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/@stellar/freighter-api/-/freighter-api-3.1.0.tgz",
+ "integrity": "sha512-hsoZwAR/jNVIt8ee6aHYcRKVk09hDLHmsfK2nUfqHUo7LuHtuHI59y/mDyrT4bp/qlklGZNd2nr0hRJyjau8WQ==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "buffer": "^6.0.3",
+ "semver": "^7.6.3"
+ }
},
"node_modules/@stellar/js-xdr": {
"version": "3.1.2",
@@ -7406,6 +7423,18 @@
"url": "https://github.com/fb55/domutils?sponsor=1"
}
},
+ "node_modules/dotenv": {
+ "version": "16.4.7",
+ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz",
+ "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://dotenvx.com"
+ }
+ },
"node_modules/dunder-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
@@ -8851,21 +8880,23 @@
}
},
"node_modules/glob": {
- "version": "7.2.3",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
- "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
- "deprecated": "Glob versions prior to v9 are no longer supported",
+ "version": "11.0.1",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.1.tgz",
+ "integrity": "sha512-zrQDm8XPnYEKawJScsnM0QzobJxlT/kHOOlRTio8IH/GrmxRE5fjllkzdaHclIuNjUQTJYH2xHNIGfdpJkDJUw==",
"license": "ISC",
"dependencies": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.1.1",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
+ "foreground-child": "^3.1.0",
+ "jackspeak": "^4.0.1",
+ "minimatch": "^10.0.0",
+ "minipass": "^7.1.2",
+ "package-json-from-dist": "^1.0.0",
+ "path-scurry": "^2.0.0"
+ },
+ "bin": {
+ "glob": "dist/esm/bin.mjs"
},
"engines": {
- "node": "*"
+ "node": "20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
@@ -8883,6 +8914,70 @@
"node": ">=10.13.0"
}
},
+ "node_modules/glob/node_modules/brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/glob/node_modules/jackspeak": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.0.tgz",
+ "integrity": "sha512-9DDdhb5j6cpeitCbvLO7n7J4IxnbM6hoF6O1g4HQ5TfhvvKN8ywDM7668ZhMHRqVmxqhps/F6syWK2KcPxYlkw==",
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "@isaacs/cliui": "^8.0.2"
+ },
+ "engines": {
+ "node": "20 || >=22"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/glob/node_modules/lru-cache": {
+ "version": "11.0.2",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.0.2.tgz",
+ "integrity": "sha512-123qHRfJBmo2jXDbo/a5YOQrJoHF/GNQTLzQ5+IdK5pWpceK17yRc6ozlWd25FxvGKQbIUs91fDFkXmDHTKcyA==",
+ "license": "ISC",
+ "engines": {
+ "node": "20 || >=22"
+ }
+ },
+ "node_modules/glob/node_modules/minimatch": {
+ "version": "10.0.1",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz",
+ "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==",
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": "20 || >=22"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/glob/node_modules/path-scurry": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz",
+ "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==",
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "lru-cache": "^11.0.0",
+ "minipass": "^7.1.2"
+ },
+ "engines": {
+ "node": "20 || >=22"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
"node_modules/globals": {
"version": "13.24.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
@@ -10935,6 +11030,16 @@
"url": "https://github.com/sponsors/panva"
}
},
+ "node_modules/next-themes": {
+ "version": "0.4.4",
+ "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.4.4.tgz",
+ "integrity": "sha512-LDQ2qIOJF0VnuVrrMSMLrWGjRMkq+0mpgl6e0juCLqdJ+oo8Q84JRWT6Wh11VDQKkMMe+dVzDKLWs5n87T+PkQ==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc"
+ }
+ },
"node_modules/next/node_modules/postcss": {
"version": "8.4.31",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
@@ -12013,6 +12118,10 @@
"integrity": "sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q==",
"license": "MIT"
},
+ "node_modules/project_contract": {
+ "resolved": "packages/project_contract",
+ "link": true
+ },
"node_modules/prop-types": {
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
@@ -12610,6 +12719,27 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/rimraf/node_modules/glob": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "deprecated": "Glob versions prior to v9 are no longer supported",
+ "license": "ISC",
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.1.1",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
"node_modules/ripemd160": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz",
@@ -13223,9 +13353,9 @@
}
},
"node_modules/sonner": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/sonner/-/sonner-2.0.0.tgz",
- "integrity": "sha512-3WeSl3WrEdhmdiTniT8JsCiVRVDOdn7k+4MG2drqzSMOeqrExm03HIwDBPKuq52JBqL7wRLG17QBIiSleUbljw==",
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/sonner/-/sonner-2.0.1.tgz",
+ "integrity": "sha512-FRBphaehZ5tLdLcQ8g2WOIRE+Y7BCfWi5Zyd8bCvBjiW8TxxAyoWZIxS661Yz6TGPqFQ4VLzOF89WEYhfynSFQ==",
"license": "MIT",
"peerDependencies": {
"react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc",
@@ -13272,40 +13402,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/stellar-sdk": {
- "version": "13.1.0",
- "resolved": "https://registry.npmjs.org/stellar-sdk/-/stellar-sdk-13.1.0.tgz",
- "integrity": "sha512-b7fYK9kX4ljulXckt63jSwzAzTW43RlitSIJH4CHTft7Fce8zNqWuNwJ29FALt258SKlxiL0qKn58LcOA9iJIw==",
- "deprecated": "⚠️ This package has moved to @stellar/stellar-sdk! 🚚",
- "license": "Apache-2.0",
- "dependencies": {
- "@stellar/stellar-base": "^13.0.1",
- "axios": "^1.7.9",
- "bignumber.js": "^9.1.2",
- "eventsource": "^2.0.2",
- "feaxios": "^0.0.23",
- "randombytes": "^2.1.0",
- "toml": "^3.0.0",
- "urijs": "^1.19.1"
- }
- },
- "node_modules/stellar-sdk/node_modules/@stellar/stellar-base": {
- "version": "13.0.1",
- "resolved": "https://registry.npmjs.org/@stellar/stellar-base/-/stellar-base-13.0.1.tgz",
- "integrity": "sha512-Xbd12mc9Oj/130Tv0URmm3wXG77XMshZtZ2yNCjqX5ZbMD5IYpbBs3DVCteLU/4SLj/Fnmhh1dzhrQXnk4r+pQ==",
- "license": "Apache-2.0",
- "dependencies": {
- "@stellar/js-xdr": "^3.1.2",
- "base32.js": "^0.1.0",
- "bignumber.js": "^9.1.2",
- "buffer": "^6.0.3",
- "sha.js": "^2.3.6",
- "tweetnacl": "^1.0.3"
- },
- "optionalDependencies": {
- "sodium-native": "^4.3.0"
- }
- },
"node_modules/stream-browserify": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz",
@@ -15032,6 +15128,58 @@
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
+ },
+ "packages/project_contract": {
+ "version": "0.0.0",
+ "dependencies": {
+ "@stellar/stellar-sdk": "13.0.0",
+ "buffer": "6.0.3"
+ },
+ "devDependencies": {
+ "typescript": "^5.6.2"
+ }
+ },
+ "packages/project_contract/node_modules/@stellar/stellar-base": {
+ "version": "13.0.1",
+ "resolved": "https://registry.npmjs.org/@stellar/stellar-base/-/stellar-base-13.0.1.tgz",
+ "integrity": "sha512-Xbd12mc9Oj/130Tv0URmm3wXG77XMshZtZ2yNCjqX5ZbMD5IYpbBs3DVCteLU/4SLj/Fnmhh1dzhrQXnk4r+pQ==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@stellar/js-xdr": "^3.1.2",
+ "base32.js": "^0.1.0",
+ "bignumber.js": "^9.1.2",
+ "buffer": "^6.0.3",
+ "sha.js": "^2.3.6",
+ "tweetnacl": "^1.0.3"
+ },
+ "optionalDependencies": {
+ "sodium-native": "^4.3.0"
+ }
+ },
+ "packages/project_contract/node_modules/@stellar/stellar-sdk": {
+ "version": "13.0.0",
+ "resolved": "https://registry.npmjs.org/@stellar/stellar-sdk/-/stellar-sdk-13.0.0.tgz",
+ "integrity": "sha512-+wvmKi+XWwu27nLYTM17EgBdpbKohEkOfCIK4XKfsI4WpMXAqvnqSm98i9h5dAblNB+w8BJqzGs1JY0PtTGm4A==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@stellar/stellar-base": "^13.0.1",
+ "axios": "^1.7.7",
+ "bignumber.js": "^9.1.2",
+ "eventsource": "^2.0.2",
+ "feaxios": "^0.0.20",
+ "randombytes": "^2.1.0",
+ "toml": "^3.0.0",
+ "urijs": "^1.19.1"
+ }
+ },
+ "packages/project_contract/node_modules/feaxios": {
+ "version": "0.0.20",
+ "resolved": "https://registry.npmjs.org/feaxios/-/feaxios-0.0.20.tgz",
+ "integrity": "sha512-g3hm2YDNffNxA3Re3Hd8ahbpmDee9Fv1Pb1C/NoWsjY7mtD8nyNeJytUzn+DK0Hyl9o6HppeWOrtnqgmhOYfWA==",
+ "license": "MIT",
+ "dependencies": {
+ "is-retry-allowed": "^3.0.0"
+ }
}
}
}
diff --git a/package.json b/package.json
index 8d3adaf1..6d666004 100644
--- a/package.json
+++ b/package.json
@@ -2,8 +2,10 @@
"name": "boundless",
"version": "0.1.0",
"private": true,
+ "type": "module",
"scripts": {
- "dev": "next dev",
+ "init": "node initialize.js",
+ "dev": "next dev --experimental-https",
"build": "next build",
"start": "next start",
"lint": "next lint",
@@ -40,6 +42,7 @@
"@radix-ui/react-slot": "^1.1.2",
"@radix-ui/react-tabs": "^1.1.3",
"@radix-ui/react-tooltip": "^1.1.7",
+ "@stellar/freighter-api": "^3.1.0",
"@stellar/stellar-sdk": "^13.1.0",
"@tanstack/react-query": "^5.66.11",
"@types/pg": "^8.11.11",
@@ -47,22 +50,25 @@
"bcrypt": "^5.1.1",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
+ "dotenv": "^16.4.7",
"framer-motion": "^12.4.2",
+ "glob": "^11.0.1",
"lucide-react": "^0.474.0",
"next": "^15.1.6",
"next-auth": "^4.24.11",
+ "next-themes": "^0.4.4",
"pg": "^8.13.1",
"react": "^18",
"react-dom": "^18",
- "recharts": "^2.15.1",
"react-hook-form": "^7.54.2",
+ "recharts": "^2.15.1",
"resend": "^4.1.2",
- "sonner": "^2.0.0",
- "stellar-sdk": "^13.1.0",
+ "sonner": "^2.0.1",
"tailwind-merge": "^2.6.0",
"tailwindcss-animate": "^1.0.7",
"zod": "^3.24.2"
},
+ "workspaces": ["packages/*"],
"devDependencies": {
"@biomejs/biome": "1.9.4",
"@types/bcrypt": "^5.0.2",
diff --git a/src/contracts/util.ts b/src/contracts/util.ts
new file mode 100644
index 00000000..642466b0
--- /dev/null
+++ b/src/contracts/util.ts
@@ -0,0 +1,6 @@
+export const rpcUrl =
+ process.env.PUBLIC_STELLAR_RPC_URL ??
+ "https://soroban-testnet.stellar.org:443";
+export const networkPassphrase =
+ process.env.PUBLIC_STELLAR_NETWORK_PASSPHRASE ??
+ "Test SDF Network ; September 2015";
diff --git a/tsconfig.json b/tsconfig.json
index d8b93235..eedb14e2 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,27 +1,33 @@
{
- "compilerOptions": {
- "target": "ES2017",
- "lib": ["dom", "dom.iterable", "esnext"],
- "allowJs": true,
- "skipLibCheck": true,
- "strict": true,
- "noEmit": true,
- "esModuleInterop": true,
- "module": "esnext",
- "moduleResolution": "bundler",
- "resolveJsonModule": true,
- "isolatedModules": true,
- "jsx": "preserve",
- "incremental": true,
- "plugins": [
- {
- "name": "next"
- }
- ],
- "paths": {
- "@/*": ["./*"]
- }
- },
- "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
- "exclude": ["node_modules"]
+ "compilerOptions": {
+ "target": "ES2017",
+ "lib": ["dom", "dom.iterable", "esnext"],
+ "allowJs": true,
+ "skipLibCheck": true,
+ "strict": true,
+ "noEmit": true,
+ "esModuleInterop": true,
+ "module": "esnext",
+ "moduleResolution": "bundler",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "jsx": "preserve",
+ "incremental": true,
+ "plugins": [
+ {
+ "name": "next"
+ }
+ ],
+ "paths": {
+ "@/*": ["./*"]
+ }
+ },
+ "include": [
+ "next-env.d.ts",
+ "**/*.ts",
+ "**/*.tsx",
+ ".next/types/**/*.ts",
+ "initialize.js"
+ ],
+ "exclude": ["node_modules", "packages"]
}