├── .eslintrc.json ├── public ├── favicon.ico ├── robots.txt ├── favicon-16x16.png ├── favicon-32x32.png ├── apple-touch-icon.png ├── android-chrome-192x192.png ├── android-chrome-512x512.png ├── vercel.svg ├── window.svg ├── file.svg ├── site.webmanifest ├── globe.svg ├── next.svg └── solana-sol-logo.svg ├── app ├── fonts │ ├── GeistVF.woff │ └── GeistMonoVF.woff ├── robot.ts ├── sitemap.ts ├── page.tsx ├── dashboard │ └── page.tsx ├── globals.css └── layout.tsx ├── switch ├── programs │ └── switch │ │ ├── Xargo.toml │ │ ├── Cargo.toml │ │ └── src │ │ └── lib.rs ├── .prettierignore ├── Cargo.toml ├── tsconfig.json ├── Anchor.toml ├── migrations │ └── deploy.ts ├── package.json ├── tests │ └── switch.ts └── yarn.lock ├── postcss.config.mjs ├── lib └── utils.ts ├── components.json ├── next.config.js ├── tsconfig.json ├── .gitignore ├── components ├── NetworkSwitcher.tsx ├── ui │ ├── animated-shiny-text.tsx │ ├── sonner.tsx │ ├── popover.tsx │ ├── button.tsx │ ├── accordion.tsx │ ├── card-spotlight.tsx │ ├── calendar.tsx │ ├── select.tsx │ ├── particles.tsx │ └── canvas-reveal-effect.tsx ├── WalletConnectionProvider.tsx ├── home │ ├── Dashboard.tsx │ ├── Hero.tsx │ ├── HowItWorks.tsx │ └── FAQ.tsx ├── custom-date-picker.tsx ├── Homepage.tsx ├── blocks │ └── features-section-demo-2.tsx └── DeadManSwitch.tsx ├── contexts └── NetworkConfigurationProvider.tsx ├── package.json ├── README.md ├── tailwind.config.ts └── types └── dead-man-switch.ts /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["next/core-web-vitals", "next/typescript"] 3 | } 4 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/retrogtx/eternal-key/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Allow: / 3 | 4 | Sitemap: https://eternalkey.xyz/sitemap.xml -------------------------------------------------------------------------------- /app/fonts/GeistVF.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/retrogtx/eternal-key/HEAD/app/fonts/GeistVF.woff -------------------------------------------------------------------------------- /switch/programs/switch/Xargo.toml: -------------------------------------------------------------------------------- 1 | [target.bpfel-unknown-unknown.dependencies.std] 2 | features = [] 3 | -------------------------------------------------------------------------------- /app/fonts/GeistMonoVF.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/retrogtx/eternal-key/HEAD/app/fonts/GeistMonoVF.woff -------------------------------------------------------------------------------- /public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/retrogtx/eternal-key/HEAD/public/favicon-16x16.png -------------------------------------------------------------------------------- /public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/retrogtx/eternal-key/HEAD/public/favicon-32x32.png -------------------------------------------------------------------------------- /public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/retrogtx/eternal-key/HEAD/public/apple-touch-icon.png -------------------------------------------------------------------------------- /switch/.prettierignore: -------------------------------------------------------------------------------- 1 | 2 | .anchor 3 | .DS_Store 4 | target 5 | node_modules 6 | dist 7 | build 8 | test-ledger 9 | -------------------------------------------------------------------------------- /public/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/retrogtx/eternal-key/HEAD/public/android-chrome-192x192.png -------------------------------------------------------------------------------- /public/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/retrogtx/eternal-key/HEAD/public/android-chrome-512x512.png -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /postcss.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('postcss-load-config').Config} */ 2 | const config = { 3 | plugins: { 4 | tailwindcss: {}, 5 | }, 6 | }; 7 | 8 | export default config; 9 | -------------------------------------------------------------------------------- /lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { clsx, type ClassValue } from "clsx" 2 | import { twMerge } from "tailwind-merge" 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)) 6 | } 7 | -------------------------------------------------------------------------------- /switch/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "2" 3 | members = [ 4 | "programs/*" 5 | ] 6 | 7 | [profile.release] 8 | overflow-checks = true 9 | lto = "fat" 10 | codegen-units = 1 11 | [profile.release.build-override] 12 | opt-level = 3 13 | incremental = false 14 | codegen-units = 1 15 | -------------------------------------------------------------------------------- /app/robot.ts: -------------------------------------------------------------------------------- 1 | import type { MetadataRoute } from 'next' 2 | 3 | export default function robots(): MetadataRoute.Robots { 4 | return { 5 | rules: { 6 | userAgent: '*', 7 | allow: '/', 8 | disallow: [], 9 | }, 10 | sitemap: 'https://eternalkey.xyz/sitemap.xml', 11 | } 12 | } -------------------------------------------------------------------------------- /app/sitemap.ts: -------------------------------------------------------------------------------- 1 | import type { MetadataRoute } from 'next' 2 | 3 | export default function sitemap(): MetadataRoute.Sitemap { 4 | return [ 5 | { 6 | url: 'https://eternalkey.xyz', 7 | lastModified: new Date(), 8 | changeFrequency: 'yearly', 9 | priority: 1, 10 | } 11 | ] 12 | } -------------------------------------------------------------------------------- /switch/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "types": ["mocha", "chai"], 4 | "typeRoots": ["./node_modules/@types"], 5 | "lib": ["es2015"], 6 | "module": "commonjs", 7 | "target": "es6", 8 | "esModuleInterop": true 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /public/window.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/file.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "default", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.ts", 8 | "css": "app/globals.css", 9 | "baseColor": "slate", 10 | "cssVariables": true 11 | }, 12 | "aliases": { 13 | "components": "@/components", 14 | "utils": "@/lib/utils" 15 | } 16 | } -------------------------------------------------------------------------------- /switch/Anchor.toml: -------------------------------------------------------------------------------- 1 | [features] 2 | seeds = false 3 | skip-lint = false 4 | 5 | [programs.devnet] 6 | switch = "8hK7vGkWap7CwfWnZG8igqz5uxevUDTbhoeuCcwgvpYq" 7 | 8 | [registry] 9 | url = "https://api.apr.dev" 10 | 11 | [provider] 12 | cluster = "devnet" 13 | wallet = "/home/amrit/.config/solana/id.json" 14 | 15 | [scripts] 16 | test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts" 17 | -------------------------------------------------------------------------------- /switch/migrations/deploy.ts: -------------------------------------------------------------------------------- 1 | // Migrations are an early feature. Currently, they're nothing more than this 2 | // single deploy script that's invoked from the CLI, injecting a provider 3 | // configured from the workspace's Anchor.toml. 4 | 5 | import * as anchor from '@project-serum/anchor'; 6 | 7 | module.exports = async function (provider: anchor.Provider) { 8 | anchor.setProvider(provider); 9 | }; 10 | -------------------------------------------------------------------------------- /switch/programs/switch/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "switch" 3 | version = "0.1.0" 4 | description = "Created with Anchor" 5 | edition = "2021" 6 | 7 | [lib] 8 | crate-type = ["cdylib", "lib"] 9 | 10 | [features] 11 | no-entrypoint = [] 12 | no-idl = [] 13 | no-log-ix-name = [] 14 | cpi = ["no-entrypoint"] 15 | default = [] 16 | idl-build = ["anchor-lang/idl-build"] 17 | 18 | [dependencies] 19 | anchor-lang = "0.30.1" 20 | -------------------------------------------------------------------------------- /switch/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "test": "anchor test" 4 | }, 5 | "devDependencies": { 6 | "@types/bn.js": "^5.1.0", 7 | "@types/chai": "^4.3.20", 8 | "@types/mocha": "^9.1.1", 9 | "chai": "^4.5.0", 10 | "mocha": "^9.0.3", 11 | "ts-mocha": "^10.0.0", 12 | "typescript": "^4.3.5" 13 | }, 14 | "dependencies": { 15 | "@project-serum/anchor": "^0.26.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /public/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Eternal Key", 3 | "short_name": "Eternal Key", 4 | "description": "Decentralized crypto inheritance on Solana", 5 | "icons": [ 6 | { 7 | "src": "/android-chrome-192x192.png", 8 | "sizes": "192x192", 9 | "type": "image/png" 10 | }, 11 | { 12 | "src": "/android-chrome-512x512.png", 13 | "sizes": "512x512", 14 | "type": "image/png" 15 | } 16 | ], 17 | "theme_color": "#000000", 18 | "background_color": "#000000", 19 | "display": "standalone" 20 | } -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | output: 'standalone', 4 | images: { 5 | unoptimized: true, 6 | }, 7 | webpack: (config) => { 8 | config.resolve.fallback = { fs: false }; 9 | return config; 10 | }, 11 | async headers() { 12 | return [ 13 | { 14 | source: '/:path*', 15 | headers: [ 16 | { 17 | key: 'Cache-Control', 18 | value: 'public, max-age=31536000, immutable', 19 | }, 20 | ], 21 | }, 22 | ]; 23 | }, 24 | }; 25 | 26 | module.exports = nextConfig; 27 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2017", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "noEmit": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "jsx": "preserve", 15 | "incremental": true, 16 | "plugins": [ 17 | { 18 | "name": "next" 19 | } 20 | ], 21 | "paths": { 22 | "@/*": ["./*"] 23 | } 24 | }, 25 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 26 | "exclude": ["node_modules"] 27 | } 28 | -------------------------------------------------------------------------------- /app/page.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import React, { FC } from 'react'; 4 | import dynamic from 'next/dynamic'; 5 | import '@solana/wallet-adapter-react-ui/styles.css'; 6 | import { NetworkConfigurationProvider } from '@/contexts/NetworkConfigurationProvider'; 7 | 8 | const WalletConnectionProvider = dynamic( 9 | () => import('@/components/WalletConnectionProvider'), 10 | { ssr: false } 11 | ); 12 | 13 | import Homepage from '@/components/Homepage'; 14 | 15 | const Home: FC = () => { 16 | return ( 17 | 18 | 19 | 20 | 21 | 22 | ); 23 | }; 24 | 25 | export default Home; 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.* 7 | .yarn/* 8 | !.yarn/patches 9 | !.yarn/plugins 10 | !.yarn/releases 11 | !.yarn/versions 12 | 13 | # testing 14 | /coverage 15 | 16 | # next.js 17 | /.next/ 18 | /out/ 19 | 20 | # production 21 | /build 22 | 23 | # misc 24 | .DS_Store 25 | *.pem 26 | tasks 27 | 28 | # debug 29 | npm-debug.log* 30 | yarn-debug.log* 31 | yarn-error.log* 32 | 33 | # env files (can opt-in for commiting if needed) 34 | .env* 35 | 36 | # vercel 37 | .vercel 38 | 39 | # typescript 40 | *.tsbuildinfo 41 | next-env.d.ts 42 | 43 | # Anchor 44 | switch/node_modules 45 | .anchor 46 | target 47 | **/*.rs.bk 48 | test-ledger 49 | -------------------------------------------------------------------------------- /components/NetworkSwitcher.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { FC } from 'react'; 4 | import { useNetworkConfiguration } from '@/contexts/NetworkConfigurationProvider'; 5 | import { WalletAdapterNetwork } from '@solana/wallet-adapter-base'; 6 | import { toast } from "sonner"; 7 | 8 | export const NetworkSwitcher: FC = () => { 9 | const { networkConfiguration } = useNetworkConfiguration(); 10 | 11 | const handleNetworkSwitch = () => { 12 | toast.error("Mainnet functionality is under development"); 13 | }; 14 | 15 | return ( 16 | 22 | ); 23 | }; -------------------------------------------------------------------------------- /public/globe.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /components/ui/animated-shiny-text.tsx: -------------------------------------------------------------------------------- 1 | import { CSSProperties, FC, ReactNode } from "react"; 2 | 3 | import { cn } from "@/lib/utils"; 4 | 5 | interface AnimatedShinyTextProps { 6 | children: ReactNode; 7 | className?: string; 8 | shimmerWidth?: number; 9 | } 10 | 11 | const AnimatedShinyText: FC = ({ 12 | children, 13 | className, 14 | shimmerWidth = 100, 15 | }) => { 16 | return ( 17 |

30 | {children} 31 |

32 | ); 33 | }; 34 | 35 | export default AnimatedShinyText; 36 | -------------------------------------------------------------------------------- /components/ui/sonner.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import { useTheme } from "next-themes" 4 | import { Toaster as Sonner } from "sonner" 5 | 6 | type ToasterProps = React.ComponentProps 7 | 8 | const Toaster = ({ ...props }: ToasterProps) => { 9 | const { theme = "system" } = useTheme() 10 | 11 | return ( 12 | 28 | ) 29 | } 30 | 31 | export { Toaster } 32 | -------------------------------------------------------------------------------- /contexts/NetworkConfigurationProvider.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { createContext, FC, ReactNode, useContext, useState } from 'react'; 4 | import { WalletAdapterNetwork } from '@solana/wallet-adapter-base'; 5 | 6 | interface NetworkConfigurationContextState { 7 | networkConfiguration: WalletAdapterNetwork; 8 | setNetworkConfiguration: (network: WalletAdapterNetwork) => void; 9 | } 10 | 11 | const NetworkConfigurationContext = createContext({} as NetworkConfigurationContextState); 12 | 13 | export function useNetworkConfiguration() { 14 | return useContext(NetworkConfigurationContext); 15 | } 16 | 17 | export const NetworkConfigurationProvider: FC<{ children: ReactNode }> = ({ children }) => { 18 | const [networkConfiguration, setNetworkConfiguration] = useState(WalletAdapterNetwork.Devnet); 19 | 20 | return ( 21 | 22 | {children} 23 | 24 | ); 25 | }; -------------------------------------------------------------------------------- /public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /components/ui/popover.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as PopoverPrimitive from "@radix-ui/react-popover" 5 | 6 | import { cn } from "@/lib/utils" 7 | 8 | const Popover = PopoverPrimitive.Root 9 | 10 | const PopoverTrigger = PopoverPrimitive.Trigger 11 | 12 | const PopoverAnchor = PopoverPrimitive.Anchor 13 | 14 | const PopoverContent = React.forwardRef< 15 | React.ElementRef, 16 | React.ComponentPropsWithoutRef 17 | >(({ className, align = "center", sideOffset = 4, ...props }, ref) => ( 18 | 19 | 29 | 30 | )) 31 | PopoverContent.displayName = PopoverPrimitive.Content.displayName 32 | 33 | export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor } 34 | -------------------------------------------------------------------------------- /components/WalletConnectionProvider.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import React, { FC, useMemo } from 'react'; 4 | import { ConnectionProvider, WalletProvider } from '@solana/wallet-adapter-react'; 5 | import { SolflareWalletAdapter } from '@solana/wallet-adapter-wallets'; 6 | import { clusterApiUrl } from '@solana/web3.js'; 7 | import { useNetworkConfiguration } from '@/contexts/NetworkConfigurationProvider'; 8 | import dynamic from 'next/dynamic'; 9 | 10 | const WalletModalProviderDynamic = dynamic( 11 | () => import('@solana/wallet-adapter-react-ui').then(mod => mod.WalletModalProvider), 12 | { ssr: false } 13 | ); 14 | 15 | export const WalletConnectionProvider: FC<{ children: React.ReactNode }> = ({ children }) => { 16 | const { networkConfiguration } = useNetworkConfiguration(); 17 | 18 | const endpoint = useMemo(() => { 19 | return clusterApiUrl(networkConfiguration); 20 | }, [networkConfiguration]); 21 | 22 | const wallets = useMemo( 23 | () => { 24 | if (typeof window !== 'undefined') { 25 | return [ 26 | new SolflareWalletAdapter(), 27 | ]; 28 | } 29 | return []; 30 | }, 31 | [] 32 | ); 33 | 34 | return ( 35 | 36 | 37 | {children} 38 | 39 | 40 | ); 41 | }; 42 | 43 | export default WalletConnectionProvider; 44 | -------------------------------------------------------------------------------- /components/home/Dashboard.tsx: -------------------------------------------------------------------------------- 1 | import { NetworkSwitcher } from '@/components/NetworkSwitcher'; 2 | import dynamic from 'next/dynamic'; 3 | 4 | const WalletMultiButton = dynamic( 5 | () => import('@solana/wallet-adapter-react-ui').then((mod) => mod.WalletMultiButton), 6 | { ssr: false } 7 | ); 8 | 9 | const DeadManSwitch = dynamic( 10 | () => import('@/components/DeadManSwitch'), 11 | { ssr: false } 12 | ); 13 | 14 | export const Dashboard = () => { 15 | return ( 16 |
17 | 31 | 32 |
33 |
34 | 35 |
36 |
37 |
38 | ); 39 | }; -------------------------------------------------------------------------------- /components/home/Hero.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from "@/lib/utils"; 2 | import { ArrowRightIcon } from "lucide-react"; 3 | import AnimatedShinyText from "@/components/ui/animated-shiny-text"; 4 | import dynamic from 'next/dynamic'; 5 | 6 | const WalletMultiButton = dynamic( 7 | () => import('@solana/wallet-adapter-react-ui').then((mod) => mod.WalletMultiButton), 8 | { ssr: false } 9 | ); 10 | 11 | export const Hero = () => { 12 | return ( 13 |
14 |
15 |
18 | 19 | ✨ Join the beta 20 | 21 | 22 |
23 |

24 | Eternal Key 25 |

26 |
27 |

28 | The next generation of digital asset inheritance. 29 |
30 | Secure, automated, and decentralized on Solana. 31 |

32 |
33 | 34 |
35 |
36 | ); 37 | }; -------------------------------------------------------------------------------- /components/custom-date-picker.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import { format } from "date-fns" 5 | import { CalendarIcon } from "lucide-react" 6 | 7 | import { cn } from "@/lib/utils" 8 | import { Button } from "@/components/ui/button" 9 | import { Calendar } from "@/components/ui/calendar" 10 | import { 11 | Popover, 12 | PopoverContent, 13 | PopoverTrigger, 14 | } from "@/components/ui/popover" 15 | 16 | interface DatePickerDemoProps { 17 | selected?: Date 18 | onSelect?: (date: Date | undefined) => void 19 | } 20 | 21 | export function DatePickerDemo({ selected, onSelect }: DatePickerDemoProps) { 22 | return ( 23 | 24 | 25 | 43 | 44 | 48 | 55 | 56 | 57 | ) 58 | } 59 | -------------------------------------------------------------------------------- /public/solana-sol-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 10 | 11 | 12 | 13 | 14 | 16 | 17 | 18 | 19 | 20 | 22 | 23 | 24 | 25 | 26 | 28 | 29 | -------------------------------------------------------------------------------- /app/dashboard/page.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import React, { FC, useEffect, useState } from 'react'; 4 | import { useWallet } from '@solana/wallet-adapter-react'; 5 | import { useRouter } from 'next/navigation'; 6 | import dynamic from 'next/dynamic'; 7 | 8 | const DeadManSwitch = dynamic( 9 | () => import('@/components/DeadManSwitch'), 10 | { ssr: false } 11 | ); 12 | 13 | const Dashboard: FC = () => { 14 | const { connected } = useWallet(); 15 | const router = useRouter(); 16 | const [isLoading, setIsLoading] = useState(true); 17 | 18 | useEffect(() => { 19 | const checkWallet = async () => { 20 | // Add a small delay to prevent immediate redirection 21 | await new Promise(resolve => setTimeout(resolve, 500)); 22 | 23 | if (!connected) { 24 | router.replace('/'); 25 | } 26 | setIsLoading(false); 27 | }; 28 | 29 | checkWallet(); 30 | }, [connected, router]); 31 | 32 | // Show nothing while checking wallet status 33 | if (isLoading) { 34 | return null; 35 | } 36 | 37 | // If not connected, show nothing (redirect will happen) 38 | if (!connected) { 39 | return null; 40 | } 41 | 42 | return ( 43 |
44 | 57 | 58 |
59 | 60 |
61 |
62 | ); 63 | }; 64 | 65 | export default Dashboard; -------------------------------------------------------------------------------- /app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | body { 6 | font-family: Arial, Helvetica, sans-serif; 7 | } 8 | 9 | @layer base { 10 | :root { 11 | --background: 0 0% 100%; 12 | --foreground: 0 0% 3.9%; 13 | --card: 0 0% 100%; 14 | --card-foreground: 0 0% 3.9%; 15 | --popover: 0 0% 100%; 16 | --popover-foreground: 0 0% 3.9%; 17 | --primary: 0 0% 9%; 18 | --primary-foreground: 0 0% 98%; 19 | --secondary: 0 0% 96.1%; 20 | --secondary-foreground: 0 0% 9%; 21 | --muted: 0 0% 96.1%; 22 | --muted-foreground: 0 0% 45.1%; 23 | --accent: 0 0% 96.1%; 24 | --accent-foreground: 0 0% 9%; 25 | --destructive: 0 84.2% 60.2%; 26 | --destructive-foreground: 0 0% 98%; 27 | --border: 0 0% 89.8%; 28 | --input: 0 0% 89.8%; 29 | --ring: 0 0% 3.9%; 30 | --chart-1: 12 76% 61%; 31 | --chart-2: 173 58% 39%; 32 | --chart-3: 197 37% 24%; 33 | --chart-4: 43 74% 66%; 34 | --chart-5: 27 87% 67%; 35 | --radius: 0.5rem; 36 | } 37 | .dark { 38 | --background: 0 0% 3.9%; 39 | --foreground: 0 0% 98%; 40 | --card: 0 0% 3.9%; 41 | --card-foreground: 0 0% 98%; 42 | --popover: 0 0% 3.9%; 43 | --popover-foreground: 0 0% 98%; 44 | --primary: 0 0% 98%; 45 | --primary-foreground: 0 0% 9%; 46 | --secondary: 0 0% 14.9%; 47 | --secondary-foreground: 0 0% 98%; 48 | --muted: 0 0% 14.9%; 49 | --muted-foreground: 0 0% 63.9%; 50 | --accent: 0 0% 14.9%; 51 | --accent-foreground: 0 0% 98%; 52 | --destructive: 0 62.8% 30.6%; 53 | --destructive-foreground: 0 0% 98%; 54 | --border: 0 0% 14.9%; 55 | --input: 0 0% 14.9%; 56 | --ring: 0 0% 83.1%; 57 | --chart-1: 220 70% 50%; 58 | --chart-2: 160 60% 45%; 59 | --chart-3: 30 80% 55%; 60 | --chart-4: 280 65% 60%; 61 | --chart-5: 340 75% 55%; 62 | } 63 | } 64 | 65 | @layer base { 66 | * { 67 | @apply border-border; 68 | } 69 | body { 70 | @apply bg-background text-foreground; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sol-deadlock", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint", 10 | "test": "cd switch && anchor test" 11 | }, 12 | "dependencies": { 13 | "@coral-xyz/anchor": "^0.28.0", 14 | "@project-serum/anchor": "^0.26.0", 15 | "@radix-ui/react-accordion": "^1.2.1", 16 | "@radix-ui/react-icons": "^1.3.2", 17 | "@radix-ui/react-popover": "^1.1.2", 18 | "@radix-ui/react-select": "^2.1.2", 19 | "@radix-ui/react-slot": "^1.1.0", 20 | "@radix-ui/react-toast": "^1.2.2", 21 | "@react-three/fiber": "^8.17.10", 22 | "@solana/wallet-adapter-base": "^0.9.23", 23 | "@solana/wallet-adapter-particle": "^0.1.12", 24 | "@solana/wallet-adapter-react": "^0.15.35", 25 | "@solana/wallet-adapter-react-ui": "^0.9.35", 26 | "@solana/wallet-adapter-wallets": "^0.19.32", 27 | "@solana/web3.js": "^1.95.4", 28 | "@tabler/icons-react": "^3.22.0", 29 | "@types/three": "^0.170.0", 30 | "@vercel/analytics": "^1.4.0", 31 | "bs58": "^6.0.0", 32 | "class-variance-authority": "^0.7.0", 33 | "clsx": "^2.1.1", 34 | "cobe": "^0.6.3", 35 | "date-fns": "^3.6.0", 36 | "framer-motion": "^11.11.17", 37 | "lucide-react": "^0.454.0", 38 | "next": "^14.1.0", 39 | "next-themes": "^0.4.3", 40 | "pino-pretty": "^11.3.0", 41 | "react": "^18.2.0", 42 | "react-day-picker": "^8.10.1", 43 | "react-dom": "^18.2.0", 44 | "sonner": "^1.7.0", 45 | "tailwind-merge": "^2.5.4", 46 | "tailwindcss-animate": "^1.0.7", 47 | "three": "^0.170.0" 48 | }, 49 | "devDependencies": { 50 | "@types/chai": "^4.3.0", 51 | "@types/mocha": "^9.0.0", 52 | "@types/node": "^20", 53 | "@types/react": "^18", 54 | "@types/react-dom": "^18", 55 | "chai": "^4.3.4", 56 | "eslint": "^8", 57 | "eslint-config-next": "15.0.1", 58 | "mocha": "^9.0.3", 59 | "postcss": "^8", 60 | "tailwindcss": "^3.4.1", 61 | "ts-mocha": "^10.0.0", 62 | "typescript": "^5" 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /components/ui/button.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import { Slot } from "@radix-ui/react-slot" 3 | import { cva, type VariantProps } from "class-variance-authority" 4 | 5 | import { cn } from "@/lib/utils" 6 | 7 | const buttonVariants = cva( 8 | "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", 9 | { 10 | variants: { 11 | variant: { 12 | default: 13 | "bg-primary text-primary-foreground shadow hover:bg-primary/90", 14 | destructive: 15 | "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90", 16 | outline: 17 | "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground", 18 | secondary: 19 | "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80", 20 | ghost: "hover:bg-accent hover:text-accent-foreground", 21 | link: "text-primary underline-offset-4 hover:underline", 22 | }, 23 | size: { 24 | default: "h-9 px-4 py-2", 25 | sm: "h-8 rounded-md px-3 text-xs", 26 | lg: "h-10 rounded-md px-8", 27 | icon: "h-9 w-9", 28 | }, 29 | }, 30 | defaultVariants: { 31 | variant: "default", 32 | size: "default", 33 | }, 34 | } 35 | ) 36 | 37 | export interface ButtonProps 38 | extends React.ButtonHTMLAttributes, 39 | VariantProps { 40 | asChild?: boolean 41 | } 42 | 43 | const Button = React.forwardRef( 44 | ({ className, variant, size, asChild = false, ...props }, ref) => { 45 | const Comp = asChild ? Slot : "button" 46 | return ( 47 | 52 | ) 53 | } 54 | ) 55 | Button.displayName = "Button" 56 | 57 | export { Button, buttonVariants } 58 | -------------------------------------------------------------------------------- /components/ui/accordion.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as AccordionPrimitive from "@radix-ui/react-accordion" 5 | import { ChevronDown } from "lucide-react" 6 | 7 | import { cn } from "@/lib/utils" 8 | 9 | const Accordion = AccordionPrimitive.Root 10 | 11 | const AccordionItem = React.forwardRef< 12 | React.ElementRef, 13 | React.ComponentPropsWithoutRef 14 | >(({ className, ...props }, ref) => ( 15 | 20 | )) 21 | AccordionItem.displayName = "AccordionItem" 22 | 23 | const AccordionTrigger = React.forwardRef< 24 | React.ElementRef, 25 | React.ComponentPropsWithoutRef 26 | >(({ className, children, ...props }, ref) => ( 27 | 28 | svg]:rotate-180", 32 | className 33 | )} 34 | {...props} 35 | > 36 | {children} 37 | 38 | 39 | 40 | )) 41 | AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName 42 | 43 | const AccordionContent = React.forwardRef< 44 | React.ElementRef, 45 | React.ComponentPropsWithoutRef 46 | >(({ className, children, ...props }, ref) => ( 47 | 52 |
{children}
53 |
54 | )) 55 | AccordionContent.displayName = AccordionPrimitive.Content.displayName 56 | 57 | export { Accordion, AccordionItem, AccordionTrigger, AccordionContent } 58 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Eternal Key 🔑 2 | 3 | A decentralized "dead man's switch" for crypto inheritance on Solana, ensuring your digital assets reach your loved ones. Or just use it as a simple time-lock for your solana based asset to surprise someone on their birthday maybe. 4 | 5 | ## 🌟 The Problem 6 | 7 | What if Satoshi Nakamoto wanted to pass on his 1.1 million BTC but disappeared or passed away? In the crypto world, there's no built-in inheritance system. Unlike traditional banking, crypto assets can be permanently lost if the owner passes away without sharing their private keys or recovery phrases. I wished to make something that would allow people to easily set up an inheritance system for their crypto assets, without the need of a centralized service. 8 | 9 | ## 💡 The Solution 10 | 11 | Eternal Key provides an automated, trustless solution for crypto inheritance: 12 | 13 | - Set up a "dead man's switch" that activates after a period of inactivity 14 | - Designate beneficiaries who can claim assets after the deadline 15 | - Regular "check-ins" to prove you're still active 16 | - Completely decentralized and non-custodial 17 | - Built on Solana for speed and low costs 18 | - The SOL locked into the escrow can be recovered once the account is closed upon withdrawal from the beneficiary. 19 | 20 | ## 🚀 Features 21 | 22 | - **Activity Monitoring**: Automated tracking of wallet activity 23 | - **Secure Transfers**: Trustless transfer to beneficiaries after inactivity threshold 24 | - **Flexible Check-ins**: Extend your deadline with simple check-in transactions 25 | - **Multi-Asset Support**: Works with SOL and other Solana tokens 26 | - **Non-custodial**: You maintain full control of your assets 27 | - **Low Cost**: Minimal fees for setup and maintenance 28 | 29 | ## 💻 Smart Contract 30 | 31 | The core functionality is implemented in Rust using the Anchor framework: 32 | 33 | - `initialize`: Create new dead man's switch 34 | - `deposit`: Add funds to escrow 35 | - `checkin`: Reset/extend the deadline 36 | - `claim`: Beneficiary claims funds after deadline 37 | - `cancel`: Owner cancels switch and reclaims funds 38 | 39 |

🏆 Backed by a $3000 grant from Superteam

40 |

Built with ❤️ for the Solana community

41 | -------------------------------------------------------------------------------- /components/ui/card-spotlight.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import { useMotionValue, motion, useMotionTemplate } from "framer-motion"; 4 | import React, { MouseEvent as ReactMouseEvent, useState } from "react"; 5 | import { CanvasRevealEffect } from "@/components/ui/canvas-reveal-effect"; 6 | import { cn } from "@/lib/utils"; 7 | 8 | export const CardSpotlight = ({ 9 | children, 10 | radius = 350, 11 | color = "#262626", 12 | className, 13 | ...props 14 | }: { 15 | radius?: number; 16 | color?: string; 17 | children: React.ReactNode; 18 | } & React.HTMLAttributes) => { 19 | const mouseX = useMotionValue(0); 20 | const mouseY = useMotionValue(0); 21 | function handleMouseMove({ 22 | currentTarget, 23 | clientX, 24 | clientY, 25 | }: ReactMouseEvent) { 26 | const { left, top } = currentTarget.getBoundingClientRect(); 27 | 28 | mouseX.set(clientX - left); 29 | mouseY.set(clientY - top); 30 | } 31 | 32 | const [isHovering, setIsHovering] = useState(false); 33 | const handleMouseEnter = () => setIsHovering(true); 34 | const handleMouseLeave = () => setIsHovering(false); 35 | return ( 36 |
46 | 59 | {isHovering && ( 60 | 69 | )} 70 | 71 | {children} 72 |
73 | ); 74 | }; 75 | -------------------------------------------------------------------------------- /components/Homepage.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import React, { FC } from 'react'; 4 | import { useWallet } from '@solana/wallet-adapter-react'; 5 | import Particles from "@/components/ui/particles"; 6 | import FeaturesSectionDemo from "@/components/blocks/features-section-demo-2"; 7 | import { Hero } from '@/components/home/Hero'; 8 | import { HowItWorks } from '@/components/home/HowItWorks'; 9 | import { FAQ } from '@/components/home/FAQ'; 10 | import { Dashboard } from '@/components/home/Dashboard'; 11 | 12 | const structuredData = { 13 | "@context": "https://schema.org", 14 | "@type": "SoftwareApplication", 15 | "name": "Eternal Key", 16 | "applicationCategory": "DeFi", 17 | "operatingSystem": "Web", 18 | "description": "A decentralized dead man's switch for crypto inheritance on Solana, ensuring your digital assets reach your loved ones.", 19 | "offers": { 20 | "@type": "Offer", 21 | "price": "0", 22 | "priceCurrency": "USD" 23 | }, 24 | "author": { 25 | "@type": "Person", 26 | "name": "Amrit", 27 | "url": "https://twitter.com/amritwt" 28 | } 29 | }; 30 | 31 | const Homepage: FC = () => { 32 | const { connected } = useWallet(); 33 | 34 | if (connected) { 35 | return ; 36 | } 37 | 38 | return ( 39 | <> 40 |