From 935b7700b05828d6a60c9ad5aa2a731725838942 Mon Sep 17 00:00:00 2001 From: Randika Dilshan Date: Thu, 17 Jul 2025 10:53:45 +0530 Subject: [PATCH 1/3] Refactor dashboard page to utilize chain-db services for fetching members and transfers, --- app/[alias]/(dashboard)/page.tsx | 37 +++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/app/[alias]/(dashboard)/page.tsx b/app/[alias]/(dashboard)/page.tsx index f92dd171..89322408 100644 --- a/app/[alias]/(dashboard)/page.tsx +++ b/app/[alias]/(dashboard)/page.tsx @@ -1,10 +1,11 @@ -import { getMembersAction } from '@/app/[alias]/(dashboard)/members/action'; -import { getTransfersOfTokenAction } from '@/app/[alias]/(dashboard)/transfers/actions'; import { getAuthUserAction } from '@/app/_actions/user-actions'; import { MetricCard, MetricCardSkeleton } from '@/components/custom/metric-card'; +import { getServiceRoleClient as getChainDbServiceRoleClient } from '@/services/chain-db'; +import { getMembers } from '@/services/chain-db/members'; +import { getTransfersOfToken } from '@/services/chain-db/transfers'; import { getServiceRoleClient } from '@/services/top-db'; import { getCommunityByAlias } from '@/services/top-db/community'; import { SupabaseClient } from '@supabase/supabase-js'; @@ -96,14 +97,19 @@ export default async function Page(props: { async function getMembersOverview({ alias, client }: { alias: string, client: SupabaseClient }) { - const { data, error } = await getCommunityByAlias(client, alias); + const { data: communityData, error: communityError } = await getCommunityByAlias(client, alias); - if (error || !data) { + if (communityError || !communityData) { throw new Error('Failed to get community by alias'); } - const { count } = await getMembersAction({ - config: data.json, + const { chain_id: chainId, address: profileContract } = communityData.json.community.profile; + const supabase = getChainDbServiceRoleClient(chainId); + + + const { count } = await getMembers({ + client: supabase, + profileContract, query: '', page: 1, showAllMembers: true @@ -119,17 +125,24 @@ async function getMembersOverview({ alias, client }: { alias: string, client: Su } async function getTransactionsOverview({ alias, client }: { alias: string, client: SupabaseClient }) { - const { data, error } = await getCommunityByAlias(client, alias); + const { data: communityData, error: communityError } = await getCommunityByAlias(client, alias); - if (error || !data) { + if (communityError || !communityData) { throw new Error('Failed to get community by alias'); } - const { count } = await getTransfersOfTokenAction({ - config: data.json, + const { chain_id: chainId, address: tokenAddress } = + communityData.json.community.primary_token; + const supabase = getChainDbServiceRoleClient(chainId); + + + const { count } = await getTransfersOfToken({ + client: supabase, + token: tokenAddress, query: '', - page: 1 - }); + page: 1, + }) + return ( Date: Thu, 17 Jul 2025 10:54:34 +0530 Subject: [PATCH 2/3] Update TransferWithMembersResponseT with specific fields for improved data handling. --- services/chain-db/transfers.ts | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/services/chain-db/transfers.ts b/services/chain-db/transfers.ts index 918b38ef..d5a14d2b 100644 --- a/services/chain-db/transfers.ts +++ b/services/chain-db/transfers.ts @@ -5,7 +5,7 @@ import { MemberT } from './members'; import { ethers } from 'ethers'; const TABLE_NAME = 'a_transfers'; -export const PAGE_SIZE = 25; +export const PAGE_SIZE = 20; export interface TransferT { id: string; @@ -24,6 +24,12 @@ export interface TransferWithMembersT extends TransferT { to_member: MemberT; } +export interface TransferWithMembersResponseT + extends Pick { + from_member: MemberT; + to_member: MemberT; +} + export const getTransfersOfToken = async (args: { client: SupabaseClient; token: string; @@ -31,7 +37,7 @@ export const getTransfersOfToken = async (args: { page: number; from?: string; to?: string; -}): Promise> => { +}): Promise> => { const { client, token, query, page, from, to } = args; const offset = (page - 1) * PAGE_SIZE; @@ -40,14 +46,16 @@ export const getTransfersOfToken = async (args: { let queryBuilder = client .from(TABLE_NAME) .select( - ` - *, + `hash, + value, + description, from_member:a_members!from_member_id!inner(*), - to_member:a_members!to_member_id!inner(*) + to_member:a_members!to_member_id!inner(*), + created_at `, - { count: 'exact' } + { count: 'planned' } ) - .ilike('token_contract', token); + .eq('token_contract', token); if (from) { // Convert to start of day in ISO format with UTC timezone @@ -72,7 +80,8 @@ export const getTransfersOfToken = async (args: { return queryBuilder .order('created_at', { ascending: false }) .range(offset, offset + PAGE_SIZE - 1) - .limit(PAGE_SIZE); + .limit(PAGE_SIZE) + .returns(); }; export const getTreasuryTransfersOfToken = async (args: { From 73506f690462335cc44c6988c92d9baf50349155 Mon Sep 17 00:00:00 2001 From: Randika Dilshan Date: Thu, 17 Jul 2025 10:55:11 +0530 Subject: [PATCH 3/3] Refactor transfer table components to use TransferWithMembersResponseT --- .env.example | 90 +- .gitignore | 74 +- app/(home)/_components/alias-utils.ts | 118 +- .../_components/create-community-modal.tsx | 570 +- app/(home)/_table/communities-table.tsx | 124 +- app/(home)/action.ts | 308 +- app/(home)/page.tsx | 88 +- app/(home)/user.tsx | 130 +- .../(dashboard)/_components/app-sidebar.tsx | 406 +- .../_components/community-switcher.tsx | 264 +- .../(dashboard)/_components/nav-projects.tsx | 192 +- .../(dashboard)/_components/nav-user.tsx | 324 +- .../admins/_table/admins-client-table.tsx | 118 +- .../admins/_table/admins-table.tsx | 154 +- .../(dashboard)/admins/_table/columns.tsx | 418 +- app/[alias]/(dashboard)/admins/add/actions.ts | 246 +- app/[alias]/(dashboard)/admins/add/page.tsx | 94 +- app/[alias]/(dashboard)/checkout/action.ts | 650 +- .../(dashboard)/checkout/checkout-flow.tsx | 576 +- .../contract/ERC1967Proxy_contract.ts | 84 +- .../checkout/contract/paymaster_contract.ts | 982 +- .../checkout/contract/profile_contract.ts | 1036 +- .../checkout/contract/token_contract.ts | 1834 +- app/[alias]/(dashboard)/checkout/page.tsx | 312 +- .../_components/byoc-fallback.tsx | 84 +- .../_components/create-fallback.tsx | 98 +- .../configuration/_components/fallback.tsx | 108 +- .../configuration/_components/iconUpload.tsx | 210 +- .../(dashboard)/configuration/action.ts | 434 +- .../(dashboard)/configuration/byoc/byoc.tsx | 416 +- .../(dashboard)/configuration/byoc/page.tsx | 60 +- .../configuration/configuration.tsx | 148 +- .../configuration/create/create.tsx | 380 +- .../(dashboard)/configuration/create/page.tsx | 56 +- .../(dashboard)/configuration/page.tsx | 40 +- app/[alias]/(dashboard)/layout.tsx | 184 +- .../(dashboard)/members/[account]/action.ts | 312 +- .../members/[account]/add/page.tsx | 118 +- .../members/[account]/add/profile.tsx | 528 +- .../members/[account]/edit/page.tsx | 182 +- .../members/[account]/edit/profile.tsx | 788 +- .../(dashboard)/members/_table/columns.tsx | 746 +- .../members/_table/members-client-table.tsx | 38 +- .../members/_table/members-table.tsx | 96 +- app/[alias]/(dashboard)/members/page.tsx | 158 +- app/[alias]/(dashboard)/page.tsx | 308 +- .../profile/_components/colorPicker.tsx | 162 +- .../profile/_components/fallback.tsx | 170 +- .../profile/_components/logoUpload.tsx | 210 +- app/[alias]/(dashboard)/profile/action.ts | 150 +- app/[alias]/(dashboard)/profile/page.tsx | 98 +- app/[alias]/(dashboard)/profile/profile.tsx | 594 +- app/[alias]/(dashboard)/roles/RolePage.tsx | 866 +- app/[alias]/(dashboard)/roles/action.ts | 204 +- app/[alias]/(dashboard)/roles/page.tsx | 216 +- app/[alias]/(dashboard)/token/actions.ts | 352 +- app/[alias]/(dashboard)/token/burn/form.tsx | 886 +- app/[alias]/(dashboard)/token/burn/page.tsx | 80 +- app/[alias]/(dashboard)/token/mint/form.tsx | 806 +- app/[alias]/(dashboard)/token/mint/page.tsx | 80 +- .../(dashboard)/transfers/_table/columns.tsx | 394 +- .../_table/transfers-client-table.tsx | 44 +- .../transfers/_table/transfers-table.tsx | 115 +- app/[alias]/(dashboard)/transfers/page.tsx | 148 +- .../treasury/_table/treasury-table.tsx | 236 +- .../(dashboard)/webhooks/edit/[id]/page.tsx | 260 +- app/[alias]/(dashboard)/webhooks/page.tsx | 248 +- app/[alias]/login/email-form.tsx | 316 +- app/[alias]/login/otp-form.tsx | 424 +- app/[alias]/login/page.tsx | 48 +- app/api/communities/route.ts | 42 +- app/onramp/page.tsx | 270 +- auth.config.ts | 350 +- components/ui/progress.tsx | 62 +- helpers/formatting.ts | 30 +- lib/utils.ts | 38 +- middleware.ts | 40 +- next.config.ts | 64 +- package-lock.json | 17546 ++++++++-------- package.json | 138 +- private-key.ts | 62 +- services/chain-db/event.ts | 128 +- services/chain-db/transfers.ts | 252 +- services/pinata/pinata.ts | 144 +- services/storage/index.ts | 102 +- services/top-db/community.ts | 212 +- services/top-db/users.ts | 252 +- state/session/action.ts | 252 +- state/session/state.ts | 114 +- tailwind.config.js | 190 +- 90 files changed, 21044 insertions(+), 21035 deletions(-) diff --git a/.env.example b/.env.example index 1b057c22..a727b71f 100644 --- a/.env.example +++ b/.env.example @@ -1,46 +1,46 @@ -NEXTAUTH_URL=http://localhost:3000 -NEXT_PUBLIC_APP_URL=http://localhost:3000 -AUTH_SECRET= # https://generate-secret.vercel.app/32 - -COMMUNITIES_CONFIG_URL='' - -# Brevo -BREVO_API_KEY= -BREVO_SENDER_EMAIL= -BREVO_SENDER_NAME= - -# Server Account -SERVER_PRIVATE_KEY= -SERVER_ACCOUNT_ADDRESS= - -# Supabase top level -SUPABASE_URL=https://... -SUPABASE_ANON_KEY=... -SUPABASE_SERVICE_ROLE_KEY=... -SUPABASE_DB_PASSWORD= - -# Supabase for chain 100 (Gnosis Chain) -SUPABASE_100_URL=https://... -SUPABASE_100_ANON_KEY=... -SUPABASE_100_SERVICE_ROLE_KEY=... - -# Supabase for chain 137 (Polygon) -SUPABASE_137_URL=https://... -SUPABASE_137_ANON_KEY=... -SUPABASE_137_SERVICE_ROLE_KEY=... - -# Supabase for chain 42220 (Celo) -SUPABASE_42220_URL=https://... -SUPABASE_42220_ANON_KEY=... -SUPABASE_42220_SERVICE_ROLE_KEY=... -SERVER_42220_ACCOUNT_ADDRESS= -SERVER_42220_WALLET_PRIVATE_KEY= - - -# Supabase for chain 8453 (Base) -SUPABASE_8453_URL=https://... -SUPABASE_8453_ANON_KEY=... -SUPABASE_8453_SERVICE_ROLE_KEY=... - -# ONRAMP +NEXTAUTH_URL=http://localhost:3000 +NEXT_PUBLIC_APP_URL=http://localhost:3000 +AUTH_SECRET= # https://generate-secret.vercel.app/32 + +COMMUNITIES_CONFIG_URL='' + +# Brevo +BREVO_API_KEY= +BREVO_SENDER_EMAIL= +BREVO_SENDER_NAME= + +# Server Account +SERVER_PRIVATE_KEY= +SERVER_ACCOUNT_ADDRESS= + +# Supabase top level +SUPABASE_URL=https://... +SUPABASE_ANON_KEY=... +SUPABASE_SERVICE_ROLE_KEY=... +SUPABASE_DB_PASSWORD= + +# Supabase for chain 100 (Gnosis Chain) +SUPABASE_100_URL=https://... +SUPABASE_100_ANON_KEY=... +SUPABASE_100_SERVICE_ROLE_KEY=... + +# Supabase for chain 137 (Polygon) +SUPABASE_137_URL=https://... +SUPABASE_137_ANON_KEY=... +SUPABASE_137_SERVICE_ROLE_KEY=... + +# Supabase for chain 42220 (Celo) +SUPABASE_42220_URL=https://... +SUPABASE_42220_ANON_KEY=... +SUPABASE_42220_SERVICE_ROLE_KEY=... +SERVER_42220_ACCOUNT_ADDRESS= +SERVER_42220_WALLET_PRIVATE_KEY= + + +# Supabase for chain 8453 (Base) +SUPABASE_8453_URL=https://... +SUPABASE_8453_ANON_KEY=... +SUPABASE_8453_SERVICE_ROLE_KEY=... + +# ONRAMP TRANSAK_API_KEY=... \ No newline at end of file diff --git a/.gitignore b/.gitignore index 961cdbcb..f7091ea0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,37 +1,37 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.js - -# testing -/coverage - -# next.js -/.next/ -/out/ - -# production -/build - -# misc -.DS_Store -*.pem - -# debug -npm-debug.log* -yarn-debug.log* -yarn-error.log* -.pnpm-debug.log* - -# env files -.env* -!.env.example - -# vercel -.vercel - -# typescript -*.tsbuildinfo -next-env.d.ts \ No newline at end of file +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# env files +!.env.example + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts +config.bat diff --git a/app/(home)/_components/alias-utils.ts b/app/(home)/_components/alias-utils.ts index abd441f3..2ca37b3b 100644 --- a/app/(home)/_components/alias-utils.ts +++ b/app/(home)/_components/alias-utils.ts @@ -1,59 +1,59 @@ -import { z } from 'zod'; - -export const sanitizeAlias = (alias: string): string => { - return alias - .toLowerCase() - .replace(/[^a-z0-9-]/g, '-') - .replace(/-+/g, '-') - .replace(/^-+|-+$/g, '') - .slice(0, 50); -}; - -export const isValidAlias = (alias: string): boolean => { - // Check if alias is not empty after sanitization - if (!alias || alias.length === 0) { - return false; - } - - // Check if alias contains only lowercase letters, numbers, and hyphens - const validPattern = /^[a-z0-9-]+$/; - if (!validPattern.test(alias)) { - return false; - } - - // Check if alias doesn't start or end with hyphen - if (alias.startsWith('-') || alias.endsWith('-')) { - return false; - } - - // Check if alias doesn't have consecutive hyphens - if (alias.includes('--')) { - return false; - } - - return true; -}; - -export const aliasSchema = z - .string({ - required_error: 'Alias is required' - }) - .min(1, { - message: 'Alias cannot be empty' - }) - .max(50, { - message: 'Alias must be 50 characters or less' - }) - .refine( - (val) => { - const sanitized = sanitizeAlias(val); - return sanitized === val; - }, - { - message: 'Alias must contain only lowercase letters, numbers, and hyphens' - } - ) - .refine((val) => isValidAlias(val), { - message: - 'Alias must be a valid format (no leading/trailing hyphens, no consecutive hyphens)' - }); +import { z } from 'zod'; + +export const sanitizeAlias = (alias: string): string => { + return alias + .toLowerCase() + .replace(/[^a-z0-9-]/g, '-') + .replace(/-+/g, '-') + .replace(/^-+|-+$/g, '') + .slice(0, 50); +}; + +export const isValidAlias = (alias: string): boolean => { + // Check if alias is not empty after sanitization + if (!alias || alias.length === 0) { + return false; + } + + // Check if alias contains only lowercase letters, numbers, and hyphens + const validPattern = /^[a-z0-9-]+$/; + if (!validPattern.test(alias)) { + return false; + } + + // Check if alias doesn't start or end with hyphen + if (alias.startsWith('-') || alias.endsWith('-')) { + return false; + } + + // Check if alias doesn't have consecutive hyphens + if (alias.includes('--')) { + return false; + } + + return true; +}; + +export const aliasSchema = z + .string({ + required_error: 'Alias is required' + }) + .min(1, { + message: 'Alias cannot be empty' + }) + .max(50, { + message: 'Alias must be 50 characters or less' + }) + .refine( + (val) => { + const sanitized = sanitizeAlias(val); + return sanitized === val; + }, + { + message: 'Alias must contain only lowercase letters, numbers, and hyphens' + } + ) + .refine((val) => isValidAlias(val), { + message: + 'Alias must be a valid format (no leading/trailing hyphens, no consecutive hyphens)' + }); diff --git a/app/(home)/_components/create-community-modal.tsx b/app/(home)/_components/create-community-modal.tsx index b4a3054f..2047baf0 100644 --- a/app/(home)/_components/create-community-modal.tsx +++ b/app/(home)/_components/create-community-modal.tsx @@ -1,286 +1,286 @@ -'use client'; - -import { aliasSchema, isValidAlias } from '@/app/(home)/_components/alias-utils'; -import { Button } from '@/components/ui/button'; -import { - Dialog, - DialogContent, - DialogDescription, - DialogFooter, - DialogHeader, - DialogTitle, - DialogTrigger -} from '@/components/ui/dialog'; -import { - Form, - FormControl, - FormDescription, - FormField, - FormItem, - FormLabel, - FormMessage -} from '@/components/ui/form'; -import { Input } from '@/components/ui/input'; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue -} from '@/components/ui/select'; -import { zodResolver } from '@hookform/resolvers/zod'; -import { Plus } from 'lucide-react'; -import Image from 'next/image'; -import { useRouter } from 'next/navigation'; -import { useEffect, useState, useTransition } from 'react'; -import { useForm } from 'react-hook-form'; -import { toast } from 'sonner'; -import { useDebounce } from 'use-debounce'; -import { z } from 'zod'; -import { checkAliasAction, createCommunityAction, generateUniqueSlugAction } from '../action'; - -// Form validation schema -const createCommunityFormSchema = z.object({ - chainId: z.string({ - required_error: 'Please select a Chain' - }).min(1, { - message: 'Please select a Chain' - }), - name: z.string({ - required_error: 'Community name is required' - }).min(1, { - message: 'Community name is required' - }).max(100, { - message: 'Community name must be 100 characters or less' - }), - alias: aliasSchema -}); - -type CreateCommunityFormData = z.infer; - -const chains = [ - { id: '100', name: 'Gnosis', logo: '/chainLogo/Gnosis.png' }, - { id: '42220', name: 'Celo', logo: '/chainLogo/Celo.png' }, - { id: '42161', name: 'Arbitrum', logo: '/chainLogo/Arbitrum.png' }, - { id: '137', name: 'Polygon', logo: '/chainLogo/Polygon.png' } -]; - -export default function CreateCommunityModal() { - const router = useRouter(); - const [isOpen, setIsOpen] = useState(false); - const [isLoading, setIsLoading] = useState(false); - const [isAvailable, setIsAvailable] = useState(false); - const [isGeneratingAlias, startGeneratingAlias] = useTransition(); - const [isCheckingAlias, startCheckingAlias] = useTransition(); - - const form = useForm({ - resolver: zodResolver(createCommunityFormSchema), - defaultValues: { - chainId: '', - name: '', - alias: '' - } - }); - - const onSubmit = async (data: CreateCommunityFormData) => { - setIsLoading(true); - - try { - await createCommunityAction(data.chainId, data.name, data.alias); - setIsOpen(false); - toast.success('Community created successfully', { - onAutoClose: () => { - router.push(`/${data.alias}`); - }, - onDismiss: () => { - router.push(`/${data.alias}`); - } - }); - } catch (error) { - form.setError("root", { - type: "manual", - message: error instanceof Error ? error.message : 'An unexpected error occurred' - }); - } finally { - setIsLoading(false); - } - }; - - const handleOpenChange = (open: boolean) => { - setIsOpen(open); - if (!open) { - form.reset(); - } - }; - - const [debouncedName] = useDebounce(form.watch('name'), 1000); - const [debouncedAlias] = useDebounce(form.watch('alias'), 1000); - - - useEffect(() => { - if (debouncedName) { - startGeneratingAlias(async () => { - try { - const alias = await generateUniqueSlugAction(debouncedName); - form.setValue('alias', alias); - } catch (error) { - console.error('Error generating alias:', error); - } - }); - } - }, [debouncedName, form]); - - - useEffect(() => { - if (debouncedAlias) { - startCheckingAlias(async () => { - try { - if (isValidAlias(debouncedAlias)) { - const isAvailable = await checkAliasAction(debouncedAlias); - if (isAvailable) { - setIsAvailable(false); - form.clearErrors("alias"); - } else { - form.setError("alias", { - type: "manual", - message: "Alias is already taken" - }); - setIsAvailable(true); - } - } else { - form.setError("alias", { - type: "manual", - message: "Invalid alias format. Alias must contain only lowercase letters, numbers, and hyphens." - }); - setIsAvailable(true); - } - } catch (error) { - console.error('Error checking alias:', error); - form.setError("alias", { - type: "manual", - message: error instanceof Error ? error.message : 'Error checking alias availability' - }); - } - }); - } - }, [debouncedAlias, form]); - - return ( - - - - - - - Create New Community - - Create a new community by selecting a blockchain and providing basic information. - - - -
- - ( - - Blockchain - - - - )} - /> - - ( - - Community Name - - - - - - )} - /> - - ( - - - Community Alias - {(isGeneratingAlias || isCheckingAlias) && ( - - {isGeneratingAlias ? 'Generating...' : 'Checking...'} - - )} - - - - - - Alias must contain only lowercase letters, numbers, and hyphens. It will be used in your community URL. - - - - )} - /> - - {form.formState.errors.root && ( -
- {form.formState.errors.root.message} -
- )} - - - - - - - -
-
- ); +'use client'; + +import { aliasSchema, isValidAlias } from '@/app/(home)/_components/alias-utils'; +import { Button } from '@/components/ui/button'; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger +} from '@/components/ui/dialog'; +import { + Form, + FormControl, + FormDescription, + FormField, + FormItem, + FormLabel, + FormMessage +} from '@/components/ui/form'; +import { Input } from '@/components/ui/input'; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue +} from '@/components/ui/select'; +import { zodResolver } from '@hookform/resolvers/zod'; +import { Plus } from 'lucide-react'; +import Image from 'next/image'; +import { useRouter } from 'next/navigation'; +import { useEffect, useState, useTransition } from 'react'; +import { useForm } from 'react-hook-form'; +import { toast } from 'sonner'; +import { useDebounce } from 'use-debounce'; +import { z } from 'zod'; +import { checkAliasAction, createCommunityAction, generateUniqueSlugAction } from '../action'; + +// Form validation schema +const createCommunityFormSchema = z.object({ + chainId: z.string({ + required_error: 'Please select a Chain' + }).min(1, { + message: 'Please select a Chain' + }), + name: z.string({ + required_error: 'Community name is required' + }).min(1, { + message: 'Community name is required' + }).max(100, { + message: 'Community name must be 100 characters or less' + }), + alias: aliasSchema +}); + +type CreateCommunityFormData = z.infer; + +const chains = [ + { id: '100', name: 'Gnosis', logo: '/chainLogo/Gnosis.png' }, + { id: '42220', name: 'Celo', logo: '/chainLogo/Celo.png' }, + { id: '42161', name: 'Arbitrum', logo: '/chainLogo/Arbitrum.png' }, + { id: '137', name: 'Polygon', logo: '/chainLogo/Polygon.png' } +]; + +export default function CreateCommunityModal() { + const router = useRouter(); + const [isOpen, setIsOpen] = useState(false); + const [isLoading, setIsLoading] = useState(false); + const [isAvailable, setIsAvailable] = useState(false); + const [isGeneratingAlias, startGeneratingAlias] = useTransition(); + const [isCheckingAlias, startCheckingAlias] = useTransition(); + + const form = useForm({ + resolver: zodResolver(createCommunityFormSchema), + defaultValues: { + chainId: '', + name: '', + alias: '' + } + }); + + const onSubmit = async (data: CreateCommunityFormData) => { + setIsLoading(true); + + try { + await createCommunityAction(data.chainId, data.name, data.alias); + setIsOpen(false); + toast.success('Community created successfully', { + onAutoClose: () => { + router.push(`/${data.alias}`); + }, + onDismiss: () => { + router.push(`/${data.alias}`); + } + }); + } catch (error) { + form.setError("root", { + type: "manual", + message: error instanceof Error ? error.message : 'An unexpected error occurred' + }); + } finally { + setIsLoading(false); + } + }; + + const handleOpenChange = (open: boolean) => { + setIsOpen(open); + if (!open) { + form.reset(); + } + }; + + const [debouncedName] = useDebounce(form.watch('name'), 1000); + const [debouncedAlias] = useDebounce(form.watch('alias'), 1000); + + + useEffect(() => { + if (debouncedName) { + startGeneratingAlias(async () => { + try { + const alias = await generateUniqueSlugAction(debouncedName); + form.setValue('alias', alias); + } catch (error) { + console.error('Error generating alias:', error); + } + }); + } + }, [debouncedName, form]); + + + useEffect(() => { + if (debouncedAlias) { + startCheckingAlias(async () => { + try { + if (isValidAlias(debouncedAlias)) { + const isAvailable = await checkAliasAction(debouncedAlias); + if (isAvailable) { + setIsAvailable(false); + form.clearErrors("alias"); + } else { + form.setError("alias", { + type: "manual", + message: "Alias is already taken" + }); + setIsAvailable(true); + } + } else { + form.setError("alias", { + type: "manual", + message: "Invalid alias format. Alias must contain only lowercase letters, numbers, and hyphens." + }); + setIsAvailable(true); + } + } catch (error) { + console.error('Error checking alias:', error); + form.setError("alias", { + type: "manual", + message: error instanceof Error ? error.message : 'Error checking alias availability' + }); + } + }); + } + }, [debouncedAlias, form]); + + return ( + + + + + + + Create New Community + + Create a new community by selecting a blockchain and providing basic information. + + + +
+ + ( + + Blockchain + + + + )} + /> + + ( + + Community Name + + + + + + )} + /> + + ( + + + Community Alias + {(isGeneratingAlias || isCheckingAlias) && ( + + {isGeneratingAlias ? 'Generating...' : 'Checking...'} + + )} + + + + + + Alias must contain only lowercase letters, numbers, and hyphens. It will be used in your community URL. + + + + )} + /> + + {form.formState.errors.root && ( +
+ {form.formState.errors.root.message} +
+ )} + + + + + + + +
+
+ ); } \ No newline at end of file diff --git a/app/(home)/_table/communities-table.tsx b/app/(home)/_table/communities-table.tsx index fd6c9d73..03efe0f2 100644 --- a/app/(home)/_table/communities-table.tsx +++ b/app/(home)/_table/communities-table.tsx @@ -1,62 +1,62 @@ -import { DataTable } from '@/components/ui/data-table'; -import { Separator } from '@/components/ui/separator'; -import { getServiceRoleClient } from '@/services/top-db'; -import { getCommunities } from '@/services/top-db/community'; -import { Config } from '@citizenwallet/sdk'; -import { columns } from './columns'; -import CreateCommunityModal from '../_components/create-community-modal'; - -interface CommunitiesTableProps { - query: string; - page: number; -} - -export async function CommunitiesTable({ query, page }: CommunitiesTableProps) { - let communities: Config[] = []; - let total: number = 0; - - try { - - const client = getServiceRoleClient(); - - const { data: datas, count } = await getCommunities(client, query, page); - - if (!datas || datas.length < 1) { - - communities = []; - total = 0; - } else { - communities = datas?.map((data) => data?.json); - total = count ?? 0; - } - - } catch (error) { - console.error(error); - } - - return ( -
-
-
-

Communities

-

Browse communities

-
- -
- -
-
- -
-
- - - -
-

- Total: {total} -

-
-
- ); -} +import { DataTable } from '@/components/ui/data-table'; +import { Separator } from '@/components/ui/separator'; +import { getServiceRoleClient } from '@/services/top-db'; +import { getCommunities } from '@/services/top-db/community'; +import { Config } from '@citizenwallet/sdk'; +import { columns } from './columns'; +import CreateCommunityModal from '../_components/create-community-modal'; + +interface CommunitiesTableProps { + query: string; + page: number; +} + +export async function CommunitiesTable({ query, page }: CommunitiesTableProps) { + let communities: Config[] = []; + let total: number = 0; + + try { + + const client = getServiceRoleClient(); + + const { data: datas, count } = await getCommunities(client, query, page); + + if (!datas || datas.length < 1) { + + communities = []; + total = 0; + } else { + communities = datas?.map((data) => data?.json); + total = count ?? 0; + } + + } catch (error) { + console.error(error); + } + + return ( +
+
+
+

Communities

+

Browse communities

+
+ +
+ +
+
+ +
+
+ + + +
+

+ Total: {total} +

+
+
+ ); +} diff --git a/app/(home)/action.ts b/app/(home)/action.ts index 992c4469..c1c2c888 100644 --- a/app/(home)/action.ts +++ b/app/(home)/action.ts @@ -1,154 +1,154 @@ -'use server'; - -import { generateRandomString } from '@/helpers/formatting'; -import { - sanitizeAlias, - isValidAlias -} from '@/app/(home)/_components/alias-utils'; -import { getServiceRoleClient } from '@/services/top-db'; -import { - createCommunity, - getCommunityByAlias -} from '@/services/top-db/community'; -import { getAuthUserAction } from '../_actions/user-actions'; -import { addUserRowoCommunity } from '@/services/top-db/users'; - -export const generateUniqueSlugAction = async (baseSlug: string) => { - let slug = sanitizeAlias(baseSlug); - - if (!isValidAlias(slug)) { - throw new Error( - 'Invalid alias format. Alias must contain only lowercase letters, numbers, and hyphens.' - ); - } - - let attempts = 0; - const maxAttempts = 5; - - while (attempts < maxAttempts) { - const client = getServiceRoleClient(); - - const { data, error } = await getCommunityByAlias(client, slug); - - if (error && error.code !== 'PGRST116') { - throw new Error('Error checking slug uniqueness'); - } - - if (!data) { - return slug; - } - - // When generating a new slug variant, ensure it remains valid - slug = sanitizeAlias(`${baseSlug}-${generateRandomString(4)}`); - attempts++; - } - - throw new Error('Unable to generate unique slug after max attempts'); -}; - -export const checkAliasAction = async (alias: string) => { - const sanitizedAlias = sanitizeAlias(alias); - - if (!isValidAlias(sanitizedAlias)) { - throw new Error( - 'Invalid alias format. Alias must contain only lowercase letters, numbers, and hyphens.' - ); - } - - const client = getServiceRoleClient(); - - const { data, error } = await getCommunityByAlias(client, sanitizedAlias); - - if (error && error.code !== 'PGRST116') { - throw new Error('Error checking alias availability'); - } - return !data; -}; - -export const createCommunityAction = async ( - chainId: string, - name: string, - alias: string -) => { - const client = getServiceRoleClient(); - - // Generate the community JSON configuration - const communityConfig = { - ipfs: { url: '' }, - scan: { url: '', name: '' }, - cards: {}, - chains: { - [chainId]: { - id: parseInt(chainId), - node: { - url: `https://${chainId}.engine.citizenwallet.xyz`, - ws_url: `wss://${chainId}.engine.citizenwallet.xyz` - } - } - }, - tokens: {}, - plugins: [], - version: 4, - accounts: {}, - sessions: {}, - community: { - url: '', - logo: '', - name: name, - alias: alias, - theme: { primary: '#1f6feb' }, - profile: { - address: '', - chain_id: parseInt(chainId) - }, - description: `The ${name} community`, - primary_token: { - address: '', - chain_id: parseInt(chainId) - }, - primary_card_manager: { - address: '', - chain_id: parseInt(chainId) - }, - primary_account_factory: { - address: '', - chain_id: parseInt(chainId) - }, - primary_session_manager: { - address: '', - chain_id: parseInt(chainId) - } - }, - config_location: '' - }; - - const user = await getAuthUserAction({ chain_id: parseInt(chainId) }); - if (!user) { - throw new Error('User not found'); - } - - const [communityResult] = await Promise.allSettled([ - createCommunity(client, { - chain_id: parseInt(chainId), - alias: alias, - active: false, - created_at: new Date(), - updated_at: new Date(), - json: communityConfig - }), - addUserRowoCommunity({ - client, - data: { - user_id: Number(user.data?.id), - chain_id: parseInt(chainId), - alias: alias, - role: 'owner' - } - }) - ]); - - const data = - communityResult.status === 'fulfilled' ? communityResult.value.data : []; - - return data; -}; +'use server'; + +import { generateRandomString } from '@/helpers/formatting'; +import { + sanitizeAlias, + isValidAlias +} from '@/app/(home)/_components/alias-utils'; +import { getServiceRoleClient } from '@/services/top-db'; +import { + createCommunity, + getCommunityByAlias +} from '@/services/top-db/community'; +import { getAuthUserAction } from '../_actions/user-actions'; +import { addUserRowoCommunity } from '@/services/top-db/users'; + +export const generateUniqueSlugAction = async (baseSlug: string) => { + let slug = sanitizeAlias(baseSlug); + + if (!isValidAlias(slug)) { + throw new Error( + 'Invalid alias format. Alias must contain only lowercase letters, numbers, and hyphens.' + ); + } + + let attempts = 0; + const maxAttempts = 5; + + while (attempts < maxAttempts) { + const client = getServiceRoleClient(); + + const { data, error } = await getCommunityByAlias(client, slug); + + if (error && error.code !== 'PGRST116') { + throw new Error('Error checking slug uniqueness'); + } + + if (!data) { + return slug; + } + + // When generating a new slug variant, ensure it remains valid + slug = sanitizeAlias(`${baseSlug}-${generateRandomString(4)}`); + attempts++; + } + + throw new Error('Unable to generate unique slug after max attempts'); +}; + +export const checkAliasAction = async (alias: string) => { + const sanitizedAlias = sanitizeAlias(alias); + + if (!isValidAlias(sanitizedAlias)) { + throw new Error( + 'Invalid alias format. Alias must contain only lowercase letters, numbers, and hyphens.' + ); + } + + const client = getServiceRoleClient(); + + const { data, error } = await getCommunityByAlias(client, sanitizedAlias); + + if (error && error.code !== 'PGRST116') { + throw new Error('Error checking alias availability'); + } + return !data; +}; + +export const createCommunityAction = async ( + chainId: string, + name: string, + alias: string +) => { + const client = getServiceRoleClient(); + + // Generate the community JSON configuration + const communityConfig = { + ipfs: { url: '' }, + scan: { url: '', name: '' }, + cards: {}, + chains: { + [chainId]: { + id: parseInt(chainId), + node: { + url: `https://${chainId}.engine.citizenwallet.xyz`, + ws_url: `wss://${chainId}.engine.citizenwallet.xyz` + } + } + }, + tokens: {}, + plugins: [], + version: 4, + accounts: {}, + sessions: {}, + community: { + url: '', + logo: '', + name: name, + alias: alias, + theme: { primary: '#1f6feb' }, + profile: { + address: '', + chain_id: parseInt(chainId) + }, + description: `The ${name} community`, + primary_token: { + address: '', + chain_id: parseInt(chainId) + }, + primary_card_manager: { + address: '', + chain_id: parseInt(chainId) + }, + primary_account_factory: { + address: '', + chain_id: parseInt(chainId) + }, + primary_session_manager: { + address: '', + chain_id: parseInt(chainId) + } + }, + config_location: '' + }; + + const user = await getAuthUserAction({ chain_id: parseInt(chainId) }); + if (!user) { + throw new Error('User not found'); + } + + const [communityResult] = await Promise.allSettled([ + createCommunity(client, { + chain_id: parseInt(chainId), + alias: alias, + active: false, + created_at: new Date(), + updated_at: new Date(), + json: communityConfig + }), + addUserRowoCommunity({ + client, + data: { + user_id: Number(user.data?.id), + chain_id: parseInt(chainId), + alias: alias, + role: 'owner' + } + }) + ]); + + const data = + communityResult.status === 'fulfilled' ? communityResult.value.data : []; + + return data; +}; diff --git a/app/(home)/page.tsx b/app/(home)/page.tsx index f28e993b..ccf5ab8d 100644 --- a/app/(home)/page.tsx +++ b/app/(home)/page.tsx @@ -1,44 +1,44 @@ -import { Suspense } from 'react'; -import { skeletonColumns } from './_table/columns'; -import { DataTable } from '@/components/ui/data-table'; -import { CommunitiesTable } from './_table/communities-table'; -import { placeholderData } from './_table/columns'; -import { Button } from '@/components/ui/button'; -import { Plus } from 'lucide-react'; - - -export default async function Page(props: { - searchParams: Promise<{ query?: string; page?: string }>; -}) { - const { query: queryParam, page: pageParam } = await props.searchParams; - const query = queryParam || ''; - const page = pageParam || '1'; - - return ( - }> - - - ); -} - -function Fallback() { - return ( -
-
-
-

Communities

-
- -
- -
-
- -
-
-
- ); -} +import { Suspense } from 'react'; +import { skeletonColumns } from './_table/columns'; +import { DataTable } from '@/components/ui/data-table'; +import { CommunitiesTable } from './_table/communities-table'; +import { placeholderData } from './_table/columns'; +import { Button } from '@/components/ui/button'; +import { Plus } from 'lucide-react'; + + +export default async function Page(props: { + searchParams: Promise<{ query?: string; page?: string }>; +}) { + const { query: queryParam, page: pageParam } = await props.searchParams; + const query = queryParam || ''; + const page = pageParam || '1'; + + return ( + }> + + + ); +} + +function Fallback() { + return ( +
+
+
+

Communities

+
+ +
+ +
+
+ +
+
+
+ ); +} diff --git a/app/(home)/user.tsx b/app/(home)/user.tsx index bf5771ec..e4aad96f 100644 --- a/app/(home)/user.tsx +++ b/app/(home)/user.tsx @@ -1,65 +1,65 @@ -'use client'; - -import { Button } from '@/components/ui/button'; -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuTrigger -} from '@/components/ui/dropdown-menu'; -import { signOutAction } from '@/app/_actions/user-actions'; -import { UserRow } from '@/services/top-db/users'; -import { Avatar, AvatarImage, AvatarFallback } from '@radix-ui/react-avatar'; - -interface UserProps { - user: UserRow | null; -} - -export default function User(props: UserProps) { - const { user } = props; - - const getInitials = (name?: string) => { - if (!name) return 'U'; - const nameParts = name.split(' '); - if (nameParts.length >= 2) { - return `${nameParts[0][0]}${nameParts[1][0]}`.toUpperCase(); - } - return name.slice(0, 2).toUpperCase(); - }; - - return ( - - - - - - -
{ - await signOutAction(); - }} - > - -
-
-
-
- ); -} +'use client'; + +import { Button } from '@/components/ui/button'; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger +} from '@/components/ui/dropdown-menu'; +import { signOutAction } from '@/app/_actions/user-actions'; +import { UserRow } from '@/services/top-db/users'; +import { Avatar, AvatarImage, AvatarFallback } from '@radix-ui/react-avatar'; + +interface UserProps { + user: UserRow | null; +} + +export default function User(props: UserProps) { + const { user } = props; + + const getInitials = (name?: string) => { + if (!name) return 'U'; + const nameParts = name.split(' '); + if (nameParts.length >= 2) { + return `${nameParts[0][0]}${nameParts[1][0]}`.toUpperCase(); + } + return name.slice(0, 2).toUpperCase(); + }; + + return ( + + + + + + +
{ + await signOutAction(); + }} + > + +
+
+
+
+ ); +} diff --git a/app/[alias]/(dashboard)/_components/app-sidebar.tsx b/app/[alias]/(dashboard)/_components/app-sidebar.tsx index 622c7d1e..47b302d0 100644 --- a/app/[alias]/(dashboard)/_components/app-sidebar.tsx +++ b/app/[alias]/(dashboard)/_components/app-sidebar.tsx @@ -1,203 +1,203 @@ -'use client'; - -import { - Sidebar, - SidebarContent, - SidebarFooter, - SidebarHeader, - SidebarMenuButton, - SidebarRail -} from '@/components/ui/sidebar'; -import { isEmpty } from '@/lib/utils'; -import { UserRow } from '@/services/top-db/users'; -import { Config } from '@citizenwallet/sdk'; -import { - ArrowLeft, - CircleCheck, - CircleDashed, - Hammer, - Home, - Landmark, - List, - LucideLineChart, - PlusIcon, - Settings, - Shield, - University, - Users, - Webhook, - Wrench -} from 'lucide-react'; -import Link from 'next/link'; -import type * as React from 'react'; -import { CommunitySwitcher } from './community-switcher'; -import { NavProjects } from './nav-projects'; -import { NavUser } from './nav-user'; -import { Button } from '@/components/ui/button'; -import Image from 'next/image'; - -interface AppSidebarProps extends React.ComponentProps { - communities: Config[]; - config: Config; - active: boolean; - user: UserRow | null; - hasAccess: boolean; -} - -export function AppSidebar({ - communities, - config, - active, - user, - hasAccess, - ...props -}: AppSidebarProps) { - const profileActive = - !isEmpty(config.community.logo) && !isEmpty(config.community.url); - const currencyActive = - !isEmpty(config.community.primary_token.address) && - !isEmpty(config.community.profile.address); - - const data = { - user: { - name: user?.name ?? '', - email: user?.email ?? '', - avatar: user?.avatar ?? '' - }, - projects: - active === false - ? [ - { - name: 'Profile', - url: `/${config?.community.alias}/profile`, - icon: University, - nextIcon: profileActive ? CircleCheck : CircleDashed - }, - { - name: 'Currency', - url: `/${config?.community.alias}/configuration`, - icon: Settings, - nextIcon: currencyActive ? CircleCheck : CircleDashed - }, - { - name: 'Admins', - url: `/${config?.community.alias}/admins`, - icon: Shield - } - ] - : [ - { - name: 'Overview', - url: `/${config?.community.alias}`, - icon: Home - }, - { - name: 'Members', - url: `/${config?.community.alias}/members`, - icon: Users - }, - { - name: 'Transfers', - url: `/${config?.community.alias}/transfers`, - icon: LucideLineChart - }, - { - name: 'Treasury', - url: `/${config?.community.alias}/treasury`, - icon: Landmark, - items: [ - { - name: 'History', - url: `/${config?.community.alias}/treasury`, - icon: List - }, - { - name: 'Minters', - url: `/${config?.community.alias}/roles`, - icon: Hammer - } - ] - }, - { - name: 'Profile', - url: `/${config?.community.alias}/profile`, - icon: University - }, - { - name: 'Currency', - url: `/${config?.community.alias}/configuration`, - icon: Settings - }, - { - name: 'Admins', - url: `/${config?.community.alias}/admins`, - icon: Shield - }, - { - name: 'Developer', - url: `/${config?.community.alias}`, - icon: Wrench, - items: [ - { - name: 'Webhooks', - url: `/${config?.community.alias}/webhooks`, - icon: Webhook - } - ] - } - ] - }; - - return ( - - - - - - - project.name == 'Overview') - } - /> - - -
- CTZN -

0

- -
- -
- -
- ); -} - -function BackToAllCommunities() { - const handleClick = () => { - document.cookie = `lastViewedAlias=; path=/; max-age=0`; - }; - - return ( - - - - Home - - - ); -} +'use client'; + +import { + Sidebar, + SidebarContent, + SidebarFooter, + SidebarHeader, + SidebarMenuButton, + SidebarRail +} from '@/components/ui/sidebar'; +import { isEmpty } from '@/lib/utils'; +import { UserRow } from '@/services/top-db/users'; +import { Config } from '@citizenwallet/sdk'; +import { + ArrowLeft, + CircleCheck, + CircleDashed, + Hammer, + Home, + Landmark, + List, + LucideLineChart, + PlusIcon, + Settings, + Shield, + University, + Users, + Webhook, + Wrench +} from 'lucide-react'; +import Link from 'next/link'; +import type * as React from 'react'; +import { CommunitySwitcher } from './community-switcher'; +import { NavProjects } from './nav-projects'; +import { NavUser } from './nav-user'; +import { Button } from '@/components/ui/button'; +import Image from 'next/image'; + +interface AppSidebarProps extends React.ComponentProps { + communities: Config[]; + config: Config; + active: boolean; + user: UserRow | null; + hasAccess: boolean; +} + +export function AppSidebar({ + communities, + config, + active, + user, + hasAccess, + ...props +}: AppSidebarProps) { + const profileActive = + !isEmpty(config.community.logo) && !isEmpty(config.community.url); + const currencyActive = + !isEmpty(config.community.primary_token.address) && + !isEmpty(config.community.profile.address); + + const data = { + user: { + name: user?.name ?? '', + email: user?.email ?? '', + avatar: user?.avatar ?? '' + }, + projects: + active === false + ? [ + { + name: 'Profile', + url: `/${config?.community.alias}/profile`, + icon: University, + nextIcon: profileActive ? CircleCheck : CircleDashed + }, + { + name: 'Currency', + url: `/${config?.community.alias}/configuration`, + icon: Settings, + nextIcon: currencyActive ? CircleCheck : CircleDashed + }, + { + name: 'Admins', + url: `/${config?.community.alias}/admins`, + icon: Shield + } + ] + : [ + { + name: 'Overview', + url: `/${config?.community.alias}`, + icon: Home + }, + { + name: 'Members', + url: `/${config?.community.alias}/members`, + icon: Users + }, + { + name: 'Transfers', + url: `/${config?.community.alias}/transfers`, + icon: LucideLineChart + }, + { + name: 'Treasury', + url: `/${config?.community.alias}/treasury`, + icon: Landmark, + items: [ + { + name: 'History', + url: `/${config?.community.alias}/treasury`, + icon: List + }, + { + name: 'Minters', + url: `/${config?.community.alias}/roles`, + icon: Hammer + } + ] + }, + { + name: 'Profile', + url: `/${config?.community.alias}/profile`, + icon: University + }, + { + name: 'Currency', + url: `/${config?.community.alias}/configuration`, + icon: Settings + }, + { + name: 'Admins', + url: `/${config?.community.alias}/admins`, + icon: Shield + }, + { + name: 'Developer', + url: `/${config?.community.alias}`, + icon: Wrench, + items: [ + { + name: 'Webhooks', + url: `/${config?.community.alias}/webhooks`, + icon: Webhook + } + ] + } + ] + }; + + return ( + + + + + + + project.name == 'Overview') + } + /> + + +
+ CTZN +

0

+ +
+ +
+ +
+ ); +} + +function BackToAllCommunities() { + const handleClick = () => { + document.cookie = `lastViewedAlias=; path=/; max-age=0`; + }; + + return ( + + + + Home + + + ); +} diff --git a/app/[alias]/(dashboard)/_components/community-switcher.tsx b/app/[alias]/(dashboard)/_components/community-switcher.tsx index b547c337..a543b538 100644 --- a/app/[alias]/(dashboard)/_components/community-switcher.tsx +++ b/app/[alias]/(dashboard)/_components/community-switcher.tsx @@ -1,132 +1,132 @@ -'use client'; - -import { CommunityLogo } from '@/components/icons'; -import { Badge } from '@/components/ui/badge'; -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuLabel, - DropdownMenuTrigger -} from '@/components/ui/dropdown-menu'; -import { - SidebarMenu, - SidebarMenuButton, - SidebarMenuItem, - useSidebar -} from '@/components/ui/sidebar'; -import { CommunityConfig, Config, ConfigToken } from '@citizenwallet/sdk'; -import { ChevronsUpDown } from 'lucide-react'; -import { useRouter } from 'next/navigation'; -import { useState } from 'react'; - -export function CommunitySwitcher({ - communities, - selectedCommunity, - active -}: { - communities: Config[]; - selectedCommunity?: Config; - active?: boolean; -}) { - const { isMobile } = useSidebar(); - const [activeCommunity, setActiveCommunity] = useState(selectedCommunity); - const router = useRouter(); - - if (!activeCommunity) { - return null; - } - - - const communityConfig = new CommunityConfig(activeCommunity); - - - const primaryToken: ConfigToken = communityConfig.primaryToken; - const logo: string = communityConfig.community.logo; - - - - return ( - - - - - -
- -
-
- - {activeCommunity.community.name} - - - {activeCommunity.community.alias} - -
- {active ? ( - - Public - - ) : ( - Inactive - )} - -
- -
- - - Communities - - {communities.map((community) => { - const communityConfig = new CommunityConfig(community); - const alias = communityConfig.community.alias; - const primaryToken = communityConfig.primaryToken; - const logo = communityConfig.community.logo; - - const onSelectCommunity = () => { - document.cookie = `lastViewedAlias=${alias}; path=/; max-age=31536000`; - setActiveCommunity(community); - router.push(`/${alias}`); - }; - - return ( - -
- -
- {community.community.name} -
- ); - })} - {/* */} - {/* -
- -
-
Add team
-
*/} -
-
-
-
- ); -} +'use client'; + +import { CommunityLogo } from '@/components/icons'; +import { Badge } from '@/components/ui/badge'; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuTrigger +} from '@/components/ui/dropdown-menu'; +import { + SidebarMenu, + SidebarMenuButton, + SidebarMenuItem, + useSidebar +} from '@/components/ui/sidebar'; +import { CommunityConfig, Config, ConfigToken } from '@citizenwallet/sdk'; +import { ChevronsUpDown } from 'lucide-react'; +import { useRouter } from 'next/navigation'; +import { useState } from 'react'; + +export function CommunitySwitcher({ + communities, + selectedCommunity, + active +}: { + communities: Config[]; + selectedCommunity?: Config; + active?: boolean; +}) { + const { isMobile } = useSidebar(); + const [activeCommunity, setActiveCommunity] = useState(selectedCommunity); + const router = useRouter(); + + if (!activeCommunity) { + return null; + } + + + const communityConfig = new CommunityConfig(activeCommunity); + + + const primaryToken: ConfigToken = communityConfig.primaryToken; + const logo: string = communityConfig.community.logo; + + + + return ( + + + + + +
+ +
+
+ + {activeCommunity.community.name} + + + {activeCommunity.community.alias} + +
+ {active ? ( + + Public + + ) : ( + Inactive + )} + +
+ +
+ + + Communities + + {communities.map((community) => { + const communityConfig = new CommunityConfig(community); + const alias = communityConfig.community.alias; + const primaryToken = communityConfig.primaryToken; + const logo = communityConfig.community.logo; + + const onSelectCommunity = () => { + document.cookie = `lastViewedAlias=${alias}; path=/; max-age=31536000`; + setActiveCommunity(community); + router.push(`/${alias}`); + }; + + return ( + +
+ +
+ {community.community.name} +
+ ); + })} + {/* */} + {/* +
+ +
+
Add team
+
*/} +
+
+
+
+ ); +} diff --git a/app/[alias]/(dashboard)/_components/nav-projects.tsx b/app/[alias]/(dashboard)/_components/nav-projects.tsx index 58f77792..a4b6dbe2 100644 --- a/app/[alias]/(dashboard)/_components/nav-projects.tsx +++ b/app/[alias]/(dashboard)/_components/nav-projects.tsx @@ -1,97 +1,97 @@ -'use client'; - -import { - Collapsible, - CollapsibleContent, - CollapsibleTrigger, -} from "@/components/ui/collapsible"; -import { - SidebarGroup, - SidebarMenu, - SidebarMenuButton, - SidebarMenuItem, - SidebarMenuSub, - SidebarMenuSubButton, - SidebarMenuSubItem -} from '@/components/ui/sidebar'; -import { ChevronRight, CircleCheck, type LucideIcon } from 'lucide-react'; -import Link from 'next/link'; - -export function NavProjects({ - projects -}: { - projects: { - nextIcon?: LucideIcon; - name: string; - url: string; - icon: LucideIcon; - items?: { - name: string; - url: string; - icon: LucideIcon; - }[]; - }[]; -}) { - return ( - - - - {projects.map((item) => ( - - - {item.items && item.items.length > 0 ? ( - - - - - {item.icon && } - {item.name} - - - - - - {item.items?.map((subItem) => ( - - - - - {subItem.name} - - - - ))} - - - - - ) : ( - - - - - - {item.name} - {item.nextIcon && -
- -
- } - -
-
- - )} - -
- ))} - - -
-
- ); +'use client'; + +import { + Collapsible, + CollapsibleContent, + CollapsibleTrigger, +} from "@/components/ui/collapsible"; +import { + SidebarGroup, + SidebarMenu, + SidebarMenuButton, + SidebarMenuItem, + SidebarMenuSub, + SidebarMenuSubButton, + SidebarMenuSubItem +} from '@/components/ui/sidebar'; +import { ChevronRight, CircleCheck, type LucideIcon } from 'lucide-react'; +import Link from 'next/link'; + +export function NavProjects({ + projects +}: { + projects: { + nextIcon?: LucideIcon; + name: string; + url: string; + icon: LucideIcon; + items?: { + name: string; + url: string; + icon: LucideIcon; + }[]; + }[]; +}) { + return ( + + + + {projects.map((item) => ( + + + {item.items && item.items.length > 0 ? ( + + + + + {item.icon && } + {item.name} + + + + + + {item.items?.map((subItem) => ( + + + + + {subItem.name} + + + + ))} + + + + + ) : ( + + + + + + {item.name} + {item.nextIcon && +
+ +
+ } + +
+
+ + )} + +
+ ))} + + +
+
+ ); } \ No newline at end of file diff --git a/app/[alias]/(dashboard)/_components/nav-user.tsx b/app/[alias]/(dashboard)/_components/nav-user.tsx index fe651652..387bd758 100644 --- a/app/[alias]/(dashboard)/_components/nav-user.tsx +++ b/app/[alias]/(dashboard)/_components/nav-user.tsx @@ -1,162 +1,162 @@ -'use client'; - -import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuLabel, - DropdownMenuSeparator, - DropdownMenuTrigger -} from '@/components/ui/dropdown-menu'; -import { - SidebarMenu, - SidebarMenuButton, - SidebarMenuItem, - useSidebar -} from '@/components/ui/sidebar'; -import { StorageService } from '@/services/storage'; -import { CommunityConfig, Config, revokeSession } from '@citizenwallet/sdk'; -import { Wallet } from 'ethers'; -import { ChevronsUpDown, LogOut } from 'lucide-react'; -import { useSession as useNextAuthSession } from 'next-auth/react'; -import { useRouter } from 'next/navigation'; -import { toast } from 'sonner'; -import { useSession } from 'state/session/action'; - -export function NavUser({ - user, - config -}: { - user: { - name: string; - email: string; - avatar: string; - }; - config?: Config; -}) { - const { isMobile } = useSidebar(); - const { data: session, update } = useNextAuthSession(); - const router = useRouter(); - - const [, sessionActions] = useSession(config as Config); - - const removeSession = async () => { - try { - if (!config) { - return; - } - - const privateKey = sessionActions.storage.getKey('session_private_key'); - const account = await sessionActions.getAccountAddress(); - const communityConfig = new CommunityConfig(config); - const storageService = new StorageService(config.community.alias); - - if (!privateKey || !account) { - return; - } - - const signer = new Wallet(privateKey); - - const tx = await revokeSession({ - community: communityConfig, - signer, - account - }); - - if (!tx) { - toast.error('Signout failed'); - return; - } - sessionActions.clear(); - storageService.deleteKey('session_private_key'); - storageService.deleteKey('session_source_type'); - storageService.deleteKey('session_source_value'); - storageService.deleteKey('session_hash'); - - const removeChainIds = config?.community.profile.chain_id; - const updateChainIds = session?.user.chainIds?.filter( - (chainId: number) => chainId !== removeChainIds - ); - - //remove chainId from session - await update({ - chainIds: updateChainIds - }); - - toast.success('Signout successful'); - } catch (error) { - console.error(error); - toast.error('Signout failed'); - } finally { - router.push('/'); - } - }; - - return ( - - - - - - - - - {user.name.slice(0, 2)} - - -
- {user.name} - {user.email} -
- -
-
- - -
- - - - {user.name.slice(0, 2)} - - -
- {user.name} - {user.email} -
-
-
- - - - - -
-
-
-
- ); -} +'use client'; + +import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger +} from '@/components/ui/dropdown-menu'; +import { + SidebarMenu, + SidebarMenuButton, + SidebarMenuItem, + useSidebar +} from '@/components/ui/sidebar'; +import { StorageService } from '@/services/storage'; +import { CommunityConfig, Config, revokeSession } from '@citizenwallet/sdk'; +import { Wallet } from 'ethers'; +import { ChevronsUpDown, LogOut } from 'lucide-react'; +import { useSession as useNextAuthSession } from 'next-auth/react'; +import { useRouter } from 'next/navigation'; +import { toast } from 'sonner'; +import { useSession } from 'state/session/action'; + +export function NavUser({ + user, + config +}: { + user: { + name: string; + email: string; + avatar: string; + }; + config?: Config; +}) { + const { isMobile } = useSidebar(); + const { data: session, update } = useNextAuthSession(); + const router = useRouter(); + + const [, sessionActions] = useSession(config as Config); + + const removeSession = async () => { + try { + if (!config) { + return; + } + + const privateKey = sessionActions.storage.getKey('session_private_key'); + const account = await sessionActions.getAccountAddress(); + const communityConfig = new CommunityConfig(config); + const storageService = new StorageService(config.community.alias); + + if (!privateKey || !account) { + return; + } + + const signer = new Wallet(privateKey); + + const tx = await revokeSession({ + community: communityConfig, + signer, + account + }); + + if (!tx) { + toast.error('Signout failed'); + return; + } + sessionActions.clear(); + storageService.deleteKey('session_private_key'); + storageService.deleteKey('session_source_type'); + storageService.deleteKey('session_source_value'); + storageService.deleteKey('session_hash'); + + const removeChainIds = config?.community.profile.chain_id; + const updateChainIds = session?.user.chainIds?.filter( + (chainId: number) => chainId !== removeChainIds + ); + + //remove chainId from session + await update({ + chainIds: updateChainIds + }); + + toast.success('Signout successful'); + } catch (error) { + console.error(error); + toast.error('Signout failed'); + } finally { + router.push('/'); + } + }; + + return ( + + + + + + + + + {user.name.slice(0, 2)} + + +
+ {user.name} + {user.email} +
+ +
+
+ + +
+ + + + {user.name.slice(0, 2)} + + +
+ {user.name} + {user.email} +
+
+
+ + + + + +
+
+
+
+ ); +} diff --git a/app/[alias]/(dashboard)/admins/_table/admins-client-table.tsx b/app/[alias]/(dashboard)/admins/_table/admins-client-table.tsx index 893d75ea..3ddd33b1 100644 --- a/app/[alias]/(dashboard)/admins/_table/admins-client-table.tsx +++ b/app/[alias]/(dashboard)/admins/_table/admins-client-table.tsx @@ -1,59 +1,59 @@ -'use client'; - -import { DataTable } from '@/components/ui/data-table'; -import { - UserRow, - UserCommunityAccessT, - CommunityAccessRoleT -} from '@/services/top-db/users'; - -import { createColumns } from './columns'; -import { useOptimistic, useTransition } from 'react'; -import { removeUserFromCommunityAction } from '@/app/[alias]/(dashboard)/admins/action'; - -interface AdminsClientTableProps { - data: (UserCommunityAccessT & { user: UserRow })[]; - communityRole?: CommunityAccessRoleT; - alias: string; -} - -export function AdminsClientTable({ - data, - alias, - communityRole -}: AdminsClientTableProps) { - const [isPending, startTransition] = useTransition(); - const [optimisticAdmins, addOptimisticRemoval] = useOptimistic( - data, - (state, adminIdToRemove: number) => - state.filter((admin) => admin.user_id !== adminIdToRemove) - ); - - const handleRemoveAdmin = async (args: { userId: number }) => { - const { userId } = args; - - startTransition(async () => { - // Optimistically remove the admin from the UI - addOptimisticRemoval(userId); - - try { - await removeUserFromCommunityAction({ - userIdToRemove: userId, - alias: alias - }); - } catch (error) { - // If the removal fails, the state will automatically revert - console.error('Failed to remove admin:', error); - } - }); - }; - - const columns = createColumns({ - communityRole: communityRole, - alias: alias, - onRemoveAdmin: handleRemoveAdmin, - isPending: isPending - }); - - return ; -} +'use client'; + +import { DataTable } from '@/components/ui/data-table'; +import { + UserRow, + UserCommunityAccessT, + CommunityAccessRoleT +} from '@/services/top-db/users'; + +import { createColumns } from './columns'; +import { useOptimistic, useTransition } from 'react'; +import { removeUserFromCommunityAction } from '@/app/[alias]/(dashboard)/admins/action'; + +interface AdminsClientTableProps { + data: (UserCommunityAccessT & { user: UserRow })[]; + communityRole?: CommunityAccessRoleT; + alias: string; +} + +export function AdminsClientTable({ + data, + alias, + communityRole +}: AdminsClientTableProps) { + const [isPending, startTransition] = useTransition(); + const [optimisticAdmins, addOptimisticRemoval] = useOptimistic( + data, + (state, adminIdToRemove: number) => + state.filter((admin) => admin.user_id !== adminIdToRemove) + ); + + const handleRemoveAdmin = async (args: { userId: number }) => { + const { userId } = args; + + startTransition(async () => { + // Optimistically remove the admin from the UI + addOptimisticRemoval(userId); + + try { + await removeUserFromCommunityAction({ + userIdToRemove: userId, + alias: alias + }); + } catch (error) { + // If the removal fails, the state will automatically revert + console.error('Failed to remove admin:', error); + } + }); + }; + + const columns = createColumns({ + communityRole: communityRole, + alias: alias, + onRemoveAdmin: handleRemoveAdmin, + isPending: isPending + }); + + return ; +} diff --git a/app/[alias]/(dashboard)/admins/_table/admins-table.tsx b/app/[alias]/(dashboard)/admins/_table/admins-table.tsx index 145d8398..606fccbb 100644 --- a/app/[alias]/(dashboard)/admins/_table/admins-table.tsx +++ b/app/[alias]/(dashboard)/admins/_table/admins-table.tsx @@ -1,77 +1,77 @@ -import AddAdmin from '@/app/[alias]/(dashboard)/admins/_components/add-admin'; -import { getUsersOfCommunityAction } from '@/app/[alias]/(dashboard)/admins/action'; -import { getAuthUserRoleInCommunityAction } from '@/app/_actions/user-actions'; -import UrlPagination from '@/components/custom/pagination-via-url'; -import { Separator } from '@/components/ui/separator'; -import { getServiceRoleClient } from '@/services/top-db'; -import { getCommunityByAlias } from '@/services/top-db/community'; -import { AdminsClientTable } from './admins-client-table'; - -interface AdminsTableProps { - alias: string; -} - -export default async function AdminsTable({ alias }: AdminsTableProps) { - const client = getServiceRoleClient(); - const { data: communityData, error: communityError } = await getCommunityByAlias(client, alias); - - if (communityError || !communityData) { - throw new Error('Failed to get community by alias'); - } - - const config = communityData.json; - const [usersResult, roleResult] = await Promise.allSettled([ - getUsersOfCommunityAction({ - alias - }), - getAuthUserRoleInCommunityAction({ - alias - }) - ]); - - const data = usersResult.status === 'fulfilled' ? usersResult.value.data : []; - - const totalCount = - usersResult.status === 'fulfilled' ? usersResult.value.count : 0; - - const communityRole = - roleResult.status === 'fulfilled' ? roleResult.value : undefined; - - const totalPages = 1; - - return ( -
-
-
-

Admins

-

{config.community.name}

-
- - {communityRole === 'owner' && ( -
- -
- )} -
- -
-
- -
-
- - - -
-

- Total: {totalCount} -

- -
-
- ); -} +import AddAdmin from '@/app/[alias]/(dashboard)/admins/_components/add-admin'; +import { getUsersOfCommunityAction } from '@/app/[alias]/(dashboard)/admins/action'; +import { getAuthUserRoleInCommunityAction } from '@/app/_actions/user-actions'; +import UrlPagination from '@/components/custom/pagination-via-url'; +import { Separator } from '@/components/ui/separator'; +import { getServiceRoleClient } from '@/services/top-db'; +import { getCommunityByAlias } from '@/services/top-db/community'; +import { AdminsClientTable } from './admins-client-table'; + +interface AdminsTableProps { + alias: string; +} + +export default async function AdminsTable({ alias }: AdminsTableProps) { + const client = getServiceRoleClient(); + const { data: communityData, error: communityError } = await getCommunityByAlias(client, alias); + + if (communityError || !communityData) { + throw new Error('Failed to get community by alias'); + } + + const config = communityData.json; + const [usersResult, roleResult] = await Promise.allSettled([ + getUsersOfCommunityAction({ + alias + }), + getAuthUserRoleInCommunityAction({ + alias + }) + ]); + + const data = usersResult.status === 'fulfilled' ? usersResult.value.data : []; + + const totalCount = + usersResult.status === 'fulfilled' ? usersResult.value.count : 0; + + const communityRole = + roleResult.status === 'fulfilled' ? roleResult.value : undefined; + + const totalPages = 1; + + return ( +
+
+
+

Admins

+

{config.community.name}

+
+ + {communityRole === 'owner' && ( +
+ +
+ )} +
+ +
+
+ +
+
+ + + +
+

+ Total: {totalCount} +

+ +
+
+ ); +} diff --git a/app/[alias]/(dashboard)/admins/_table/columns.tsx b/app/[alias]/(dashboard)/admins/_table/columns.tsx index 90929052..5b4f99ad 100644 --- a/app/[alias]/(dashboard)/admins/_table/columns.tsx +++ b/app/[alias]/(dashboard)/admins/_table/columns.tsx @@ -1,209 +1,209 @@ -'use client'; -import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; - -import { - UserRow, - UserCommunityAccessT, - CommunityAccessRoleT -} from '@/services/top-db/users'; -import { ColumnDef } from '@tanstack/react-table'; -import { Skeleton } from '@/components/ui/skeleton'; -import { cn } from '@/lib/utils'; -import { Button } from '@/components/ui/button'; -import { Trash2 } from 'lucide-react'; -import { - Dialog, - DialogClose, - DialogContent, - DialogDescription, - DialogFooter, - DialogHeader, - DialogTitle -} from '@/components/ui/dialog'; -import { useState } from 'react'; -import { toast } from 'sonner'; - -interface CreateColumnsProps { - communityRole?: CommunityAccessRoleT; - alias: string; - onRemoveAdmin: (args: { userId: number }) => Promise; - isPending: boolean; -} - -export const createColumns = ( - props: CreateColumnsProps -): ColumnDef[] => { - const baseColumns: ColumnDef[] = [ - { - header: 'Member', - cell: ({ row }) => { - const { user } = row.original; - const { avatar, name, email } = user; - return ( -
- - - {name?.slice(0, 2) ?? ''} - -
- {name} - {email} -
-
- ); - } - }, - { - header: 'Role', - accessorKey: 'role', - cell: ({ row }) => { - const role = row.original.role; - return ( -
- - {role} - -
- ); - } - }, - { - header: 'Created at', - accessorKey: 'created_at', - cell: ({ row }) => { - const createdAt = new Date(row.original.created_at); - return ( -
- - {createdAt.toLocaleString()} - -
- ); - } - } - ]; - - const ownerColumns: ColumnDef[] = [ - { - id: 'remove', - cell: function RemoveCell({ row }) { - const [isDialogOpen, setIsDialogOpen] = useState(false); - - const { - user_id, - user: { name } - } = row.original; - - const handleOpenDialog = () => { - setIsDialogOpen(true); - }; - - const handleCloseDialog = () => { - setIsDialogOpen(false); - }; - - const onRemoveAdmin = async () => { - try { - await props.onRemoveAdmin({ - userId: user_id - }); - handleCloseDialog(); - toast.success('Admin removed successfully'); - } catch (error) { - if (error instanceof Error) { - toast.error(error.message); - } else { - toast.error('Could not remove admin'); - } - } - }; - - return ( - <> - - - - - - Remove Admin - - Are you sure you want to remove{' '} - {name} as an admin? - - - - - - - - - - - - ); - } - } - ]; - - return props.communityRole === 'owner' - ? [...baseColumns, ...ownerColumns] - : baseColumns; -}; - -export const skeletonColumns: ColumnDef< - UserCommunityAccessT & { admin: UserRow } ->[] = [ - { - header: 'Member', - cell: () => ( -
- -
- {/* name */} - {/* email */} -
-
- ) - }, - { - header: 'Created at', - cell: () => ( -
- -
- ) - } -]; - -export const placeholderData: (UserCommunityAccessT & { admin: UserRow })[] = - Array(5); +'use client'; +import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; + +import { + UserRow, + UserCommunityAccessT, + CommunityAccessRoleT +} from '@/services/top-db/users'; +import { ColumnDef } from '@tanstack/react-table'; +import { Skeleton } from '@/components/ui/skeleton'; +import { cn } from '@/lib/utils'; +import { Button } from '@/components/ui/button'; +import { Trash2 } from 'lucide-react'; +import { + Dialog, + DialogClose, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle +} from '@/components/ui/dialog'; +import { useState } from 'react'; +import { toast } from 'sonner'; + +interface CreateColumnsProps { + communityRole?: CommunityAccessRoleT; + alias: string; + onRemoveAdmin: (args: { userId: number }) => Promise; + isPending: boolean; +} + +export const createColumns = ( + props: CreateColumnsProps +): ColumnDef[] => { + const baseColumns: ColumnDef[] = [ + { + header: 'Member', + cell: ({ row }) => { + const { user } = row.original; + const { avatar, name, email } = user; + return ( +
+ + + {name?.slice(0, 2) ?? ''} + +
+ {name} + {email} +
+
+ ); + } + }, + { + header: 'Role', + accessorKey: 'role', + cell: ({ row }) => { + const role = row.original.role; + return ( +
+ + {role} + +
+ ); + } + }, + { + header: 'Created at', + accessorKey: 'created_at', + cell: ({ row }) => { + const createdAt = new Date(row.original.created_at); + return ( +
+ + {createdAt.toLocaleString()} + +
+ ); + } + } + ]; + + const ownerColumns: ColumnDef[] = [ + { + id: 'remove', + cell: function RemoveCell({ row }) { + const [isDialogOpen, setIsDialogOpen] = useState(false); + + const { + user_id, + user: { name } + } = row.original; + + const handleOpenDialog = () => { + setIsDialogOpen(true); + }; + + const handleCloseDialog = () => { + setIsDialogOpen(false); + }; + + const onRemoveAdmin = async () => { + try { + await props.onRemoveAdmin({ + userId: user_id + }); + handleCloseDialog(); + toast.success('Admin removed successfully'); + } catch (error) { + if (error instanceof Error) { + toast.error(error.message); + } else { + toast.error('Could not remove admin'); + } + } + }; + + return ( + <> + + + + + + Remove Admin + + Are you sure you want to remove{' '} + {name} as an admin? + + + + + + + + + + + + ); + } + } + ]; + + return props.communityRole === 'owner' + ? [...baseColumns, ...ownerColumns] + : baseColumns; +}; + +export const skeletonColumns: ColumnDef< + UserCommunityAccessT & { admin: UserRow } +>[] = [ + { + header: 'Member', + cell: () => ( +
+ +
+ {/* name */} + {/* email */} +
+
+ ) + }, + { + header: 'Created at', + cell: () => ( +
+ +
+ ) + } +]; + +export const placeholderData: (UserCommunityAccessT & { admin: UserRow })[] = + Array(5); diff --git a/app/[alias]/(dashboard)/admins/add/actions.ts b/app/[alias]/(dashboard)/admins/add/actions.ts index 855528ed..365d62a5 100644 --- a/app/[alias]/(dashboard)/admins/add/actions.ts +++ b/app/[alias]/(dashboard)/admins/add/actions.ts @@ -1,123 +1,123 @@ -'use server'; - -import { getServiceRoleClient as getTopDbClient } from '@/services/top-db'; -import { z } from 'zod'; -import { inviteAdminFormSchema } from './form-schema'; - -import { addUserRowoApp, addUserRowoCommunity } from '@/services/top-db/users'; -import { saveOTP } from '@/services/top-db/otp'; - -import { sendCommunityInvitationEmail } from '@/services/brevo'; -import { generateOTP } from '@/lib/utils'; -import { getAuthUserRoleInCommunityAction } from '@/app/_actions/user-actions'; -import { Config } from '@citizenwallet/sdk'; -import { revalidatePath } from 'next/cache'; - -export async function submitAdminInvitation(args: { - formData: z.infer; - chainId: number; -}) { - const { formData, chainId } = args; - - const result = inviteAdminFormSchema.safeParse(formData); - - if (!result.success) { - console.error(result.error); - throw new Error('Invalid form data'); - } - - const userRole = await getAuthUserRoleInCommunityAction({ - alias: formData.alias - }); - - if (userRole !== 'owner') { - throw new Error('You are not authorized to add admins to this community'); - } - - const { email, name, avatar, alias, role } = result.data; - - const topDbClient = getTopDbClient(); - - const { data: user, error: addUserRowoAppError } = await addUserRowoApp({ - client: topDbClient, - data: { - email, - name, - avatar: avatar ?? null - } - }); - - if (addUserRowoAppError) { - console.error(addUserRowoAppError); - throw new Error('Failed to add user to app'); - } - - const { error: addUserRowoCommunityError } = await addUserRowoCommunity({ - client: topDbClient, - data: { - user_id: user.id, - alias, - role, - chain_id: chainId - } - }); - - if (addUserRowoCommunityError) { - console.error(addUserRowoCommunityError); - throw new Error('Failed to add user to community'); - } - - revalidatePath(`/${alias}/admins`); -} - -export async function sendAdminSignInInvitationAction(args: { - email: string; - config: Config; -}) { - const { email, config } = args; - - const { alias: communityAlias, name: communityName } = config.community; - - const userRole = await getAuthUserRoleInCommunityAction({ - alias: communityAlias - }); - - if (userRole !== 'owner') { - throw new Error('You are not authorized to add admins to this community'); - } - - const topDbClient = getTopDbClient(); - const otp = generateOTP(); - - // brevo - try { - sendCommunityInvitationEmail({ - email, - otp, - communityAlias, - communityName - }); - } catch (error) { - console.error(error); - // Preserve the original error message - if (error instanceof Error) { - throw error; - } - throw new Error('Failed to send invitation email'); - } - - // db - const { error: saveOTPError } = await saveOTP({ - client: topDbClient, - data: { - source: email, - code: otp, - source_type: 'email' - } - }); - - if (saveOTPError) { - console.error(saveOTPError); - throw new Error('Failed to save OTP'); - } -} +'use server'; + +import { getServiceRoleClient as getTopDbClient } from '@/services/top-db'; +import { z } from 'zod'; +import { inviteAdminFormSchema } from './form-schema'; + +import { addUserRowoApp, addUserRowoCommunity } from '@/services/top-db/users'; +import { saveOTP } from '@/services/top-db/otp'; + +import { sendCommunityInvitationEmail } from '@/services/brevo'; +import { generateOTP } from '@/lib/utils'; +import { getAuthUserRoleInCommunityAction } from '@/app/_actions/user-actions'; +import { Config } from '@citizenwallet/sdk'; +import { revalidatePath } from 'next/cache'; + +export async function submitAdminInvitation(args: { + formData: z.infer; + chainId: number; +}) { + const { formData, chainId } = args; + + const result = inviteAdminFormSchema.safeParse(formData); + + if (!result.success) { + console.error(result.error); + throw new Error('Invalid form data'); + } + + const userRole = await getAuthUserRoleInCommunityAction({ + alias: formData.alias + }); + + if (userRole !== 'owner') { + throw new Error('You are not authorized to add admins to this community'); + } + + const { email, name, avatar, alias, role } = result.data; + + const topDbClient = getTopDbClient(); + + const { data: user, error: addUserRowoAppError } = await addUserRowoApp({ + client: topDbClient, + data: { + email, + name, + avatar: avatar ?? null + } + }); + + if (addUserRowoAppError) { + console.error(addUserRowoAppError); + throw new Error('Failed to add user to app'); + } + + const { error: addUserRowoCommunityError } = await addUserRowoCommunity({ + client: topDbClient, + data: { + user_id: user.id, + alias, + role, + chain_id: chainId + } + }); + + if (addUserRowoCommunityError) { + console.error(addUserRowoCommunityError); + throw new Error('Failed to add user to community'); + } + + revalidatePath(`/${alias}/admins`); +} + +export async function sendAdminSignInInvitationAction(args: { + email: string; + config: Config; +}) { + const { email, config } = args; + + const { alias: communityAlias, name: communityName } = config.community; + + const userRole = await getAuthUserRoleInCommunityAction({ + alias: communityAlias + }); + + if (userRole !== 'owner') { + throw new Error('You are not authorized to add admins to this community'); + } + + const topDbClient = getTopDbClient(); + const otp = generateOTP(); + + // brevo + try { + sendCommunityInvitationEmail({ + email, + otp, + communityAlias, + communityName + }); + } catch (error) { + console.error(error); + // Preserve the original error message + if (error instanceof Error) { + throw error; + } + throw new Error('Failed to send invitation email'); + } + + // db + const { error: saveOTPError } = await saveOTP({ + client: topDbClient, + data: { + source: email, + code: otp, + source_type: 'email' + } + }); + + if (saveOTPError) { + console.error(saveOTPError); + throw new Error('Failed to save OTP'); + } +} diff --git a/app/[alias]/(dashboard)/admins/add/page.tsx b/app/[alias]/(dashboard)/admins/add/page.tsx index b36dd9d0..e4f4b7ba 100644 --- a/app/[alias]/(dashboard)/admins/add/page.tsx +++ b/app/[alias]/(dashboard)/admins/add/page.tsx @@ -1,47 +1,47 @@ -import { getAuthUserRoleInCommunityAction } from '@/app/_actions/user-actions'; -import { - Card, - CardContent, - CardDescription, - CardHeader, - CardTitle -} from '@/components/ui/card'; -import { getServiceRoleClient } from '@/services/top-db'; -import { getCommunityByAlias } from '@/services/top-db/community'; -import { redirect } from 'next/navigation'; -import InviteAdminForm from './form'; - -export default async function Page(props: { - params: Promise<{ alias: string }>; -}) { - const { alias } = await props.params; - const client = getServiceRoleClient(); - const { data, error } = await getCommunityByAlias(client, alias); - - if (error || !data) { - throw new Error('Failed to get community by alias'); - } - - const config = data.json; - const authRole = await getAuthUserRoleInCommunityAction({ - alias - }); - - if (authRole !== 'owner') { - redirect(`/${alias}/admins`); - } - - return ( -
- - - Invite admin - Invite an admin to your community - - - - - -
- ); -} +import { getAuthUserRoleInCommunityAction } from '@/app/_actions/user-actions'; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle +} from '@/components/ui/card'; +import { getServiceRoleClient } from '@/services/top-db'; +import { getCommunityByAlias } from '@/services/top-db/community'; +import { redirect } from 'next/navigation'; +import InviteAdminForm from './form'; + +export default async function Page(props: { + params: Promise<{ alias: string }>; +}) { + const { alias } = await props.params; + const client = getServiceRoleClient(); + const { data, error } = await getCommunityByAlias(client, alias); + + if (error || !data) { + throw new Error('Failed to get community by alias'); + } + + const config = data.json; + const authRole = await getAuthUserRoleInCommunityAction({ + alias + }); + + if (authRole !== 'owner') { + redirect(`/${alias}/admins`); + } + + return ( +
+ + + Invite admin + Invite an admin to your community + + + + + +
+ ); +} diff --git a/app/[alias]/(dashboard)/checkout/action.ts b/app/[alias]/(dashboard)/checkout/action.ts index b3303cf8..ac9e6e2f 100644 --- a/app/[alias]/(dashboard)/checkout/action.ts +++ b/app/[alias]/(dashboard)/checkout/action.ts @@ -1,325 +1,325 @@ -'use server'; - -import { - getAuthUserRoleInAppAction, - getAuthUserRoleInCommunityAction -} from '@/app/_actions/user-actions'; -import { getServiceRoleClient } from '@/services/top-db'; -import { - activeCommunity, - updateCommunityJson -} from '@/services/top-db/community'; -import { Config } from '@citizenwallet/sdk'; -import { ethers } from 'ethers'; -import { - ERC1967_ABI, - ERC1967_BYTECODE -} from './contract/ERC1967Proxy_contract'; -import { - PAYMASTER_ABI, - PAYMASTER_BYTECODE -} from './contract/paymaster_contract'; -import { PROFILE_ABI, PROFILE_BYTECODE } from './contract/profile_contract'; -import { TOKEN_ABI, TOKEN_BYTECODE } from './contract/token_contract'; - -interface ProxyDeployParams { - initializeArgs?: string[]; - privateKey: string; - chainId: string; -} - -const CHAIN_ID_TO_RPC_URL = (chainId: string) => { - switch (chainId) { - case '137': - return process.env.POLYGON_RPC_URL; - case '100': - return process.env.GNOSIS_RPC_URL; - case '42220': - return process.env.CELO_RPC_URL; - case '42161': - return process.env.ARBITRUM_RPC_URL; - default: - return process.env.BASE_RPC_URL; - } -}; - -export async function deployProfileAction({ - initializeArgs = [], - privateKey, - chainId -}: ProxyDeployParams): Promise { - try { - // Connect to Polygon Amoy - const provider = new ethers.JsonRpcProvider(CHAIN_ID_TO_RPC_URL(chainId)); - - // Your deployment wallet - const wallet = new ethers.Wallet(privateKey, provider); - - // 1. Deploy Implementation Contract - const implementationFactory = new ethers.ContractFactory( - PROFILE_ABI, - PROFILE_BYTECODE, - wallet - ); - - const implementation = await implementationFactory.deploy({ - gasLimit: 3000000 - }); - await implementation.waitForDeployment(); - const implementationAddress = await implementation.getAddress(); - - // 2. Prepare initialization data if needed - let initData = '0x'; - if (initializeArgs.length > 0) { - const contract = new ethers.Contract( - implementationAddress, - PROFILE_ABI, - wallet - ); - initData = contract.interface.encodeFunctionData( - 'initialize', - initializeArgs - ); - } - - // 3. Deploy ERC1967Proxy - const proxyFactory = new ethers.ContractFactory( - ERC1967_ABI, - ERC1967_BYTECODE, - wallet - ); - - const proxy = await proxyFactory.deploy(implementationAddress, initData, { - gasLimit: 3000000 - }); - await proxy.waitForDeployment(); - const proxyAddress = await proxy.getAddress(); - - return proxyAddress; - } catch (error) { - console.error('Proxy deployment error:', error); - } -} - -export async function deployPaymasterAction({ - privateKey, - chainId, - profileAddress, - tokenAddress -}: { - privateKey: string; - chainId: string; - profileAddress: string; - tokenAddress: string; -}): Promise { - try { - // Get the provider from environment variable - const provider = new ethers.JsonRpcProvider(CHAIN_ID_TO_RPC_URL(chainId)); - - // Create a wallet instance - const wallet = new ethers.Wallet(privateKey, provider); - - // Create contract factory - const factory = new ethers.ContractFactory( - PAYMASTER_ABI, - PAYMASTER_BYTECODE, - wallet - ); - - // Deploy the contract with constructor arguments if provided - const contract = await factory.deploy({ - gasLimit: 3000000 - }); - - // Wait for deployment to complete - await contract.waitForDeployment(); - - // Get the contract address - const contractAddress = await contract.getAddress(); - - // Create a new contract instance for interaction - const paymasterContract = new ethers.Contract( - contractAddress, - PAYMASTER_ABI, - wallet - ); - - // whitelisted addresses - const whitelistedAddresses = [ - profileAddress, - tokenAddress, - '0xBA861e2DABd8316cf11Ae7CdA101d110CF581f28', // Card Manager - '0xE2F3DC3E638113b9496060349e5332963d9C1152' // Session Manager - ]; - - // Initialize the contract with the deployer as sponsor and whitelisted addresses - await paymasterContract.initialize(wallet.address, whitelistedAddresses, { - gasLimit: 3000000 - }); - - return contractAddress; - } catch (error) { - console.error('Contract deployment error:', error); - } -} - -export async function deployTokenAction({ - privateKey, - chainId -}: { - privateKey: string; - chainId: string; -}): Promise { - try { - // Get the provider from environment variable - const provider = new ethers.JsonRpcProvider(CHAIN_ID_TO_RPC_URL(chainId)); - - // Create a wallet instance - const wallet = new ethers.Wallet(privateKey, provider); - - // Create contract factory - const factory = new ethers.ContractFactory( - TOKEN_ABI, - TOKEN_BYTECODE, - wallet - ); - - // Deploy the contract with constructor arguments if provided - const contract = await factory.deploy({ - gasLimit: 3000000 - }); - - // Wait for deployment to complete - await contract.waitForDeployment(); - - // Get the contract address - const contractAddress = await contract.getAddress(); - - return contractAddress; - } catch (error) { - console.error('Contract deployment error:', error); - } -} - -const chains = [ - { - id: '100', - primary_account_factory: '0xBABCf159c4e3186cf48e4a48bC0AeC17CF9d90FE', - entrypoint_address: '0xAAEb9DC18aDadae9b3aE7ec2b47842565A81113f' - }, - { - id: '42220', - primary_account_factory: '0xcd8b1B9E760148c5026Bc5B0D56a5374e301FDcA', - entrypoint_address: '0x66fE9c22CcA49B257dd4F00508AC90198d99Bf27' - }, - { - id: '42161', - primary_account_factory: '0x0000000000000000000000000000000000000000', - entrypoint_address: '0x0000000000000000000000000000000000000000' - }, - { - id: '137', - primary_account_factory: '0x940Cbb155161dc0C4aade27a4826a16Ed8ca0cb2', - entrypoint_address: '0x7079253c0358eF9Fd87E16488299Ef6e06F403B6' - } -]; - -export async function updateCommunityConfigAction( - profileAddress: string, - paymasterAddress: string, - config: Config, - tokenAddress?: string -) { - const client = getServiceRoleClient(); - - const roleInCommunity = await getAuthUserRoleInCommunityAction({ - alias: config.community.alias - }); - - const roleInApp = await getAuthUserRoleInAppAction(); - - if (!roleInApp) { - throw new Error('Unauthenticated user'); - } - - if (roleInApp === 'user' && !roleInCommunity) { - throw new Error('You are not a member of this community'); - } - - const updateJson = { - ...config, - community: { - ...config.community, - profile: { - ...config.community.profile, - address: profileAddress - }, - primary_token: { - ...config.community.primary_token, - address: tokenAddress || config.community.primary_token.address - }, - primary_account_factory: { - ...config.community.primary_account_factory, - address: - chains.find( - (chain) => Number(chain.id) === config.community.profile.chain_id - )?.primary_account_factory || '' - } - }, - accounts: { - ...config.accounts, - [`${config.community.profile.chain_id}:${chains.find((chain) => Number(chain.id) === config.community.profile.chain_id)?.primary_account_factory}`]: - { - chain_id: config.community.profile.chain_id, - entrypoint_address: chains.find( - (chain) => Number(chain.id) === config.community.profile.chain_id - )?.entrypoint_address, - paymaster_address: paymasterAddress, - account_factory_address: chains.find( - (chain) => Number(chain.id) === config.community.profile.chain_id - )?.primary_account_factory, - paymaster_type: 'cw-safe' - } - }, - tokens: { - ...(tokenAddress - ? { - // remove the token address from the tokens object - ...Object.fromEntries( - Object.entries(config.tokens).filter( - ([key]) => - key !== - `${config.community.profile.chain_id}:${ethers.ZeroAddress}` - ) - ), - - [`${config.community.profile.chain_id}:${tokenAddress}`]: { - ...config.tokens[ - `${config.community.profile.chain_id}:${ethers.ZeroAddress}` - ], - address: tokenAddress - } - } - : config.tokens) - } - } as Config; - - try { - const { data: updatedData, error } = await updateCommunityJson( - client, - config.community.alias, - { json: updateJson } - ); - - if (error) { - throw new Error('Failed to update community config'); - } - - await activeCommunity(client, config.community.alias); - - return updatedData; - } catch (error) { - console.error('Error updating community config:', error); - throw new Error('Failed to update community config'); - } -} +'use server'; + +import { + getAuthUserRoleInAppAction, + getAuthUserRoleInCommunityAction +} from '@/app/_actions/user-actions'; +import { getServiceRoleClient } from '@/services/top-db'; +import { + activeCommunity, + updateCommunityJson +} from '@/services/top-db/community'; +import { Config } from '@citizenwallet/sdk'; +import { ethers } from 'ethers'; +import { + ERC1967_ABI, + ERC1967_BYTECODE +} from './contract/ERC1967Proxy_contract'; +import { + PAYMASTER_ABI, + PAYMASTER_BYTECODE +} from './contract/paymaster_contract'; +import { PROFILE_ABI, PROFILE_BYTECODE } from './contract/profile_contract'; +import { TOKEN_ABI, TOKEN_BYTECODE } from './contract/token_contract'; + +interface ProxyDeployParams { + initializeArgs?: string[]; + privateKey: string; + chainId: string; +} + +const CHAIN_ID_TO_RPC_URL = (chainId: string) => { + switch (chainId) { + case '137': + return process.env.POLYGON_RPC_URL; + case '100': + return process.env.GNOSIS_RPC_URL; + case '42220': + return process.env.CELO_RPC_URL; + case '42161': + return process.env.ARBITRUM_RPC_URL; + default: + return process.env.BASE_RPC_URL; + } +}; + +export async function deployProfileAction({ + initializeArgs = [], + privateKey, + chainId +}: ProxyDeployParams): Promise { + try { + // Connect to Polygon Amoy + const provider = new ethers.JsonRpcProvider(CHAIN_ID_TO_RPC_URL(chainId)); + + // Your deployment wallet + const wallet = new ethers.Wallet(privateKey, provider); + + // 1. Deploy Implementation Contract + const implementationFactory = new ethers.ContractFactory( + PROFILE_ABI, + PROFILE_BYTECODE, + wallet + ); + + const implementation = await implementationFactory.deploy({ + gasLimit: 3000000 + }); + await implementation.waitForDeployment(); + const implementationAddress = await implementation.getAddress(); + + // 2. Prepare initialization data if needed + let initData = '0x'; + if (initializeArgs.length > 0) { + const contract = new ethers.Contract( + implementationAddress, + PROFILE_ABI, + wallet + ); + initData = contract.interface.encodeFunctionData( + 'initialize', + initializeArgs + ); + } + + // 3. Deploy ERC1967Proxy + const proxyFactory = new ethers.ContractFactory( + ERC1967_ABI, + ERC1967_BYTECODE, + wallet + ); + + const proxy = await proxyFactory.deploy(implementationAddress, initData, { + gasLimit: 3000000 + }); + await proxy.waitForDeployment(); + const proxyAddress = await proxy.getAddress(); + + return proxyAddress; + } catch (error) { + console.error('Proxy deployment error:', error); + } +} + +export async function deployPaymasterAction({ + privateKey, + chainId, + profileAddress, + tokenAddress +}: { + privateKey: string; + chainId: string; + profileAddress: string; + tokenAddress: string; +}): Promise { + try { + // Get the provider from environment variable + const provider = new ethers.JsonRpcProvider(CHAIN_ID_TO_RPC_URL(chainId)); + + // Create a wallet instance + const wallet = new ethers.Wallet(privateKey, provider); + + // Create contract factory + const factory = new ethers.ContractFactory( + PAYMASTER_ABI, + PAYMASTER_BYTECODE, + wallet + ); + + // Deploy the contract with constructor arguments if provided + const contract = await factory.deploy({ + gasLimit: 3000000 + }); + + // Wait for deployment to complete + await contract.waitForDeployment(); + + // Get the contract address + const contractAddress = await contract.getAddress(); + + // Create a new contract instance for interaction + const paymasterContract = new ethers.Contract( + contractAddress, + PAYMASTER_ABI, + wallet + ); + + // whitelisted addresses + const whitelistedAddresses = [ + profileAddress, + tokenAddress, + '0xBA861e2DABd8316cf11Ae7CdA101d110CF581f28', // Card Manager + '0xE2F3DC3E638113b9496060349e5332963d9C1152' // Session Manager + ]; + + // Initialize the contract with the deployer as sponsor and whitelisted addresses + await paymasterContract.initialize(wallet.address, whitelistedAddresses, { + gasLimit: 3000000 + }); + + return contractAddress; + } catch (error) { + console.error('Contract deployment error:', error); + } +} + +export async function deployTokenAction({ + privateKey, + chainId +}: { + privateKey: string; + chainId: string; +}): Promise { + try { + // Get the provider from environment variable + const provider = new ethers.JsonRpcProvider(CHAIN_ID_TO_RPC_URL(chainId)); + + // Create a wallet instance + const wallet = new ethers.Wallet(privateKey, provider); + + // Create contract factory + const factory = new ethers.ContractFactory( + TOKEN_ABI, + TOKEN_BYTECODE, + wallet + ); + + // Deploy the contract with constructor arguments if provided + const contract = await factory.deploy({ + gasLimit: 3000000 + }); + + // Wait for deployment to complete + await contract.waitForDeployment(); + + // Get the contract address + const contractAddress = await contract.getAddress(); + + return contractAddress; + } catch (error) { + console.error('Contract deployment error:', error); + } +} + +const chains = [ + { + id: '100', + primary_account_factory: '0xBABCf159c4e3186cf48e4a48bC0AeC17CF9d90FE', + entrypoint_address: '0xAAEb9DC18aDadae9b3aE7ec2b47842565A81113f' + }, + { + id: '42220', + primary_account_factory: '0xcd8b1B9E760148c5026Bc5B0D56a5374e301FDcA', + entrypoint_address: '0x66fE9c22CcA49B257dd4F00508AC90198d99Bf27' + }, + { + id: '42161', + primary_account_factory: '0x0000000000000000000000000000000000000000', + entrypoint_address: '0x0000000000000000000000000000000000000000' + }, + { + id: '137', + primary_account_factory: '0x940Cbb155161dc0C4aade27a4826a16Ed8ca0cb2', + entrypoint_address: '0x7079253c0358eF9Fd87E16488299Ef6e06F403B6' + } +]; + +export async function updateCommunityConfigAction( + profileAddress: string, + paymasterAddress: string, + config: Config, + tokenAddress?: string +) { + const client = getServiceRoleClient(); + + const roleInCommunity = await getAuthUserRoleInCommunityAction({ + alias: config.community.alias + }); + + const roleInApp = await getAuthUserRoleInAppAction(); + + if (!roleInApp) { + throw new Error('Unauthenticated user'); + } + + if (roleInApp === 'user' && !roleInCommunity) { + throw new Error('You are not a member of this community'); + } + + const updateJson = { + ...config, + community: { + ...config.community, + profile: { + ...config.community.profile, + address: profileAddress + }, + primary_token: { + ...config.community.primary_token, + address: tokenAddress || config.community.primary_token.address + }, + primary_account_factory: { + ...config.community.primary_account_factory, + address: + chains.find( + (chain) => Number(chain.id) === config.community.profile.chain_id + )?.primary_account_factory || '' + } + }, + accounts: { + ...config.accounts, + [`${config.community.profile.chain_id}:${chains.find((chain) => Number(chain.id) === config.community.profile.chain_id)?.primary_account_factory}`]: + { + chain_id: config.community.profile.chain_id, + entrypoint_address: chains.find( + (chain) => Number(chain.id) === config.community.profile.chain_id + )?.entrypoint_address, + paymaster_address: paymasterAddress, + account_factory_address: chains.find( + (chain) => Number(chain.id) === config.community.profile.chain_id + )?.primary_account_factory, + paymaster_type: 'cw-safe' + } + }, + tokens: { + ...(tokenAddress + ? { + // remove the token address from the tokens object + ...Object.fromEntries( + Object.entries(config.tokens).filter( + ([key]) => + key !== + `${config.community.profile.chain_id}:${ethers.ZeroAddress}` + ) + ), + + [`${config.community.profile.chain_id}:${tokenAddress}`]: { + ...config.tokens[ + `${config.community.profile.chain_id}:${ethers.ZeroAddress}` + ], + address: tokenAddress + } + } + : config.tokens) + } + } as Config; + + try { + const { data: updatedData, error } = await updateCommunityJson( + client, + config.community.alias, + { json: updateJson } + ); + + if (error) { + throw new Error('Failed to update community config'); + } + + await activeCommunity(client, config.community.alias); + + return updatedData; + } catch (error) { + console.error('Error updating community config:', error); + throw new Error('Failed to update community config'); + } +} diff --git a/app/[alias]/(dashboard)/checkout/checkout-flow.tsx b/app/[alias]/(dashboard)/checkout/checkout-flow.tsx index 2a55f85d..5401b412 100644 --- a/app/[alias]/(dashboard)/checkout/checkout-flow.tsx +++ b/app/[alias]/(dashboard)/checkout/checkout-flow.tsx @@ -1,289 +1,289 @@ -'use client'; - -import { Badge } from '@/components/ui/badge'; -import { Button } from '@/components/ui/button'; -import { Card, CardContent, CardFooter } from '@/components/ui/card'; -import { Progress } from "@/components/ui/progress"; -import { Separator } from '@/components/ui/separator'; -import { CommunityConfig, Config } from '@citizenwallet/sdk'; -import { AlertCircle, Coins, Loader2, Wallet as WalletIcon } from 'lucide-react'; -import { useRouter } from 'next/navigation'; -import { useEffect, useState, useTransition } from 'react'; -import QRCode from "react-qr-code"; -import { toast } from 'sonner'; -import { useSession } from 'state/session/action'; -import { deployPaymasterAction, deployProfileAction, deployTokenAction, updateCommunityConfigAction } from './action'; - - -interface CheckoutFlowProps { - option: 'byoc' | 'create'; - config: Config; - address?: string; - ctzn_config: Config; - tokenName: string; - tokenSymbol: string; - userAddress: string; - userAccountBalance: number; -} - - -const BYOC_COST = 100; -const TOKEN_PUBLISH_COST = 200; - -export function CheckoutFlow({ - option, - config, - address, - ctzn_config, - tokenName, - tokenSymbol, - userAddress, - userAccountBalance -}: - CheckoutFlowProps -) { - - - const [, sessionActions] = useSession(ctzn_config); - const [topupUrl, setTopupUrl] = useState(null); - const [isPending, startTransition] = useTransition(); - const [onprogress, setOnprogress] = useState(0); - const router = useRouter(); - - - useEffect(() => { - const createTopupUrl = async () => { - - const communityConfig = new CommunityConfig(ctzn_config); - - setTopupUrl(`ethereum:0x0D9B0790E97e3426C161580dF4Ee853E4A7C4607@${communityConfig.primaryToken.chain_id}/transfer?address=${userAddress}&uint256=${option === 'byoc' ? BYOC_COST : TOKEN_PUBLISH_COST}`); - - } - createTopupUrl(); - }, [option, ctzn_config, userAddress]) - - - const deployContract = () => { - startTransition(async () => { - - const privateKey = sessionActions.storage.getKey('session_private_key'); - - let profileDeploy: string | undefined; - let paymasterDeploy: string | undefined; - let tokenDeploy: string | undefined = address || undefined; - - const communityConfig = new CommunityConfig(config); - const chainId = communityConfig.primaryToken.chain_id.toString(); - - try { - if (option == 'byoc') { - - //- profile deploy - profileDeploy = await deployProfileAction({ - initializeArgs: [userAddress || ''], - privateKey: privateKey || '', - chainId: chainId - }) - setOnprogress(40); - - // - paymaster deploy - paymasterDeploy = await deployPaymasterAction({ - privateKey: privateKey || '', - chainId: chainId, - profileAddress: profileDeploy || '', - tokenAddress: tokenDeploy || '' - }) - - setOnprogress(80); - - //community config json update - await updateCommunityConfigAction(profileDeploy || '', paymasterDeploy || '', config); - setOnprogress(100); - - - } else if (option == 'create') { - // - profile deploy - profileDeploy = await deployProfileAction({ - initializeArgs: [userAddress || ''], - privateKey: privateKey || '', - chainId: chainId - }) - setOnprogress(20); - - // - token deploy - tokenDeploy = await deployTokenAction({ - privateKey: privateKey || '', - chainId: chainId - }) - setOnprogress(40); - - // - paymaster deploy - paymasterDeploy = await deployPaymasterAction({ - privateKey: privateKey || '', - chainId: chainId, - profileAddress: profileDeploy || '', - tokenAddress: tokenDeploy || '' - }) - setOnprogress(80); - - //community config json update - await updateCommunityConfigAction(profileDeploy || '', paymasterDeploy || '', config, tokenDeploy || ''); - setOnprogress(100); - - } - - toast.success('Contract deployed successfully', { - description: 'Now you community is Active', - }); - - router.push(`/${config.community.alias}/treasury`); - } catch (error) { - console.error('Error deploying contract:', error); - toast.error('Error deploying contract'); - } - - }); - } - - return ( -
- {/* Pricing Options */} - - -
-
- -
-
- {tokenName} - {tokenSymbol} -
-
-
-
- - {/* Wallet */} - - - - -
- - {userAccountBalance < (option === 'byoc' ? BYOC_COST : TOKEN_PUBLISH_COST) && ( -
-
- -

- You have enough balance to continue. Please Top Up your account. -

-
-
- )} - - -
- -
- {userAccountBalance < (option === 'byoc' ? BYOC_COST : TOKEN_PUBLISH_COST) && ( -
-
- Insufficient balance. You need {option === 'byoc' ? BYOC_COST : TOKEN_PUBLISH_COST} CTZN to continue. -
-
- {userAddress && ( - <> -
- {/* Direct top-up section */} -
-
Top up CTZN directly
- -
- - {/* Divider with text */} -
-
-
-
-
- Or -
-
- - {/* QR Code section */} -
-
Send CTZN from any wallet
-
- -
-
- - Make sure you are sending on Polygon -
-
-
- - )} -
-
- )} -
- - - -
- Current Balance: - - {userAccountBalance} CTZN - -
- -
- Required Amount: - {option === 'byoc' ? BYOC_COST : TOKEN_PUBLISH_COST} CTZN -
- -
-
- - - - - -
- -
- - -
- -
- - - {isPending && } -
- - -
- ); +'use client'; + +import { Badge } from '@/components/ui/badge'; +import { Button } from '@/components/ui/button'; +import { Card, CardContent, CardFooter } from '@/components/ui/card'; +import { Progress } from "@/components/ui/progress"; +import { Separator } from '@/components/ui/separator'; +import { CommunityConfig, Config } from '@citizenwallet/sdk'; +import { AlertCircle, Coins, Loader2, Wallet as WalletIcon } from 'lucide-react'; +import { useRouter } from 'next/navigation'; +import { useEffect, useState, useTransition } from 'react'; +import QRCode from "react-qr-code"; +import { toast } from 'sonner'; +import { useSession } from 'state/session/action'; +import { deployPaymasterAction, deployProfileAction, deployTokenAction, updateCommunityConfigAction } from './action'; + + +interface CheckoutFlowProps { + option: 'byoc' | 'create'; + config: Config; + address?: string; + ctzn_config: Config; + tokenName: string; + tokenSymbol: string; + userAddress: string; + userAccountBalance: number; +} + + +const BYOC_COST = 100; +const TOKEN_PUBLISH_COST = 200; + +export function CheckoutFlow({ + option, + config, + address, + ctzn_config, + tokenName, + tokenSymbol, + userAddress, + userAccountBalance +}: + CheckoutFlowProps +) { + + + const [, sessionActions] = useSession(ctzn_config); + const [topupUrl, setTopupUrl] = useState(null); + const [isPending, startTransition] = useTransition(); + const [onprogress, setOnprogress] = useState(0); + const router = useRouter(); + + + useEffect(() => { + const createTopupUrl = async () => { + + const communityConfig = new CommunityConfig(ctzn_config); + + setTopupUrl(`ethereum:0x0D9B0790E97e3426C161580dF4Ee853E4A7C4607@${communityConfig.primaryToken.chain_id}/transfer?address=${userAddress}&uint256=${option === 'byoc' ? BYOC_COST : TOKEN_PUBLISH_COST}`); + + } + createTopupUrl(); + }, [option, ctzn_config, userAddress]) + + + const deployContract = () => { + startTransition(async () => { + + const privateKey = sessionActions.storage.getKey('session_private_key'); + + let profileDeploy: string | undefined; + let paymasterDeploy: string | undefined; + let tokenDeploy: string | undefined = address || undefined; + + const communityConfig = new CommunityConfig(config); + const chainId = communityConfig.primaryToken.chain_id.toString(); + + try { + if (option == 'byoc') { + + //- profile deploy + profileDeploy = await deployProfileAction({ + initializeArgs: [userAddress || ''], + privateKey: privateKey || '', + chainId: chainId + }) + setOnprogress(40); + + // - paymaster deploy + paymasterDeploy = await deployPaymasterAction({ + privateKey: privateKey || '', + chainId: chainId, + profileAddress: profileDeploy || '', + tokenAddress: tokenDeploy || '' + }) + + setOnprogress(80); + + //community config json update + await updateCommunityConfigAction(profileDeploy || '', paymasterDeploy || '', config); + setOnprogress(100); + + + } else if (option == 'create') { + // - profile deploy + profileDeploy = await deployProfileAction({ + initializeArgs: [userAddress || ''], + privateKey: privateKey || '', + chainId: chainId + }) + setOnprogress(20); + + // - token deploy + tokenDeploy = await deployTokenAction({ + privateKey: privateKey || '', + chainId: chainId + }) + setOnprogress(40); + + // - paymaster deploy + paymasterDeploy = await deployPaymasterAction({ + privateKey: privateKey || '', + chainId: chainId, + profileAddress: profileDeploy || '', + tokenAddress: tokenDeploy || '' + }) + setOnprogress(80); + + //community config json update + await updateCommunityConfigAction(profileDeploy || '', paymasterDeploy || '', config, tokenDeploy || ''); + setOnprogress(100); + + } + + toast.success('Contract deployed successfully', { + description: 'Now you community is Active', + }); + + router.push(`/${config.community.alias}/treasury`); + } catch (error) { + console.error('Error deploying contract:', error); + toast.error('Error deploying contract'); + } + + }); + } + + return ( +
+ {/* Pricing Options */} + + +
+
+ +
+
+ {tokenName} + {tokenSymbol} +
+
+
+
+ + {/* Wallet */} + + + + +
+ + {userAccountBalance < (option === 'byoc' ? BYOC_COST : TOKEN_PUBLISH_COST) && ( +
+
+ +

+ You have enough balance to continue. Please Top Up your account. +

+
+
+ )} + + +
+ +
+ {userAccountBalance < (option === 'byoc' ? BYOC_COST : TOKEN_PUBLISH_COST) && ( +
+
+ Insufficient balance. You need {option === 'byoc' ? BYOC_COST : TOKEN_PUBLISH_COST} CTZN to continue. +
+
+ {userAddress && ( + <> +
+ {/* Direct top-up section */} +
+
Top up CTZN directly
+ +
+ + {/* Divider with text */} +
+
+
+
+
+ Or +
+
+ + {/* QR Code section */} +
+
Send CTZN from any wallet
+
+ +
+
+ + Make sure you are sending on Polygon +
+
+
+ + )} +
+
+ )} +
+ + + +
+ Current Balance: + + {userAccountBalance} CTZN + +
+ +
+ Required Amount: + {option === 'byoc' ? BYOC_COST : TOKEN_PUBLISH_COST} CTZN +
+ +
+
+ + + + + +
+ +
+ + +
+ +
+ + + {isPending && } +
+ + +
+ ); } \ No newline at end of file diff --git a/app/[alias]/(dashboard)/checkout/contract/ERC1967Proxy_contract.ts b/app/[alias]/(dashboard)/checkout/contract/ERC1967Proxy_contract.ts index a072c662..4c88e40b 100644 --- a/app/[alias]/(dashboard)/checkout/contract/ERC1967Proxy_contract.ts +++ b/app/[alias]/(dashboard)/checkout/contract/ERC1967Proxy_contract.ts @@ -1,42 +1,42 @@ -export const ERC1967_ABI = [ - { - inputs: [ - { internalType: 'address', name: 'implementation', type: 'address' }, - { internalType: 'bytes', name: '_data', type: 'bytes' } - ], - stateMutability: 'payable', - type: 'constructor' - }, - { - inputs: [{ internalType: 'address', name: 'target', type: 'address' }], - name: 'AddressEmptyCode', - type: 'error' - }, - { - inputs: [ - { internalType: 'address', name: 'implementation', type: 'address' } - ], - name: 'ERC1967InvalidImplementation', - type: 'error' - }, - { inputs: [], name: 'ERC1967NonPayable', type: 'error' }, - { inputs: [], name: 'FailedInnerCall', type: 'error' }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'address', - name: 'implementation', - type: 'address' - } - ], - name: 'Upgraded', - type: 'event' - }, - { stateMutability: 'payable', type: 'fallback' } -]; - -// Minimal proxy bytecode -export const ERC1967_BYTECODE = - '60806040526040516103f03803806103f08339810160408190526100229161025e565b61002c8282610033565b5050610341565b61003c82610091565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a280511561008557610080828261010c565b505050565b61008d61017f565b5050565b806001600160a01b03163b5f036100cb57604051634c9c8ce360e01b81526001600160a01b03821660048201526024015b60405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b60605f80846001600160a01b0316846040516101289190610326565b5f60405180830381855af49150503d805f8114610160576040519150601f19603f3d011682016040523d82523d5f602084013e610165565b606091505b5090925090506101768583836101a0565b95945050505050565b341561019e5760405163b398979f60e01b815260040160405180910390fd5b565b6060826101b5576101b0826101ff565b6101f8565b81511580156101cc57506001600160a01b0384163b155b156101f557604051639996b31560e01b81526001600160a01b03851660048201526024016100c2565b50805b9392505050565b80511561020f5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b634e487b7160e01b5f52604160045260245ffd5b5f5b8381101561025657818101518382015260200161023e565b50505f910152565b5f806040838503121561026f575f80fd5b82516001600160a01b0381168114610285575f80fd5b60208401519092506001600160401b03808211156102a1575f80fd5b818501915085601f8301126102b4575f80fd5b8151818111156102c6576102c6610228565b604051601f8201601f19908116603f011681019083821181831017156102ee576102ee610228565b81604052828152886020848701011115610306575f80fd5b61031783602083016020880161023c565b80955050505050509250929050565b5f825161033781846020870161023c565b9190910192915050565b60a38061034d5f395ff3fe6080604052600a600c565b005b60186014601a565b6050565b565b5f604b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b365f80375f80365f845af43d5f803e8080156069573d5ff35b3d5ffdfea26469706673582212201dd6f1a1d815e0cd15745b59d3120e2064459c7fee5248ed79c39f9848bad89c64736f6c63430008140033'; +export const ERC1967_ABI = [ + { + inputs: [ + { internalType: 'address', name: 'implementation', type: 'address' }, + { internalType: 'bytes', name: '_data', type: 'bytes' } + ], + stateMutability: 'payable', + type: 'constructor' + }, + { + inputs: [{ internalType: 'address', name: 'target', type: 'address' }], + name: 'AddressEmptyCode', + type: 'error' + }, + { + inputs: [ + { internalType: 'address', name: 'implementation', type: 'address' } + ], + name: 'ERC1967InvalidImplementation', + type: 'error' + }, + { inputs: [], name: 'ERC1967NonPayable', type: 'error' }, + { inputs: [], name: 'FailedInnerCall', type: 'error' }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'implementation', + type: 'address' + } + ], + name: 'Upgraded', + type: 'event' + }, + { stateMutability: 'payable', type: 'fallback' } +]; + +// Minimal proxy bytecode +export const ERC1967_BYTECODE = + '60806040526040516103f03803806103f08339810160408190526100229161025e565b61002c8282610033565b5050610341565b61003c82610091565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a280511561008557610080828261010c565b505050565b61008d61017f565b5050565b806001600160a01b03163b5f036100cb57604051634c9c8ce360e01b81526001600160a01b03821660048201526024015b60405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b60605f80846001600160a01b0316846040516101289190610326565b5f60405180830381855af49150503d805f8114610160576040519150601f19603f3d011682016040523d82523d5f602084013e610165565b606091505b5090925090506101768583836101a0565b95945050505050565b341561019e5760405163b398979f60e01b815260040160405180910390fd5b565b6060826101b5576101b0826101ff565b6101f8565b81511580156101cc57506001600160a01b0384163b155b156101f557604051639996b31560e01b81526001600160a01b03851660048201526024016100c2565b50805b9392505050565b80511561020f5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b634e487b7160e01b5f52604160045260245ffd5b5f5b8381101561025657818101518382015260200161023e565b50505f910152565b5f806040838503121561026f575f80fd5b82516001600160a01b0381168114610285575f80fd5b60208401519092506001600160401b03808211156102a1575f80fd5b818501915085601f8301126102b4575f80fd5b8151818111156102c6576102c6610228565b604051601f8201601f19908116603f011681019083821181831017156102ee576102ee610228565b81604052828152886020848701011115610306575f80fd5b61031783602083016020880161023c565b80955050505050509250929050565b5f825161033781846020870161023c565b9190910192915050565b60a38061034d5f395ff3fe6080604052600a600c565b005b60186014601a565b6050565b565b5f604b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b365f80375f80365f845af43d5f803e8080156069573d5ff35b3d5ffdfea26469706673582212201dd6f1a1d815e0cd15745b59d3120e2064459c7fee5248ed79c39f9848bad89c64736f6c63430008140033'; diff --git a/app/[alias]/(dashboard)/checkout/contract/paymaster_contract.ts b/app/[alias]/(dashboard)/checkout/contract/paymaster_contract.ts index 35934772..34715ded 100644 --- a/app/[alias]/(dashboard)/checkout/contract/paymaster_contract.ts +++ b/app/[alias]/(dashboard)/checkout/contract/paymaster_contract.ts @@ -1,491 +1,491 @@ -export const PAYMASTER_ABI = [ - { - type: 'function', - name: 'UPGRADE_INTERFACE_VERSION', - inputs: [], - outputs: [ - { - name: '', - type: 'string', - internalType: 'string' - } - ], - stateMutability: 'view' - }, - { - type: 'function', - name: 'getHash', - inputs: [ - { - name: 'userOp', - type: 'tuple', - internalType: 'struct UserOperation', - components: [ - { - name: 'sender', - type: 'address', - internalType: 'address' - }, - { - name: 'nonce', - type: 'uint256', - internalType: 'uint256' - }, - { - name: 'initCode', - type: 'bytes', - internalType: 'bytes' - }, - { - name: 'callData', - type: 'bytes', - internalType: 'bytes' - }, - { - name: 'callGasLimit', - type: 'uint256', - internalType: 'uint256' - }, - { - name: 'verificationGasLimit', - type: 'uint256', - internalType: 'uint256' - }, - { - name: 'preVerificationGas', - type: 'uint256', - internalType: 'uint256' - }, - { - name: 'maxFeePerGas', - type: 'uint256', - internalType: 'uint256' - }, - { - name: 'maxPriorityFeePerGas', - type: 'uint256', - internalType: 'uint256' - }, - { - name: 'paymasterAndData', - type: 'bytes', - internalType: 'bytes' - }, - { - name: 'signature', - type: 'bytes', - internalType: 'bytes' - } - ] - }, - { - name: 'validUntil', - type: 'uint48', - internalType: 'uint48' - }, - { - name: 'validAfter', - type: 'uint48', - internalType: 'uint48' - } - ], - outputs: [ - { - name: '', - type: 'bytes32', - internalType: 'bytes32' - } - ], - stateMutability: 'view' - }, - { - type: 'function', - name: 'initialize', - inputs: [ - { - name: 'aSponsor', - type: 'address', - internalType: 'address' - }, - { - name: 'addresses', - type: 'address[]', - internalType: 'address[]' - } - ], - outputs: [], - stateMutability: 'nonpayable' - }, - { - type: 'function', - name: 'owner', - inputs: [], - outputs: [ - { - name: '', - type: 'address', - internalType: 'address' - } - ], - stateMutability: 'view' - }, - { - type: 'function', - name: 'postOp', - inputs: [ - { - name: 'mode', - type: 'uint8', - internalType: 'enum IPaymaster.PostOpMode' - }, - { - name: 'context', - type: 'bytes', - internalType: 'bytes' - }, - { - name: 'actualGasCost', - type: 'uint256', - internalType: 'uint256' - } - ], - outputs: [], - stateMutability: 'view' - }, - { - type: 'function', - name: 'proxiableUUID', - inputs: [], - outputs: [ - { - name: '', - type: 'bytes32', - internalType: 'bytes32' - } - ], - stateMutability: 'view' - }, - { - type: 'function', - name: 'renounceOwnership', - inputs: [], - outputs: [], - stateMutability: 'nonpayable' - }, - { - type: 'function', - name: 'sponsor', - inputs: [], - outputs: [ - { - name: '', - type: 'address', - internalType: 'address' - } - ], - stateMutability: 'view' - }, - { - type: 'function', - name: 'transferOwnership', - inputs: [ - { - name: 'newOwner', - type: 'address', - internalType: 'address' - } - ], - outputs: [], - stateMutability: 'nonpayable' - }, - { - type: 'function', - name: 'updateSponsor', - inputs: [ - { - name: 'newSponsor', - type: 'address', - internalType: 'address' - } - ], - outputs: [], - stateMutability: 'nonpayable' - }, - { - type: 'function', - name: 'updateWhitelist', - inputs: [ - { - name: 'addresses', - type: 'address[]', - internalType: 'address[]' - } - ], - outputs: [], - stateMutability: 'nonpayable' - }, - { - type: 'function', - name: 'upgradeToAndCall', - inputs: [ - { - name: 'newImplementation', - type: 'address', - internalType: 'address' - }, - { - name: 'data', - type: 'bytes', - internalType: 'bytes' - } - ], - outputs: [], - stateMutability: 'payable' - }, - { - type: 'function', - name: 'validatePaymasterUserOp', - inputs: [ - { - name: 'userOp', - type: 'tuple', - internalType: 'struct UserOperation', - components: [ - { - name: 'sender', - type: 'address', - internalType: 'address' - }, - { - name: 'nonce', - type: 'uint256', - internalType: 'uint256' - }, - { - name: 'initCode', - type: 'bytes', - internalType: 'bytes' - }, - { - name: 'callData', - type: 'bytes', - internalType: 'bytes' - }, - { - name: 'callGasLimit', - type: 'uint256', - internalType: 'uint256' - }, - { - name: 'verificationGasLimit', - type: 'uint256', - internalType: 'uint256' - }, - { - name: 'preVerificationGas', - type: 'uint256', - internalType: 'uint256' - }, - { - name: 'maxFeePerGas', - type: 'uint256', - internalType: 'uint256' - }, - { - name: 'maxPriorityFeePerGas', - type: 'uint256', - internalType: 'uint256' - }, - { - name: 'paymasterAndData', - type: 'bytes', - internalType: 'bytes' - }, - { - name: 'signature', - type: 'bytes', - internalType: 'bytes' - } - ] - }, - { - name: 'userOpHash', - type: 'bytes32', - internalType: 'bytes32' - }, - { - name: 'maxCost', - type: 'uint256', - internalType: 'uint256' - } - ], - outputs: [ - { - name: 'context', - type: 'bytes', - internalType: 'bytes' - }, - { - name: 'validationData', - type: 'uint256', - internalType: 'uint256' - } - ], - stateMutability: 'view' - }, - { - type: 'event', - name: 'Initialized', - inputs: [ - { - name: 'version', - type: 'uint64', - indexed: false, - internalType: 'uint64' - } - ], - anonymous: false - }, - { - type: 'event', - name: 'OwnershipTransferred', - inputs: [ - { - name: 'previousOwner', - type: 'address', - indexed: true, - internalType: 'address' - }, - { - name: 'newOwner', - type: 'address', - indexed: true, - internalType: 'address' - } - ], - anonymous: false - }, - { - type: 'event', - name: 'Upgraded', - inputs: [ - { - name: 'implementation', - type: 'address', - indexed: true, - internalType: 'address' - } - ], - anonymous: false - }, - { - type: 'error', - name: 'AddressEmptyCode', - inputs: [ - { - name: 'target', - type: 'address', - internalType: 'address' - } - ] - }, - { - type: 'error', - name: 'ECDSAInvalidSignature', - inputs: [] - }, - { - type: 'error', - name: 'ECDSAInvalidSignatureLength', - inputs: [ - { - name: 'length', - type: 'uint256', - internalType: 'uint256' - } - ] - }, - { - type: 'error', - name: 'ECDSAInvalidSignatureS', - inputs: [ - { - name: 's', - type: 'bytes32', - internalType: 'bytes32' - } - ] - }, - { - type: 'error', - name: 'ERC1967InvalidImplementation', - inputs: [ - { - name: 'implementation', - type: 'address', - internalType: 'address' - } - ] - }, - { - type: 'error', - name: 'ERC1967NonPayable', - inputs: [] - }, - { - type: 'error', - name: 'FailedInnerCall', - inputs: [] - }, - { - type: 'error', - name: 'InvalidInitialization', - inputs: [] - }, - { - type: 'error', - name: 'NotInitializing', - inputs: [] - }, - { - type: 'error', - name: 'OwnableInvalidOwner', - inputs: [ - { - name: 'owner', - type: 'address', - internalType: 'address' - } - ] - }, - { - type: 'error', - name: 'OwnableUnauthorizedAccount', - inputs: [ - { - name: 'account', - type: 'address', - internalType: 'address' - } - ] - }, - { - type: 'error', - name: 'UUPSUnauthorizedCallContext', - inputs: [] - }, - { - type: 'error', - name: 'UUPSUnsupportedProxiableUUID', - inputs: [ - { - name: 'slot', - type: 'bytes32', - internalType: 'bytes32' - } - ] - } -]; - -export const PAYMASTER_BYTECODE = - '0x60a06040523060805234801561001457600080fd5b5060805161191661003e600039600081816109b6015281816109df0152610b2001526119166000f3fe6080604052600436106100c25760003560e01c8063946d92041161007f578063ad3cb1cc11610059578063ad3cb1cc14610209578063c9a54e2b14610247578063f2fde38b14610267578063f465c77e1461028757600080fd5b8063946d9204146101a857806394e1fc19146101c8578063a9a23409146101e857600080fd5b806335377214146100c75780634f1ef286146100e957806352d1902d146100fc578063715018a61461012457806377c93662146101395780638da5cb5b1461016b575b600080fd5b3480156100d357600080fd5b506100e76100e23660046112dc565b6102b5565b005b6100e76100f73660046113d4565b6102cb565b34801561010857600080fd5b506101116102e6565b6040519081526020015b60405180910390f35b34801561013057600080fd5b506100e7610303565b34801561014557600080fd5b506000546001600160a01b03165b6040516001600160a01b03909116815260200161011b565b34801561017757600080fd5b507f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b0316610153565b3480156101b457600080fd5b506100e76101c3366004611423565b610317565b3480156101d457600080fd5b506101116101e33660046114ab565b61043a565b3480156101f457600080fd5b506100e7610203366004611508565b50505050565b34801561021557600080fd5b5061023a604051806040016040528060058152602001640352e302e360dc1b81525081565b60405161011b91906115e6565b34801561025357600080fd5b506100e76102623660046115f9565b61057d565b34801561027357600080fd5b506100e76102823660046115f9565b6105a7565b34801561029357600080fd5b506102a76102a2366004611616565b6105e5565b60405161011b929190611663565b6102bd6108d1565b6102c7828261092c565b5050565b6102d36109ab565b6102dc82610a50565b6102c78282610a58565b60006102f0610b15565b506000805160206118c183398151915290565b61030b6108d1565b6103156000610b5e565b565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff1615906001600160401b031660008115801561035c5750825b90506000826001600160401b031660011480156103785750303b155b905081158015610386575080155b156103a45760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff1916600117855583156103ce57845460ff60401b1916600160401b1785555b6103d788610bcf565b6103e18787610be0565b6103ea88610cf5565b831561043057845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b5050505050505050565b60008061044a6060860186611685565b610459916004916000916116cb565b610462916116f5565b90506001600160e01b031981166104c05760405162461bcd60e51b815260206004820152601e60248201527f4141323720696e76616c69642066756e6374696f6e2073656c6563746f72000060448201526064015b60405180910390fd5b6000546001600160e01b0319828116600160a01b90920460e01b16146105285760405162461bcd60e51b815260206004820152601e60248201527f4141323720696e76616c69642066756e6374696f6e2073656c6563746f72000060448201526064016104b7565b61053185610d4f565b46306105456000546001600160a01b031690565b878760405160200161055c96959493929190611725565b604051602081830303815290604052805190602001209150505b9392505050565b6105856108d1565b600080546001600160a01b0319166001600160a01b0392909216919091179055565b6105af6108d1565b6001600160a01b0381166105d957604051631e4fbdf760e01b8152600060048201526024016104b7565b6105e281610b5e565b50565b60606000808036816106036105fe6101208b018b611685565b610dc6565b92965090945092509050604081148061061c5750604181145b6106685760405162461bcd60e51b815260206004820152601d60248201527f4141333520696e76616c6964207369676e6174757265206c656e67746800000060448201526064016104b7565b4265ffffffffffff80851690821610156106be5760405162461bcd60e51b8152602060048201526017602482015276414133322065787069726564206f72206e6f742064756560481b60448201526064016104b7565b8465ffffffffffff168165ffffffffffff16106107175760405162461bcd60e51b8152602060048201526017602482015276414133322065787069726564206f72206e6f742064756560481b60448201526064016104b7565b600061072e61072960608d018d611685565b610e03565b50509050600061073c8c3590565b9050806001600160a01b0316826001600160a01b0316148061077757506001546001600160a01b038316600090815260026020526040902054145b6107c35760405162461bcd60e51b815260206004820152601d60248201527f4141333820636f6e7472616374206e6f742077686974656c697374656400000060448201526064016104b7565b60006108066107d38e8a8a61043a565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000006000908152601c91909152603c902090565b905061084a86868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508593925050610e379050565b6001600160a01b03166108656000546001600160a01b031690565b6001600160a01b0316146108a15761087f60018989610e61565b60405180602001604052806000815250909950995050505050505050506108c9565b6108ad60008989610e61565b6040805160208101909152600081529a50985050505050505050505b935093915050565b336109037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b6001600160a01b0316146103155760405163118cdaa760e01b81523360048201526024016104b7565b6001805490600061093c83611777565b919050555060005b818110156109a657600154600260008585858181106109655761096561179e565b905060200201602081019061097a91906115f9565b6001600160a01b031681526020810191909152604001600020558061099e81611777565b915050610944565b505050565b306001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161480610a3257507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316610a266000805160206118c1833981519152546001600160a01b031690565b6001600160a01b031614155b156103155760405163703e46dd60e11b815260040160405180910390fd5b6105e26108d1565b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015610ab2575060408051601f3d908101601f19168201909252610aaf918101906117b4565b60015b610ada57604051634c9c8ce360e01b81526001600160a01b03831660048201526024016104b7565b6000805160206118c18339815191528114610b0b57604051632a87526960e21b8152600481018290526024016104b7565b6109a68383610e99565b306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146103155760405163703e46dd60e11b815260040160405180910390fd5b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b610bd7610eef565b6105e281610f38565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff1615906001600160401b0316600081158015610c255750825b90506000826001600160401b03166001148015610c415750303b155b905081158015610c4f575080155b15610c6d5760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff191660011785558315610c9757845460ff60401b1916600160401b1785555b6000600155610ca6878761092c565b8315610cec57845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50505050505050565b600080546001600160a01b0319166001600160a01b0383161790556040805160608101909152603680825261188b602083013980519060200120600060146101000a81548163ffffffff021916908360e01c021790555050565b6060813560208301356000610d6685850186611685565b610d75916004916000916116cb565b610d7e916116f5565b604080516001600160a01b03861660208201529081018490526001600160e01b0319821660608201529091506080016040516020818303038152906040529350505050919050565b6000803681610dd96054601487896116cb565b810190610de691906117cd565b9094509250610df885605481896116cb565b949793965094505050565b6000806060818080610e18876004818b6116cb565b810190610e259190611800565b919750955093505050505b9250925092565b600080600080610e478686610f40565b925092509250610e578282610f8a565b5090949350505050565b600060d08265ffffffffffff16901b60a08465ffffffffffff16901b85610e89576000610e8c565b60015b60ff161717949350505050565b610ea282611043565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a2805115610ee7576109a682826110a8565b6102c761111e565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff1661031557604051631afcd79f60e31b815260040160405180910390fd5b6105af610eef565b60008060008351604103610f7a5760208401516040850151606086015160001a610f6c8882858561113d565b955095509550505050610e30565b5050815160009150600290610e30565b6000826003811115610f9e57610f9e611858565b03610fa7575050565b6001826003811115610fbb57610fbb611858565b03610fd95760405163f645eedf60e01b815260040160405180910390fd5b6002826003811115610fed57610fed611858565b0361100e5760405163fce698f760e01b8152600481018290526024016104b7565b600382600381111561102257611022611858565b036102c7576040516335e2f38360e21b8152600481018290526024016104b7565b806001600160a01b03163b60000361107957604051634c9c8ce360e01b81526001600160a01b03821660048201526024016104b7565b6000805160206118c183398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b6060600080846001600160a01b0316846040516110c5919061186e565b600060405180830381855af49150503d8060008114611100576040519150601f19603f3d011682016040523d82523d6000602084013e611105565b606091505b509150915061111585838361120c565b95945050505050565b34156103155760405163b398979f60e01b815260040160405180910390fd5b600080807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411156111785750600091506003905082611202565b604080516000808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa1580156111cc573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166111f857506000925060019150829050611202565b9250600091508190505b9450945094915050565b6060826112215761121c82611268565b610576565b815115801561123857506001600160a01b0384163b155b1561126157604051639996b31560e01b81526001600160a01b03851660048201526024016104b7565b5080610576565b8051156112785780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b60008083601f8401126112a357600080fd5b5081356001600160401b038111156112ba57600080fd5b6020830191508360208260051b85010111156112d557600080fd5b9250929050565b600080602083850312156112ef57600080fd5b82356001600160401b0381111561130557600080fd5b61131185828601611291565b90969095509350505050565b6001600160a01b03811681146105e257600080fd5b634e487b7160e01b600052604160045260246000fd5b600082601f83011261135957600080fd5b81356001600160401b038082111561137357611373611332565b604051601f8301601f19908116603f0116810190828211818310171561139b5761139b611332565b816040528381528660208588010111156113b457600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080604083850312156113e757600080fd5b82356113f28161131d565b915060208301356001600160401b0381111561140d57600080fd5b61141985828601611348565b9150509250929050565b60008060006040848603121561143857600080fd5b83356114438161131d565b925060208401356001600160401b0381111561145e57600080fd5b61146a86828701611291565b9497909650939450505050565b6000610160828403121561148a57600080fd5b50919050565b803565ffffffffffff811681146114a657600080fd5b919050565b6000806000606084860312156114c057600080fd5b83356001600160401b038111156114d657600080fd5b6114e286828701611477565b9350506114f160208501611490565b91506114ff60408501611490565b90509250925092565b6000806000806060858703121561151e57600080fd5b84356003811061152d57600080fd5b935060208501356001600160401b038082111561154957600080fd5b818701915087601f83011261155d57600080fd5b81358181111561156c57600080fd5b88602082850101111561157e57600080fd5b95986020929092019750949560400135945092505050565b60005b838110156115b1578181015183820152602001611599565b50506000910152565b600081518084526115d2816020860160208601611596565b601f01601f19169290920160200192915050565b60208152600061057660208301846115ba565b60006020828403121561160b57600080fd5b81356105768161131d565b60008060006060848603121561162b57600080fd5b83356001600160401b0381111561164157600080fd5b61164d86828701611477565b9660208601359650604090950135949350505050565b60408152600061167660408301856115ba565b90508260208301529392505050565b6000808335601e1984360301811261169c57600080fd5b8301803591506001600160401b038211156116b657600080fd5b6020019150368190038213156112d557600080fd5b600080858511156116db57600080fd5b838611156116e857600080fd5b5050820193919092039150565b6001600160e01b0319813581811691600485101561171d5780818660040360031b1b83161692505b505092915050565b60c08152600061173860c08301896115ba565b6020830197909752506001600160a01b03948516604082015292909316606083015265ffffffffffff908116608083015290911660a090910152919050565b60006001820161179757634e487b7160e01b600052601160045260246000fd5b5060010190565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156117c657600080fd5b5051919050565b600080604083850312156117e057600080fd5b6117e983611490565b91506117f760208401611490565b90509250929050565b60008060006060848603121561181557600080fd5b83356118208161131d565b92506020840135915060408401356001600160401b0381111561184257600080fd5b61184e86828701611348565b9150509250925092565b634e487b7160e01b600052602160045260246000fd5b60008251611880818460208701611596565b919091019291505056fe657865635472616e73616374696f6e46726f6d4d6f64756c6528616464726573732c75696e743235362c62797465732c75696e743829360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca264697066735822122059a67c9925076ac42c5d343ddfed156e2ad9b18dd42613202eb6560fa72069ff64736f6c63430008140033'; +export const PAYMASTER_ABI = [ + { + type: 'function', + name: 'UPGRADE_INTERFACE_VERSION', + inputs: [], + outputs: [ + { + name: '', + type: 'string', + internalType: 'string' + } + ], + stateMutability: 'view' + }, + { + type: 'function', + name: 'getHash', + inputs: [ + { + name: 'userOp', + type: 'tuple', + internalType: 'struct UserOperation', + components: [ + { + name: 'sender', + type: 'address', + internalType: 'address' + }, + { + name: 'nonce', + type: 'uint256', + internalType: 'uint256' + }, + { + name: 'initCode', + type: 'bytes', + internalType: 'bytes' + }, + { + name: 'callData', + type: 'bytes', + internalType: 'bytes' + }, + { + name: 'callGasLimit', + type: 'uint256', + internalType: 'uint256' + }, + { + name: 'verificationGasLimit', + type: 'uint256', + internalType: 'uint256' + }, + { + name: 'preVerificationGas', + type: 'uint256', + internalType: 'uint256' + }, + { + name: 'maxFeePerGas', + type: 'uint256', + internalType: 'uint256' + }, + { + name: 'maxPriorityFeePerGas', + type: 'uint256', + internalType: 'uint256' + }, + { + name: 'paymasterAndData', + type: 'bytes', + internalType: 'bytes' + }, + { + name: 'signature', + type: 'bytes', + internalType: 'bytes' + } + ] + }, + { + name: 'validUntil', + type: 'uint48', + internalType: 'uint48' + }, + { + name: 'validAfter', + type: 'uint48', + internalType: 'uint48' + } + ], + outputs: [ + { + name: '', + type: 'bytes32', + internalType: 'bytes32' + } + ], + stateMutability: 'view' + }, + { + type: 'function', + name: 'initialize', + inputs: [ + { + name: 'aSponsor', + type: 'address', + internalType: 'address' + }, + { + name: 'addresses', + type: 'address[]', + internalType: 'address[]' + } + ], + outputs: [], + stateMutability: 'nonpayable' + }, + { + type: 'function', + name: 'owner', + inputs: [], + outputs: [ + { + name: '', + type: 'address', + internalType: 'address' + } + ], + stateMutability: 'view' + }, + { + type: 'function', + name: 'postOp', + inputs: [ + { + name: 'mode', + type: 'uint8', + internalType: 'enum IPaymaster.PostOpMode' + }, + { + name: 'context', + type: 'bytes', + internalType: 'bytes' + }, + { + name: 'actualGasCost', + type: 'uint256', + internalType: 'uint256' + } + ], + outputs: [], + stateMutability: 'view' + }, + { + type: 'function', + name: 'proxiableUUID', + inputs: [], + outputs: [ + { + name: '', + type: 'bytes32', + internalType: 'bytes32' + } + ], + stateMutability: 'view' + }, + { + type: 'function', + name: 'renounceOwnership', + inputs: [], + outputs: [], + stateMutability: 'nonpayable' + }, + { + type: 'function', + name: 'sponsor', + inputs: [], + outputs: [ + { + name: '', + type: 'address', + internalType: 'address' + } + ], + stateMutability: 'view' + }, + { + type: 'function', + name: 'transferOwnership', + inputs: [ + { + name: 'newOwner', + type: 'address', + internalType: 'address' + } + ], + outputs: [], + stateMutability: 'nonpayable' + }, + { + type: 'function', + name: 'updateSponsor', + inputs: [ + { + name: 'newSponsor', + type: 'address', + internalType: 'address' + } + ], + outputs: [], + stateMutability: 'nonpayable' + }, + { + type: 'function', + name: 'updateWhitelist', + inputs: [ + { + name: 'addresses', + type: 'address[]', + internalType: 'address[]' + } + ], + outputs: [], + stateMutability: 'nonpayable' + }, + { + type: 'function', + name: 'upgradeToAndCall', + inputs: [ + { + name: 'newImplementation', + type: 'address', + internalType: 'address' + }, + { + name: 'data', + type: 'bytes', + internalType: 'bytes' + } + ], + outputs: [], + stateMutability: 'payable' + }, + { + type: 'function', + name: 'validatePaymasterUserOp', + inputs: [ + { + name: 'userOp', + type: 'tuple', + internalType: 'struct UserOperation', + components: [ + { + name: 'sender', + type: 'address', + internalType: 'address' + }, + { + name: 'nonce', + type: 'uint256', + internalType: 'uint256' + }, + { + name: 'initCode', + type: 'bytes', + internalType: 'bytes' + }, + { + name: 'callData', + type: 'bytes', + internalType: 'bytes' + }, + { + name: 'callGasLimit', + type: 'uint256', + internalType: 'uint256' + }, + { + name: 'verificationGasLimit', + type: 'uint256', + internalType: 'uint256' + }, + { + name: 'preVerificationGas', + type: 'uint256', + internalType: 'uint256' + }, + { + name: 'maxFeePerGas', + type: 'uint256', + internalType: 'uint256' + }, + { + name: 'maxPriorityFeePerGas', + type: 'uint256', + internalType: 'uint256' + }, + { + name: 'paymasterAndData', + type: 'bytes', + internalType: 'bytes' + }, + { + name: 'signature', + type: 'bytes', + internalType: 'bytes' + } + ] + }, + { + name: 'userOpHash', + type: 'bytes32', + internalType: 'bytes32' + }, + { + name: 'maxCost', + type: 'uint256', + internalType: 'uint256' + } + ], + outputs: [ + { + name: 'context', + type: 'bytes', + internalType: 'bytes' + }, + { + name: 'validationData', + type: 'uint256', + internalType: 'uint256' + } + ], + stateMutability: 'view' + }, + { + type: 'event', + name: 'Initialized', + inputs: [ + { + name: 'version', + type: 'uint64', + indexed: false, + internalType: 'uint64' + } + ], + anonymous: false + }, + { + type: 'event', + name: 'OwnershipTransferred', + inputs: [ + { + name: 'previousOwner', + type: 'address', + indexed: true, + internalType: 'address' + }, + { + name: 'newOwner', + type: 'address', + indexed: true, + internalType: 'address' + } + ], + anonymous: false + }, + { + type: 'event', + name: 'Upgraded', + inputs: [ + { + name: 'implementation', + type: 'address', + indexed: true, + internalType: 'address' + } + ], + anonymous: false + }, + { + type: 'error', + name: 'AddressEmptyCode', + inputs: [ + { + name: 'target', + type: 'address', + internalType: 'address' + } + ] + }, + { + type: 'error', + name: 'ECDSAInvalidSignature', + inputs: [] + }, + { + type: 'error', + name: 'ECDSAInvalidSignatureLength', + inputs: [ + { + name: 'length', + type: 'uint256', + internalType: 'uint256' + } + ] + }, + { + type: 'error', + name: 'ECDSAInvalidSignatureS', + inputs: [ + { + name: 's', + type: 'bytes32', + internalType: 'bytes32' + } + ] + }, + { + type: 'error', + name: 'ERC1967InvalidImplementation', + inputs: [ + { + name: 'implementation', + type: 'address', + internalType: 'address' + } + ] + }, + { + type: 'error', + name: 'ERC1967NonPayable', + inputs: [] + }, + { + type: 'error', + name: 'FailedInnerCall', + inputs: [] + }, + { + type: 'error', + name: 'InvalidInitialization', + inputs: [] + }, + { + type: 'error', + name: 'NotInitializing', + inputs: [] + }, + { + type: 'error', + name: 'OwnableInvalidOwner', + inputs: [ + { + name: 'owner', + type: 'address', + internalType: 'address' + } + ] + }, + { + type: 'error', + name: 'OwnableUnauthorizedAccount', + inputs: [ + { + name: 'account', + type: 'address', + internalType: 'address' + } + ] + }, + { + type: 'error', + name: 'UUPSUnauthorizedCallContext', + inputs: [] + }, + { + type: 'error', + name: 'UUPSUnsupportedProxiableUUID', + inputs: [ + { + name: 'slot', + type: 'bytes32', + internalType: 'bytes32' + } + ] + } +]; + +export const PAYMASTER_BYTECODE = + '0x60a06040523060805234801561001457600080fd5b5060805161191661003e600039600081816109b6015281816109df0152610b2001526119166000f3fe6080604052600436106100c25760003560e01c8063946d92041161007f578063ad3cb1cc11610059578063ad3cb1cc14610209578063c9a54e2b14610247578063f2fde38b14610267578063f465c77e1461028757600080fd5b8063946d9204146101a857806394e1fc19146101c8578063a9a23409146101e857600080fd5b806335377214146100c75780634f1ef286146100e957806352d1902d146100fc578063715018a61461012457806377c93662146101395780638da5cb5b1461016b575b600080fd5b3480156100d357600080fd5b506100e76100e23660046112dc565b6102b5565b005b6100e76100f73660046113d4565b6102cb565b34801561010857600080fd5b506101116102e6565b6040519081526020015b60405180910390f35b34801561013057600080fd5b506100e7610303565b34801561014557600080fd5b506000546001600160a01b03165b6040516001600160a01b03909116815260200161011b565b34801561017757600080fd5b507f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b0316610153565b3480156101b457600080fd5b506100e76101c3366004611423565b610317565b3480156101d457600080fd5b506101116101e33660046114ab565b61043a565b3480156101f457600080fd5b506100e7610203366004611508565b50505050565b34801561021557600080fd5b5061023a604051806040016040528060058152602001640352e302e360dc1b81525081565b60405161011b91906115e6565b34801561025357600080fd5b506100e76102623660046115f9565b61057d565b34801561027357600080fd5b506100e76102823660046115f9565b6105a7565b34801561029357600080fd5b506102a76102a2366004611616565b6105e5565b60405161011b929190611663565b6102bd6108d1565b6102c7828261092c565b5050565b6102d36109ab565b6102dc82610a50565b6102c78282610a58565b60006102f0610b15565b506000805160206118c183398151915290565b61030b6108d1565b6103156000610b5e565b565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff1615906001600160401b031660008115801561035c5750825b90506000826001600160401b031660011480156103785750303b155b905081158015610386575080155b156103a45760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff1916600117855583156103ce57845460ff60401b1916600160401b1785555b6103d788610bcf565b6103e18787610be0565b6103ea88610cf5565b831561043057845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b5050505050505050565b60008061044a6060860186611685565b610459916004916000916116cb565b610462916116f5565b90506001600160e01b031981166104c05760405162461bcd60e51b815260206004820152601e60248201527f4141323720696e76616c69642066756e6374696f6e2073656c6563746f72000060448201526064015b60405180910390fd5b6000546001600160e01b0319828116600160a01b90920460e01b16146105285760405162461bcd60e51b815260206004820152601e60248201527f4141323720696e76616c69642066756e6374696f6e2073656c6563746f72000060448201526064016104b7565b61053185610d4f565b46306105456000546001600160a01b031690565b878760405160200161055c96959493929190611725565b604051602081830303815290604052805190602001209150505b9392505050565b6105856108d1565b600080546001600160a01b0319166001600160a01b0392909216919091179055565b6105af6108d1565b6001600160a01b0381166105d957604051631e4fbdf760e01b8152600060048201526024016104b7565b6105e281610b5e565b50565b60606000808036816106036105fe6101208b018b611685565b610dc6565b92965090945092509050604081148061061c5750604181145b6106685760405162461bcd60e51b815260206004820152601d60248201527f4141333520696e76616c6964207369676e6174757265206c656e67746800000060448201526064016104b7565b4265ffffffffffff80851690821610156106be5760405162461bcd60e51b8152602060048201526017602482015276414133322065787069726564206f72206e6f742064756560481b60448201526064016104b7565b8465ffffffffffff168165ffffffffffff16106107175760405162461bcd60e51b8152602060048201526017602482015276414133322065787069726564206f72206e6f742064756560481b60448201526064016104b7565b600061072e61072960608d018d611685565b610e03565b50509050600061073c8c3590565b9050806001600160a01b0316826001600160a01b0316148061077757506001546001600160a01b038316600090815260026020526040902054145b6107c35760405162461bcd60e51b815260206004820152601d60248201527f4141333820636f6e7472616374206e6f742077686974656c697374656400000060448201526064016104b7565b60006108066107d38e8a8a61043a565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000006000908152601c91909152603c902090565b905061084a86868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508593925050610e379050565b6001600160a01b03166108656000546001600160a01b031690565b6001600160a01b0316146108a15761087f60018989610e61565b60405180602001604052806000815250909950995050505050505050506108c9565b6108ad60008989610e61565b6040805160208101909152600081529a50985050505050505050505b935093915050565b336109037f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b6001600160a01b0316146103155760405163118cdaa760e01b81523360048201526024016104b7565b6001805490600061093c83611777565b919050555060005b818110156109a657600154600260008585858181106109655761096561179e565b905060200201602081019061097a91906115f9565b6001600160a01b031681526020810191909152604001600020558061099e81611777565b915050610944565b505050565b306001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161480610a3257507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316610a266000805160206118c1833981519152546001600160a01b031690565b6001600160a01b031614155b156103155760405163703e46dd60e11b815260040160405180910390fd5b6105e26108d1565b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015610ab2575060408051601f3d908101601f19168201909252610aaf918101906117b4565b60015b610ada57604051634c9c8ce360e01b81526001600160a01b03831660048201526024016104b7565b6000805160206118c18339815191528114610b0b57604051632a87526960e21b8152600481018290526024016104b7565b6109a68383610e99565b306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146103155760405163703e46dd60e11b815260040160405180910390fd5b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b610bd7610eef565b6105e281610f38565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff1615906001600160401b0316600081158015610c255750825b90506000826001600160401b03166001148015610c415750303b155b905081158015610c4f575080155b15610c6d5760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff191660011785558315610c9757845460ff60401b1916600160401b1785555b6000600155610ca6878761092c565b8315610cec57845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50505050505050565b600080546001600160a01b0319166001600160a01b0383161790556040805160608101909152603680825261188b602083013980519060200120600060146101000a81548163ffffffff021916908360e01c021790555050565b6060813560208301356000610d6685850186611685565b610d75916004916000916116cb565b610d7e916116f5565b604080516001600160a01b03861660208201529081018490526001600160e01b0319821660608201529091506080016040516020818303038152906040529350505050919050565b6000803681610dd96054601487896116cb565b810190610de691906117cd565b9094509250610df885605481896116cb565b949793965094505050565b6000806060818080610e18876004818b6116cb565b810190610e259190611800565b919750955093505050505b9250925092565b600080600080610e478686610f40565b925092509250610e578282610f8a565b5090949350505050565b600060d08265ffffffffffff16901b60a08465ffffffffffff16901b85610e89576000610e8c565b60015b60ff161717949350505050565b610ea282611043565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a2805115610ee7576109a682826110a8565b6102c761111e565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff1661031557604051631afcd79f60e31b815260040160405180910390fd5b6105af610eef565b60008060008351604103610f7a5760208401516040850151606086015160001a610f6c8882858561113d565b955095509550505050610e30565b5050815160009150600290610e30565b6000826003811115610f9e57610f9e611858565b03610fa7575050565b6001826003811115610fbb57610fbb611858565b03610fd95760405163f645eedf60e01b815260040160405180910390fd5b6002826003811115610fed57610fed611858565b0361100e5760405163fce698f760e01b8152600481018290526024016104b7565b600382600381111561102257611022611858565b036102c7576040516335e2f38360e21b8152600481018290526024016104b7565b806001600160a01b03163b60000361107957604051634c9c8ce360e01b81526001600160a01b03821660048201526024016104b7565b6000805160206118c183398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b6060600080846001600160a01b0316846040516110c5919061186e565b600060405180830381855af49150503d8060008114611100576040519150601f19603f3d011682016040523d82523d6000602084013e611105565b606091505b509150915061111585838361120c565b95945050505050565b34156103155760405163b398979f60e01b815260040160405180910390fd5b600080807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411156111785750600091506003905082611202565b604080516000808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa1580156111cc573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166111f857506000925060019150829050611202565b9250600091508190505b9450945094915050565b6060826112215761121c82611268565b610576565b815115801561123857506001600160a01b0384163b155b1561126157604051639996b31560e01b81526001600160a01b03851660048201526024016104b7565b5080610576565b8051156112785780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b60008083601f8401126112a357600080fd5b5081356001600160401b038111156112ba57600080fd5b6020830191508360208260051b85010111156112d557600080fd5b9250929050565b600080602083850312156112ef57600080fd5b82356001600160401b0381111561130557600080fd5b61131185828601611291565b90969095509350505050565b6001600160a01b03811681146105e257600080fd5b634e487b7160e01b600052604160045260246000fd5b600082601f83011261135957600080fd5b81356001600160401b038082111561137357611373611332565b604051601f8301601f19908116603f0116810190828211818310171561139b5761139b611332565b816040528381528660208588010111156113b457600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080604083850312156113e757600080fd5b82356113f28161131d565b915060208301356001600160401b0381111561140d57600080fd5b61141985828601611348565b9150509250929050565b60008060006040848603121561143857600080fd5b83356114438161131d565b925060208401356001600160401b0381111561145e57600080fd5b61146a86828701611291565b9497909650939450505050565b6000610160828403121561148a57600080fd5b50919050565b803565ffffffffffff811681146114a657600080fd5b919050565b6000806000606084860312156114c057600080fd5b83356001600160401b038111156114d657600080fd5b6114e286828701611477565b9350506114f160208501611490565b91506114ff60408501611490565b90509250925092565b6000806000806060858703121561151e57600080fd5b84356003811061152d57600080fd5b935060208501356001600160401b038082111561154957600080fd5b818701915087601f83011261155d57600080fd5b81358181111561156c57600080fd5b88602082850101111561157e57600080fd5b95986020929092019750949560400135945092505050565b60005b838110156115b1578181015183820152602001611599565b50506000910152565b600081518084526115d2816020860160208601611596565b601f01601f19169290920160200192915050565b60208152600061057660208301846115ba565b60006020828403121561160b57600080fd5b81356105768161131d565b60008060006060848603121561162b57600080fd5b83356001600160401b0381111561164157600080fd5b61164d86828701611477565b9660208601359650604090950135949350505050565b60408152600061167660408301856115ba565b90508260208301529392505050565b6000808335601e1984360301811261169c57600080fd5b8301803591506001600160401b038211156116b657600080fd5b6020019150368190038213156112d557600080fd5b600080858511156116db57600080fd5b838611156116e857600080fd5b5050820193919092039150565b6001600160e01b0319813581811691600485101561171d5780818660040360031b1b83161692505b505092915050565b60c08152600061173860c08301896115ba565b6020830197909752506001600160a01b03948516604082015292909316606083015265ffffffffffff908116608083015290911660a090910152919050565b60006001820161179757634e487b7160e01b600052601160045260246000fd5b5060010190565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156117c657600080fd5b5051919050565b600080604083850312156117e057600080fd5b6117e983611490565b91506117f760208401611490565b90509250929050565b60008060006060848603121561181557600080fd5b83356118208161131d565b92506020840135915060408401356001600160401b0381111561184257600080fd5b61184e86828701611348565b9150509250925092565b634e487b7160e01b600052602160045260246000fd5b60008251611880818460208701611596565b919091019291505056fe657865635472616e73616374696f6e46726f6d4d6f64756c6528616464726573732c75696e743235362c62797465732c75696e743829360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca264697066735822122059a67c9925076ac42c5d343ddfed156e2ad9b18dd42613202eb6560fa72069ff64736f6c63430008140033'; diff --git a/app/[alias]/(dashboard)/checkout/contract/profile_contract.ts b/app/[alias]/(dashboard)/checkout/contract/profile_contract.ts index 17b2eb15..b7a246ce 100644 --- a/app/[alias]/(dashboard)/checkout/contract/profile_contract.ts +++ b/app/[alias]/(dashboard)/checkout/contract/profile_contract.ts @@ -1,518 +1,518 @@ -export const PROFILE_ABI = [ - { inputs: [], stateMutability: 'nonpayable', type: 'constructor' }, - { - anonymous: false, - inputs: [ - { - indexed: false, - internalType: 'address', - name: 'previousAdmin', - type: 'address' - }, - { - indexed: false, - internalType: 'address', - name: 'newAdmin', - type: 'address' - } - ], - name: 'AdminChanged', - type: 'event' - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'address', - name: 'owner', - type: 'address' - }, - { - indexed: true, - internalType: 'address', - name: 'approved', - type: 'address' - }, - { - indexed: true, - internalType: 'uint256', - name: 'tokenId', - type: 'uint256' - } - ], - name: 'Approval', - type: 'event' - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'address', - name: 'owner', - type: 'address' - }, - { - indexed: true, - internalType: 'address', - name: 'operator', - type: 'address' - }, - { indexed: false, internalType: 'bool', name: 'approved', type: 'bool' } - ], - name: 'ApprovalForAll', - type: 'event' - }, - { - anonymous: false, - inputs: [ - { - indexed: false, - internalType: 'uint256', - name: '_fromTokenId', - type: 'uint256' - }, - { - indexed: false, - internalType: 'uint256', - name: '_toTokenId', - type: 'uint256' - } - ], - name: 'BatchMetadataUpdate', - type: 'event' - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'address', - name: 'beacon', - type: 'address' - } - ], - name: 'BeaconUpgraded', - type: 'event' - }, - { - anonymous: false, - inputs: [ - { indexed: false, internalType: 'uint8', name: 'version', type: 'uint8' } - ], - name: 'Initialized', - type: 'event' - }, - { - anonymous: false, - inputs: [ - { - indexed: false, - internalType: 'uint256', - name: '_tokenId', - type: 'uint256' - } - ], - name: 'MetadataUpdate', - type: 'event' - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'address', - name: 'previousOwner', - type: 'address' - }, - { - indexed: true, - internalType: 'address', - name: 'newOwner', - type: 'address' - } - ], - name: 'OwnershipTransferred', - type: 'event' - }, - { - anonymous: false, - inputs: [ - { indexed: true, internalType: 'bytes32', name: 'role', type: 'bytes32' }, - { - indexed: true, - internalType: 'bytes32', - name: 'previousAdminRole', - type: 'bytes32' - }, - { - indexed: true, - internalType: 'bytes32', - name: 'newAdminRole', - type: 'bytes32' - } - ], - name: 'RoleAdminChanged', - type: 'event' - }, - { - anonymous: false, - inputs: [ - { indexed: true, internalType: 'bytes32', name: 'role', type: 'bytes32' }, - { - indexed: true, - internalType: 'address', - name: 'account', - type: 'address' - }, - { - indexed: true, - internalType: 'address', - name: 'sender', - type: 'address' - } - ], - name: 'RoleGranted', - type: 'event' - }, - { - anonymous: false, - inputs: [ - { indexed: true, internalType: 'bytes32', name: 'role', type: 'bytes32' }, - { - indexed: true, - internalType: 'address', - name: 'account', - type: 'address' - }, - { - indexed: true, - internalType: 'address', - name: 'sender', - type: 'address' - } - ], - name: 'RoleRevoked', - type: 'event' - }, - { - anonymous: false, - inputs: [ - { indexed: true, internalType: 'address', name: 'from', type: 'address' }, - { indexed: true, internalType: 'address', name: 'to', type: 'address' }, - { - indexed: true, - internalType: 'uint256', - name: 'tokenId', - type: 'uint256' - } - ], - name: 'Transfer', - type: 'event' - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'address', - name: 'implementation', - type: 'address' - } - ], - name: 'Upgraded', - type: 'event' - }, - { - inputs: [], - name: 'DEFAULT_ADMIN_ROLE', - outputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }], - stateMutability: 'view', - type: 'function' - }, - { - inputs: [], - name: 'PROFILE_ADMIN_ROLE', - outputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }], - stateMutability: 'view', - type: 'function' - }, - { - inputs: [ - { internalType: 'address', name: 'to', type: 'address' }, - { internalType: 'uint256', name: 'tokenId', type: 'uint256' } - ], - name: 'approve', - outputs: [], - stateMutability: 'nonpayable', - type: 'function' - }, - { - inputs: [{ internalType: 'address', name: 'owner', type: 'address' }], - name: 'balanceOf', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], - stateMutability: 'view', - type: 'function' - }, - { - inputs: [{ internalType: 'uint256', name: 'tokenId', type: 'uint256' }], - name: 'burn', - outputs: [], - stateMutability: 'nonpayable', - type: 'function' - }, - { - inputs: [{ internalType: 'address', name: 'profile', type: 'address' }], - name: 'fromAddressToId', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], - stateMutability: 'pure', - type: 'function' - }, - { - inputs: [{ internalType: 'uint256', name: 'tokenId', type: 'uint256' }], - name: 'fromIdToAddress', - outputs: [{ internalType: 'address', name: '', type: 'address' }], - stateMutability: 'pure', - type: 'function' - }, - { - inputs: [{ internalType: 'address', name: 'profile', type: 'address' }], - name: 'get', - outputs: [{ internalType: 'string', name: '', type: 'string' }], - stateMutability: 'view', - type: 'function' - }, - { - inputs: [{ internalType: 'uint256', name: 'tokenId', type: 'uint256' }], - name: 'getApproved', - outputs: [{ internalType: 'address', name: '', type: 'address' }], - stateMutability: 'view', - type: 'function' - }, - { - inputs: [{ internalType: 'bytes32', name: 'username', type: 'bytes32' }], - name: 'getFromUsername', - outputs: [{ internalType: 'string', name: '', type: 'string' }], - stateMutability: 'view', - type: 'function' - }, - { - inputs: [{ internalType: 'bytes32', name: 'role', type: 'bytes32' }], - name: 'getRoleAdmin', - outputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }], - stateMutability: 'view', - type: 'function' - }, - { - inputs: [ - { internalType: 'bytes32', name: 'role', type: 'bytes32' }, - { internalType: 'address', name: 'account', type: 'address' } - ], - name: 'grantRole', - outputs: [], - stateMutability: 'nonpayable', - type: 'function' - }, - { - inputs: [ - { internalType: 'bytes32', name: 'role', type: 'bytes32' }, - { internalType: 'address', name: 'account', type: 'address' } - ], - name: 'hasRole', - outputs: [{ internalType: 'bool', name: '', type: 'bool' }], - stateMutability: 'view', - type: 'function' - }, - { - inputs: [{ internalType: 'address', name: '_owner', type: 'address' }], - name: 'initialize', - outputs: [], - stateMutability: 'nonpayable', - type: 'function' - }, - { - inputs: [ - { internalType: 'address', name: 'owner', type: 'address' }, - { internalType: 'address', name: 'operator', type: 'address' } - ], - name: 'isApprovedForAll', - outputs: [{ internalType: 'bool', name: '', type: 'bool' }], - stateMutability: 'view', - type: 'function' - }, - { - inputs: [], - name: 'name', - outputs: [{ internalType: 'string', name: '', type: 'string' }], - stateMutability: 'view', - type: 'function' - }, - { - inputs: [], - name: 'owner', - outputs: [{ internalType: 'address', name: '', type: 'address' }], - stateMutability: 'view', - type: 'function' - }, - { - inputs: [{ internalType: 'uint256', name: 'tokenId', type: 'uint256' }], - name: 'ownerOf', - outputs: [{ internalType: 'address', name: '', type: 'address' }], - stateMutability: 'view', - type: 'function' - }, - { - inputs: [{ internalType: 'bytes32', name: 'username', type: 'bytes32' }], - name: 'profiles', - outputs: [{ internalType: 'address', name: 'profile', type: 'address' }], - stateMutability: 'view', - type: 'function' - }, - { - inputs: [], - name: 'proxiableUUID', - outputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }], - stateMutability: 'view', - type: 'function' - }, - { - inputs: [], - name: 'renounceOwnership', - outputs: [], - stateMutability: 'nonpayable', - type: 'function' - }, - { - inputs: [ - { internalType: 'bytes32', name: 'role', type: 'bytes32' }, - { internalType: 'address', name: 'account', type: 'address' } - ], - name: 'renounceRole', - outputs: [], - stateMutability: 'nonpayable', - type: 'function' - }, - { - inputs: [ - { internalType: 'bytes32', name: 'role', type: 'bytes32' }, - { internalType: 'address', name: 'account', type: 'address' } - ], - name: 'revokeRole', - outputs: [], - stateMutability: 'nonpayable', - type: 'function' - }, - { - inputs: [ - { internalType: 'address', name: 'from', type: 'address' }, - { internalType: 'address', name: 'to', type: 'address' }, - { internalType: 'uint256', name: 'tokenId', type: 'uint256' } - ], - name: 'safeTransferFrom', - outputs: [], - stateMutability: 'nonpayable', - type: 'function' - }, - { - inputs: [ - { internalType: 'address', name: 'from', type: 'address' }, - { internalType: 'address', name: 'to', type: 'address' }, - { internalType: 'uint256', name: 'tokenId', type: 'uint256' }, - { internalType: 'bytes', name: 'data', type: 'bytes' } - ], - name: 'safeTransferFrom', - outputs: [], - stateMutability: 'nonpayable', - type: 'function' - }, - { - inputs: [ - { internalType: 'address', name: 'profile', type: 'address' }, - { internalType: 'bytes32', name: '_username', type: 'bytes32' }, - { internalType: 'string', name: '_uri', type: 'string' } - ], - name: 'set', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], - stateMutability: 'nonpayable', - type: 'function' - }, - { - inputs: [ - { internalType: 'address', name: 'operator', type: 'address' }, - { internalType: 'bool', name: 'approved', type: 'bool' } - ], - name: 'setApprovalForAll', - outputs: [], - stateMutability: 'nonpayable', - type: 'function' - }, - { - inputs: [{ internalType: 'bytes4', name: 'interfaceId', type: 'bytes4' }], - name: 'supportsInterface', - outputs: [{ internalType: 'bool', name: '', type: 'bool' }], - stateMutability: 'view', - type: 'function' - }, - { - inputs: [], - name: 'symbol', - outputs: [{ internalType: 'string', name: '', type: 'string' }], - stateMutability: 'view', - type: 'function' - }, - { - inputs: [{ internalType: 'uint256', name: 'tokenId', type: 'uint256' }], - name: 'tokenURI', - outputs: [{ internalType: 'string', name: '', type: 'string' }], - stateMutability: 'view', - type: 'function' - }, - { - inputs: [ - { internalType: 'address', name: 'from', type: 'address' }, - { internalType: 'address', name: 'to', type: 'address' }, - { internalType: 'uint256', name: 'tokenId', type: 'uint256' } - ], - name: 'transferFrom', - outputs: [], - stateMutability: 'nonpayable', - type: 'function' - }, - { - inputs: [{ internalType: 'address', name: 'newOwner', type: 'address' }], - name: 'transferOwnership', - outputs: [], - stateMutability: 'nonpayable', - type: 'function' - }, - { - inputs: [ - { internalType: 'address', name: 'newImplementation', type: 'address' } - ], - name: 'upgradeTo', - outputs: [], - stateMutability: 'nonpayable', - type: 'function' - }, - { - inputs: [ - { internalType: 'address', name: 'newImplementation', type: 'address' }, - { internalType: 'bytes', name: 'data', type: 'bytes' } - ], - name: 'upgradeToAndCall', - outputs: [], - stateMutability: 'payable', - type: 'function' - }, - { - inputs: [{ internalType: 'address', name: 'profile', type: 'address' }], - name: 'usernames', - outputs: [{ internalType: 'bytes32', name: 'username', type: 'bytes32' }], - stateMutability: 'view', - type: 'function' - } -]; - -export const PROFILE_BYTECODE = - '60a080604052346100dd57306080526000549060ff8260081c1661008b575060ff80821603610050575b604051612e7a9081620000e3823960805181818161128d0152818161137901526118c30152f35b60ff90811916176000557f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498602060405160ff8152a138610029565b62461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b6064820152608490fd5b600080fdfe6080604081815260048036101561001557600080fd5b600092833560e01c90816301ffc9a714611e335750806306fdde0314611d89578063081812fc14611d69578063095ea7b314611bf957806323b872dd14611bcf578063248a9ca314611ba55780632f2ff15d14611af957806336568abe14611a675780633659cfe61461189c57806342842e0e1461187357806342966c68146115d85780634f1ef2861461133a57806352d1902d1461127857806352f33682146112455780635971834a1461120a5780636352211e146111d957806370a0823114611143578063715018a6146110e6578063892195aa146110b85780638da5cb5b1461108f57806391d148541461104957806395d89b4114610f6457806398cd54be14610f3d5780639d91dd7d146109cf578063a217fddf146109b4578063a22cb465146108e7578063b88d4fde14610893578063be83cdc914610812578063c2bc2efc146107e2578063c4d66de81461033b578063c87b56dd14610300578063d547741f146102c5578063e985e9c514610275578063ee91877c146102385763f2fde38b146101a457600080fd5b34610234576020366003190112610234576101bd611f1b565b916101c661246a565b6001600160a01b038316156101e257836101df846124c2565b80f35b906020608492519162461bcd60e51b8352820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152fd5b8280fd5b5050346102715760203660031901126102715760209181906001600160a01b03610260611f1b565b168152610191845220549051908152f35b5080fd5b505034610271578060031936011261027157602091610292611f1b565b8261029b611f36565b9260018060a01b038093168152606a8652209116600052825260ff81600020541690519015158152f35b5090346102345780600319360112610234576101df91356102fb60016102e9611f36565b9383875260fb602052862001546120de565b6123f4565b50913461033857602036600319011261033857506103216103349235612607565b9051918291602083526020830190611ef6565b0390f35b80fd5b503461023457602090816003193601126107de57610357611f1b565b84549060ff91828160081c1615928380946107d2575b80156107bc575b156107625760019460ff19928587858316178b55610751575b5087519061039a82611fcf565b600782526650726f66696c6560c81b888301528851906103b982611fcf565b600382526228292360e91b898301526103e0848c5460081c166103db8161207e565b61207e565b825167ffffffffffffffff9384821161073e5790808d8c9594936104056065546125cd565b601f978882116106f2575b50508d91878411600114610666579261065b575b5050600019600383901b1c1916908a1b176065555b815193841161064857509082918b8a6104536066546125cd565b8481116105f2575b50505089918311600114610573578b92610568575b5050600019600383901b1c191690861b176066555b61049881895460081c166103db8161207e565b6104a1336124c2565b6104b481895460081c166103db8161207e565b87805260fb86528688206001600160a01b0390931660008181529387529287902054161561051e575b50506104e7578380f35b7f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989261ff0019855416855551908152a13880808380f35b86805260fb85528587208260005285528386600020918254161790553390867f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d8180a438806104dd565b015190503880610470565b60668c528893507f46501879b8ca8525e8c2fd519e2fbfcfa2ebea26501294aa02cbfcfb12e943549190601f1984168d5b8c8282106105dc57505084116105c3575b505050811b01606655610485565b015160001960f88460031b161c191690553880806105b5565b8385015186558c979095019493840193016105a4565b60666106379352847f46501879b8ca8525e8c2fd519e2fbfcfa2ebea26501294aa02cbfcfb12e943549181880160051c830193881061063f575b0160051c01906126e5565b8b8a3861045b565b9250819261062c565b634e487b7160e01b8c526041905260248bfd5b015190503880610424565b91908d94508e601f19851690606585527f8ff97419363ffd7000167f130ef7168fbea05faf9251824ca5043f113cc6a7c794905b8282106106d157505084116106b8575b505050811b01606555610439565b015160001960f88460031b161c191690553880806106aa565b91929395968291958786015181550195019301908f918f969594939261069a565b6107379160658552897f8ff97419363ffd7000167f130ef7168fbea05faf9251824ca5043f113cc6a7c79181880160051c830193881061063f570160051c01906126e5565b388e610410565b634e487b7160e01b8d526041835260248dfd5b61ffff19166101011789553861038d565b865162461bcd60e51b8152808601879052602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608490fd5b50303b1580156103745750600181831614610374565b5060018183161061036d565b8380fd5b50503461027157602036600319011261027157610334906103216001600160a01b0361080c611f1b565b16612607565b5082346103385760203660031901126103385781358152610192602052829020546001600160a01b0316908115610850576103348361032184612607565b606490602084519162461bcd60e51b8352820152601d60248201527f5468697320757365726e616d6520646f6573206e6f742065786973742e0000006044820152fd5b838234610271576080366003190112610271576108ae611f1b565b6108b6611f36565b9060643567ffffffffffffffff81116108e3576101df936108d991369101612060565b916044359161298b565b8480fd5b509034610234578060031936011261023457610901611f1b565b90602435918215158093036108e3576001600160a01b0316923384146109725750338452606a602052808420836000526020528060002060ff1981541660ff8416179055519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b6020606492519162461bcd60e51b8352820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152fd5b50503461027157816003193601126102715751908152602090f35b50919034610271576060366003190112610271576109eb611f1b565b92602480359367ffffffffffffffff91604435838111610234573660238201121561023457610a2290369083818801359101612029565b9060018060a01b03978860c9541633148015610f32575b8015610ef4575b15610e9557881696878452610191602099818b5288862054908115908b8280610e66575b8315610e3b575b50505015610df95760008a8152606760205260409020546001600160a01b031615610d08575b8203610cae575b5050610aa387612607565b8651610acb8a8281610abe8183019687815193849201611ed3565b8101038084520182611feb565b519020865189810190610ae88b828751610abe8187858c01611ed3565b51902003610afa575b87878751908152f35b6000878152606760205260409020546001600160a01b031615610c565786835260978852858320948251948511610c45575050908291610b3a85546125cd565b601f8111610c0c575b508791601f8411600114610ba95792610b9e575b50508160011b916000199060031b1c19161790555b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7838251848152a13880808080610af1565b015190503880610b57565b8581528881209350601f198516905b89828210610bf6575050908460019594939210610bdd575b505050811b019055610b6c565b015160001960f88460031b161c19169055388080610bd0565b6001859682939686015181550195019301610bb8565b610c3590868452898420601f860160051c8101918b8710610c3b575b601f0160051c01906126e5565b38610b43565b9091508190610c28565b634e487b7160e01b84526041905282fd5b84602e6084928a89519362461bcd60e51b85528401528201527f45524337323155524953746f726167653a2055524920736574206f66206e6f6e60448201526d32bc34b9ba32b73a103a37b5b2b760911b6064820152fd5b888552808a528785205480610cea575b508185526101928a5287852080546001600160a01b0319168a1790558885528952868420553880610a98565b85526101928a5287852080546001600160a01b031916905538610cbe565b948915610db95760008a815260676020526040902054839190610d37906001600160a01b031615155b15612a84565b60008b815260676020526040902054909690610d5d906001600160a01b03161515610d31565b8a60005260688c52896000206001815401905560678c52896000208b6001600160601b0360a01b8254161790558a8060007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a49050610a91565b6064888c86818d519362461bcd60e51b85528401528201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152fd5b885162461bcd60e51b81528089018c9052601f818601527f5468697320757365726e616d6520697320616c72656164792074616b656e2e006044820152606490fd5b1592509082610e4f575b5050388b81610a6b565b8389526101928e528b892054161490508a38610e45565b9250508488526101928d528b818c8a205416818115918215610e8b575b505092610a64565b1490508138610e83565b865162461bcd60e51b81526020818801526034818401527f4f6e6c79207468652070726f66696c65206f776e6572206f7220636f6e74726160448201527331ba1037bbb732b91031b0b71039b2ba1034ba1760611b6064820152608490fd5b507f224b562a599bb6f57441f98a50de513dff0de3d9b620f342c27a4e4a898ce8e2845260fb60205286842033855260205260ff8785205416610a40565b503389821614610a39565b509034610234576020366003190112610234575190356001600160a01b0316815260209150f35b50503461027157816003193601126102715780519082606654610f86816125cd565b808552916001918083169081156110215750600114610fc4575b505050610fb282610334940383611feb565b51918291602083526020830190611ef6565b9450606685527f46501879b8ca8525e8c2fd519e2fbfcfa2ebea26501294aa02cbfcfb12e943545b82861061100957505050610fb28260206103349582010194610fa0565b80546020878701810191909152909501948101610fec565b610334975086935060209250610fb294915060ff191682840152151560051b82010194610fa0565b50346102345781600319360112610234578160209360ff92611069611f36565b9035825260fb86528282206001600160a01b039091168252855220549151911615158152f35b50503461027157816003193601126102715760c95490516001600160a01b039091168152602090f35b505034610271576020366003190112610271576020906001600160a01b036110de611f1b565b169051908152f35b83346103385780600319360112610338576110ff61246a565b60c980546001600160a01b0319811690915581906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b50829034610271576020366003190112610271576001600160a01b03611167611f1b565b169081156111845760208480858581526068845220549051908152f35b608490602085519162461bcd60e51b8352820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b6064820152fd5b50913461033857602036600319011261033857506111f9602092356128c8565b90516001600160a01b039091168152f35b505034610271578160031936011261027157602090517f224b562a599bb6f57441f98a50de513dff0de3d9b620f342c27a4e4a898ce8e28152f35b5034610234576020366003190112610234573582526101926020908152918190205490516001600160a01b039091168152f35b508234610338578060031936011261033857507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031630036112d25760208251600080516020612e258339815191528152f35b6020608492519162461bcd60e51b8352820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152fd5b5090806003193601126102345761134f611f1b565b9060243567ffffffffffffffff81116108e35761136f9036908501612060565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081169291906113a93085141561250b565b6113c6600080516020612e2583398151915294828654161461256c565b6113ce61246a565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff161561140657505050506101df9150612723565b8491929394168351946352d1902d60e01b865260209586818981865afa8991816115a5575b5061148a57855162461bcd60e51b8152808901889052602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608490fd5b969192949593960361155057509085916114a384612723565b7fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b8380a2845115801590611548575b6114df575b505050505080f35b61153d948291660819985a5b195960ca1b8651966114fc88611fb3565b602788527f416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c8389015287015281519101845af46115376127b3565b916127e3565b5038808083816114d7565b5060016114d2565b845162461bcd60e51b8152908101839052602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608490fd5b9091508781813d83116115d1575b6115bd8183611feb565b810103126115cd5751903861142b565b8980fd5b503d6115b3565b5091903461027157602090816003193601126102345760c9546001600160a01b0385358181169690923390831614801561186a575b801561182e575b156117cf578686526101918086528487205487526101928652848720976001600160601b0360a01b9889815416905587528552858481205581611656846128c8565b161580156117c7575b1561173857508480968392611673846128c8565b848452606988528684208381541690551690818352606887528583206000198154019055838352606787528583209081541690557fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4609783526116db828520546125cd565b6116e457505050f35b8352609782528220906116f782546125cd565b908161170257505050f35b8390601f8311600114611716575050505580f35b838252812092909161173390601f0160051c8401600185016126e5565b555580f35b835162461bcd60e51b8152908101859052605b60248201527f54686973206120536f756c626f756e6420746f6b656e2e2049742063616e6e6f60448201527f74206265207472616e736665727265642e2049742063616e206f6e6c7920626560648201527f206275726e65642062792074686520746f6b656e206f776e65722e0000000000608482015260a490fd5b50600161165f565b835162461bcd60e51b8152908101859052603360248201527f4f6e6c7920746865206f776e6572206f662074686520746f6b656e206f7220706044820152723937b334b6329031b0b710313ab9371034ba1760691b6064820152608490fd5b507f224b562a599bb6f57441f98a50de513dff0de3d9b620f342c27a4e4a898ce8e2865260fb8552838620338752855260ff8487205416611614565b5033871461160d565b505034610271576101df9061188736611f4c565b9192519261189484611f81565b85845261298b565b509034610234576020806003193601126107de576118b8611f1b565b916001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166118f03082141561250b565b61190d600080516020612e2583398151915291838354161461256c565b61191561246a565b82519161192183611f81565b8783527f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff161561195d5750505050506101df9150612723565b8592939495169084516352d1902d60e01b815286818981865afa899181611a38575b506119de57855162461bcd60e51b8152808901889052602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608490fd5b969192949593960361155057509085916119f784612723565b7fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b8380a2845115801590611a31576114df57505050505080f35b50816114d2565b9091508781813d8311611a60575b611a508183611feb565b810103126115cd5751903861197f565b503d611a46565b50829034610271578260031936011261027157611a82611f36565b90336001600160a01b03831603611a9e57906101df91356123f4565b608490602085519162461bcd60e51b8352820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152fd5b50346102345781600319360112610234573590611b14611f36565b9082845260fb602052611b2c600182862001546120de565b82845260fb60209081528185206001600160a01b039093168086529290528084205460ff1615611b5a578380f35b82845260fb6020528084208285526020528320600160ff1982541617905533917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d8480a43880808380f35b5034610234576020366003190112610234578160209360019235815260fb85522001549051908152f35b8334610338576101df611be136611f4c565b91611bf4611bef8433612a16565b612929565b612b2a565b5034610234578160031936011261023457611c12611f1b565b6024359290916001600160a01b0391908280611c2d876128c8565b16941693808514611d1c57803314908115611cfd575b5015611c9557508385526069602052842080546001600160a01b03191683179055611c6d836128c8565b167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258480a480f35b6020608492519162461bcd60e51b8352820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c0000006064820152fd5b90508652606a60205281862033875260205260ff828720541638611c43565b506020608492519162461bcd60e51b8352820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b6064820152fd5b50913461033857602036600319011261033857506111f9602092356128eb565b50503461027157816003193601126102715780519082606554611dab816125cd565b808552916001918083169081156110215750600114611dd657505050610fb282610334940383611feb565b9450606585527f8ff97419363ffd7000167f130ef7168fbea05faf9251824ca5043f113cc6a7c75b828610611e1b57505050610fb28260206103349582010194610fa0565b80546020878701810191909152909501948101611dfe565b92505034610234576020366003190112610234573563ffffffff60e01b81168091036102345760209250637965db0b60e01b8114908115611e76575b5015158152f35b632483248360e11b811491508115611e90575b5038611e6f565b6380ac58cd60e01b811491508115611ec2575b8115611eb1575b5038611e89565b6301ffc9a760e01b14905038611eaa565b635b5e139f60e01b81149150611ea3565b60005b838110611ee65750506000910152565b8181015183820152602001611ed6565b90602091611f0f81518092818552858086019101611ed3565b601f01601f1916010190565b600435906001600160a01b0382168203611f3157565b600080fd5b602435906001600160a01b0382168203611f3157565b6060906003190112611f31576001600160a01b03906004358281168103611f3157916024359081168103611f31579060443590565b6020810190811067ffffffffffffffff821117611f9d57604052565b634e487b7160e01b600052604160045260246000fd5b6060810190811067ffffffffffffffff821117611f9d57604052565b6040810190811067ffffffffffffffff821117611f9d57604052565b90601f8019910116810190811067ffffffffffffffff821117611f9d57604052565b67ffffffffffffffff8111611f9d57601f01601f191660200190565b9291926120358261200d565b916120436040519384611feb565b829481845281830111611f31578281602093846000960137010152565b9080601f83011215611f315781602061207b93359101612029565b90565b1561208557565b60405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608490fd5b60009080825260209060fb8252604092838120338252835260ff8482205416156121085750505050565b3384519261211584611fb3565b602a845284840190863683378451156123e057603082538451926001938410156123cc576078602187015360295b8481116123625750612320578651926080840184811067ffffffffffffffff82111761230c578852604284528684019460603687378451156122f8576030865384518210156122f85790607860218601536041915b81831161228a5750505061224857612244938693612228936122196048946121f09a519a8b957f416363657373436f6e74726f6c3a206163636f756e74200000000000000000008c8801525180926037880190611ed3565b8401917001034b99036b4b9b9b4b733903937b6329607d1b603784015251809386840190611ed3565b01036028810187520185611feb565b5192839262461bcd60e51b845260048401526024830190611ef6565b0390fd5b60648587519062461bcd60e51b825280600483015260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152fd5b909192600f811660108110156122e4576f181899199a1a9b1b9c1cb0b131b232b360811b901a6122ba85886126fc565b5360041c9280156122d057600019019190612198565b634e487b7160e01b82526011600452602482fd5b634e487b7160e01b83526032600452602483fd5b634e487b7160e01b81526032600452602490fd5b634e487b7160e01b86526041600452602486fd5b60648688519062461bcd60e51b825280600483015260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152fd5b90600f811660108110156123b8576f181899199a1a9b1b9c1cb0b131b232b360811b901a61239083896126fc565b5360041c9080156123a45760001901612143565b634e487b7160e01b86526011600452602486fd5b634e487b7160e01b87526032600452602487fd5b634e487b7160e01b85526032600452602485fd5b634e487b7160e01b84526032600452602484fd5b9060009180835260fb602052604083209160018060a01b03169182845260205260ff60408420541661242557505050565b80835260fb602052604083208284526020526040832060ff1981541690557ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b339380a4565b60c9546001600160a01b0316330361247e57565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b60c980546001600160a01b039283166001600160a01b0319821681179092559091167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3565b1561251257565b60405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201526b19195b1959d85d1958d85b1b60a21b6064820152608490fd5b1561257357565b60405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201526b6163746976652070726f787960a01b6064820152608490fd5b90600182811c921680156125fd575b60208310146125e757565b634e487b7160e01b600052602260045260246000fd5b91607f16916125dc565b60008181526067602052604090205461262a906001600160a01b0316151561287c565b600090815260209060978252604081209160405180938390805461264d816125cd565b808552916001918083169081156126c35750600114612686575b50505061267692500383611feb565b60405161268281611f81565b5290565b86528486209492508591905b8183106126ab5750506126769350820101388080612667565b85548884018501529485019487945091830191612692565b9250505061267694925060ff191682840152151560051b820101388080612667565b8181106126f0575050565b600081556001016126e5565b90815181101561270d570160200190565b634e487b7160e01b600052603260045260246000fd5b803b1561275857600080516020612e2583398151915280546001600160a01b0319166001600160a01b03909216919091179055565b60405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608490fd5b3d156127de573d906127c48261200d565b916127d26040519384611feb565b82523d6000602084013e565b606090565b9192901561284557508151156127f7575090565b3b156128005790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b8251909150156128585750805190602001fd5b60405162461bcd60e51b815260206004820152908190612244906024830190611ef6565b1561288357565b60405162461bcd60e51b815260206004820152601860248201527f4552433732313a20696e76616c696420746f6b656e20494400000000000000006044820152606490fd5b6000908152606760205260409020546001600160a01b031661207b81151561287c565b60008181526067602052604090205461290e906001600160a01b0316151561287c565b6000908152606960205260409020546001600160a01b031690565b1561293057565b60405162461bcd60e51b815260206004820152602d60248201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560448201526c1c881bdc88185c1c1c9bdd9959609a1b6064820152608490fd5b906129af93929161299f611bef8433612a16565b6129aa838383612b2a565b612ce2565b156129b657565b60405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b6064820152608490fd5b906001600160a01b038080612a2a846128c8565b16931691838314938415612a5d575b508315612a47575b50505090565b612a53919293506128eb565b1614388080612a41565b909350600052606a60205260406000208260005260205260ff604060002054169238612a39565b15612a8b57565b60405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606490fd5b15612ad757565b60405162461bcd60e51b815260206004820152602560248201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060448201526437bbb732b960d91b6064820152608490fd5b90612b5291612b38846128c8565b6001600160a01b0393918416928492909183168414612ad0565b16918215612c915781158015612c89575b15612bf85781612b7d91612b76866128c8565b1614612ad0565b7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60008481526069602052604081206001600160601b0360a01b9081815416905583825260686020526040822060001981540190558482526040822060018154019055858252606760205284604083209182541617905580a4565b60405162461bcd60e51b815260206004820152605b60248201527f54686973206120536f756c626f756e6420746f6b656e2e2049742063616e6e6f60448201527f74206265207472616e736665727265642e2049742063616e206f6e6c7920626560648201527f206275726e65642062792074686520746f6b656e206f776e65722e0000000000608482015260a490fd5b506000612b63565b60405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b6064820152608490fd5b919290803b15612e1b57604051630a85bd0160e11b8082523360048301526001600160a01b03948516602483015260448201959095526080606482015291602091839182908190612d37906084830190611ef6565b03916000968791165af190829082612dd3575b5050612dc557612d586127b3565b80519081612dc05760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b6064820152608490fd5b602001fd5b6001600160e01b0319161490565b909192506020813d8211612e13575b81612def60209383611feb565b810103126102715751906001600160e01b0319821682036103385750903880612d4a565b3d9150612de2565b5050505060019056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca2646970667358221220e8f7685d818a5268c65c5d1c6649912a27067099631f54badf6551d90a84ff8264736f6c63430008140033'; +export const PROFILE_ABI = [ + { inputs: [], stateMutability: 'nonpayable', type: 'constructor' }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'address', + name: 'previousAdmin', + type: 'address' + }, + { + indexed: false, + internalType: 'address', + name: 'newAdmin', + type: 'address' + } + ], + name: 'AdminChanged', + type: 'event' + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'owner', + type: 'address' + }, + { + indexed: true, + internalType: 'address', + name: 'approved', + type: 'address' + }, + { + indexed: true, + internalType: 'uint256', + name: 'tokenId', + type: 'uint256' + } + ], + name: 'Approval', + type: 'event' + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'owner', + type: 'address' + }, + { + indexed: true, + internalType: 'address', + name: 'operator', + type: 'address' + }, + { indexed: false, internalType: 'bool', name: 'approved', type: 'bool' } + ], + name: 'ApprovalForAll', + type: 'event' + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'uint256', + name: '_fromTokenId', + type: 'uint256' + }, + { + indexed: false, + internalType: 'uint256', + name: '_toTokenId', + type: 'uint256' + } + ], + name: 'BatchMetadataUpdate', + type: 'event' + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'beacon', + type: 'address' + } + ], + name: 'BeaconUpgraded', + type: 'event' + }, + { + anonymous: false, + inputs: [ + { indexed: false, internalType: 'uint8', name: 'version', type: 'uint8' } + ], + name: 'Initialized', + type: 'event' + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'uint256', + name: '_tokenId', + type: 'uint256' + } + ], + name: 'MetadataUpdate', + type: 'event' + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'previousOwner', + type: 'address' + }, + { + indexed: true, + internalType: 'address', + name: 'newOwner', + type: 'address' + } + ], + name: 'OwnershipTransferred', + type: 'event' + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: 'bytes32', name: 'role', type: 'bytes32' }, + { + indexed: true, + internalType: 'bytes32', + name: 'previousAdminRole', + type: 'bytes32' + }, + { + indexed: true, + internalType: 'bytes32', + name: 'newAdminRole', + type: 'bytes32' + } + ], + name: 'RoleAdminChanged', + type: 'event' + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: 'bytes32', name: 'role', type: 'bytes32' }, + { + indexed: true, + internalType: 'address', + name: 'account', + type: 'address' + }, + { + indexed: true, + internalType: 'address', + name: 'sender', + type: 'address' + } + ], + name: 'RoleGranted', + type: 'event' + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: 'bytes32', name: 'role', type: 'bytes32' }, + { + indexed: true, + internalType: 'address', + name: 'account', + type: 'address' + }, + { + indexed: true, + internalType: 'address', + name: 'sender', + type: 'address' + } + ], + name: 'RoleRevoked', + type: 'event' + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: 'address', name: 'from', type: 'address' }, + { indexed: true, internalType: 'address', name: 'to', type: 'address' }, + { + indexed: true, + internalType: 'uint256', + name: 'tokenId', + type: 'uint256' + } + ], + name: 'Transfer', + type: 'event' + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'implementation', + type: 'address' + } + ], + name: 'Upgraded', + type: 'event' + }, + { + inputs: [], + name: 'DEFAULT_ADMIN_ROLE', + outputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }], + stateMutability: 'view', + type: 'function' + }, + { + inputs: [], + name: 'PROFILE_ADMIN_ROLE', + outputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }], + stateMutability: 'view', + type: 'function' + }, + { + inputs: [ + { internalType: 'address', name: 'to', type: 'address' }, + { internalType: 'uint256', name: 'tokenId', type: 'uint256' } + ], + name: 'approve', + outputs: [], + stateMutability: 'nonpayable', + type: 'function' + }, + { + inputs: [{ internalType: 'address', name: 'owner', type: 'address' }], + name: 'balanceOf', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function' + }, + { + inputs: [{ internalType: 'uint256', name: 'tokenId', type: 'uint256' }], + name: 'burn', + outputs: [], + stateMutability: 'nonpayable', + type: 'function' + }, + { + inputs: [{ internalType: 'address', name: 'profile', type: 'address' }], + name: 'fromAddressToId', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'pure', + type: 'function' + }, + { + inputs: [{ internalType: 'uint256', name: 'tokenId', type: 'uint256' }], + name: 'fromIdToAddress', + outputs: [{ internalType: 'address', name: '', type: 'address' }], + stateMutability: 'pure', + type: 'function' + }, + { + inputs: [{ internalType: 'address', name: 'profile', type: 'address' }], + name: 'get', + outputs: [{ internalType: 'string', name: '', type: 'string' }], + stateMutability: 'view', + type: 'function' + }, + { + inputs: [{ internalType: 'uint256', name: 'tokenId', type: 'uint256' }], + name: 'getApproved', + outputs: [{ internalType: 'address', name: '', type: 'address' }], + stateMutability: 'view', + type: 'function' + }, + { + inputs: [{ internalType: 'bytes32', name: 'username', type: 'bytes32' }], + name: 'getFromUsername', + outputs: [{ internalType: 'string', name: '', type: 'string' }], + stateMutability: 'view', + type: 'function' + }, + { + inputs: [{ internalType: 'bytes32', name: 'role', type: 'bytes32' }], + name: 'getRoleAdmin', + outputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }], + stateMutability: 'view', + type: 'function' + }, + { + inputs: [ + { internalType: 'bytes32', name: 'role', type: 'bytes32' }, + { internalType: 'address', name: 'account', type: 'address' } + ], + name: 'grantRole', + outputs: [], + stateMutability: 'nonpayable', + type: 'function' + }, + { + inputs: [ + { internalType: 'bytes32', name: 'role', type: 'bytes32' }, + { internalType: 'address', name: 'account', type: 'address' } + ], + name: 'hasRole', + outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + stateMutability: 'view', + type: 'function' + }, + { + inputs: [{ internalType: 'address', name: '_owner', type: 'address' }], + name: 'initialize', + outputs: [], + stateMutability: 'nonpayable', + type: 'function' + }, + { + inputs: [ + { internalType: 'address', name: 'owner', type: 'address' }, + { internalType: 'address', name: 'operator', type: 'address' } + ], + name: 'isApprovedForAll', + outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + stateMutability: 'view', + type: 'function' + }, + { + inputs: [], + name: 'name', + outputs: [{ internalType: 'string', name: '', type: 'string' }], + stateMutability: 'view', + type: 'function' + }, + { + inputs: [], + name: 'owner', + outputs: [{ internalType: 'address', name: '', type: 'address' }], + stateMutability: 'view', + type: 'function' + }, + { + inputs: [{ internalType: 'uint256', name: 'tokenId', type: 'uint256' }], + name: 'ownerOf', + outputs: [{ internalType: 'address', name: '', type: 'address' }], + stateMutability: 'view', + type: 'function' + }, + { + inputs: [{ internalType: 'bytes32', name: 'username', type: 'bytes32' }], + name: 'profiles', + outputs: [{ internalType: 'address', name: 'profile', type: 'address' }], + stateMutability: 'view', + type: 'function' + }, + { + inputs: [], + name: 'proxiableUUID', + outputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }], + stateMutability: 'view', + type: 'function' + }, + { + inputs: [], + name: 'renounceOwnership', + outputs: [], + stateMutability: 'nonpayable', + type: 'function' + }, + { + inputs: [ + { internalType: 'bytes32', name: 'role', type: 'bytes32' }, + { internalType: 'address', name: 'account', type: 'address' } + ], + name: 'renounceRole', + outputs: [], + stateMutability: 'nonpayable', + type: 'function' + }, + { + inputs: [ + { internalType: 'bytes32', name: 'role', type: 'bytes32' }, + { internalType: 'address', name: 'account', type: 'address' } + ], + name: 'revokeRole', + outputs: [], + stateMutability: 'nonpayable', + type: 'function' + }, + { + inputs: [ + { internalType: 'address', name: 'from', type: 'address' }, + { internalType: 'address', name: 'to', type: 'address' }, + { internalType: 'uint256', name: 'tokenId', type: 'uint256' } + ], + name: 'safeTransferFrom', + outputs: [], + stateMutability: 'nonpayable', + type: 'function' + }, + { + inputs: [ + { internalType: 'address', name: 'from', type: 'address' }, + { internalType: 'address', name: 'to', type: 'address' }, + { internalType: 'uint256', name: 'tokenId', type: 'uint256' }, + { internalType: 'bytes', name: 'data', type: 'bytes' } + ], + name: 'safeTransferFrom', + outputs: [], + stateMutability: 'nonpayable', + type: 'function' + }, + { + inputs: [ + { internalType: 'address', name: 'profile', type: 'address' }, + { internalType: 'bytes32', name: '_username', type: 'bytes32' }, + { internalType: 'string', name: '_uri', type: 'string' } + ], + name: 'set', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'nonpayable', + type: 'function' + }, + { + inputs: [ + { internalType: 'address', name: 'operator', type: 'address' }, + { internalType: 'bool', name: 'approved', type: 'bool' } + ], + name: 'setApprovalForAll', + outputs: [], + stateMutability: 'nonpayable', + type: 'function' + }, + { + inputs: [{ internalType: 'bytes4', name: 'interfaceId', type: 'bytes4' }], + name: 'supportsInterface', + outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + stateMutability: 'view', + type: 'function' + }, + { + inputs: [], + name: 'symbol', + outputs: [{ internalType: 'string', name: '', type: 'string' }], + stateMutability: 'view', + type: 'function' + }, + { + inputs: [{ internalType: 'uint256', name: 'tokenId', type: 'uint256' }], + name: 'tokenURI', + outputs: [{ internalType: 'string', name: '', type: 'string' }], + stateMutability: 'view', + type: 'function' + }, + { + inputs: [ + { internalType: 'address', name: 'from', type: 'address' }, + { internalType: 'address', name: 'to', type: 'address' }, + { internalType: 'uint256', name: 'tokenId', type: 'uint256' } + ], + name: 'transferFrom', + outputs: [], + stateMutability: 'nonpayable', + type: 'function' + }, + { + inputs: [{ internalType: 'address', name: 'newOwner', type: 'address' }], + name: 'transferOwnership', + outputs: [], + stateMutability: 'nonpayable', + type: 'function' + }, + { + inputs: [ + { internalType: 'address', name: 'newImplementation', type: 'address' } + ], + name: 'upgradeTo', + outputs: [], + stateMutability: 'nonpayable', + type: 'function' + }, + { + inputs: [ + { internalType: 'address', name: 'newImplementation', type: 'address' }, + { internalType: 'bytes', name: 'data', type: 'bytes' } + ], + name: 'upgradeToAndCall', + outputs: [], + stateMutability: 'payable', + type: 'function' + }, + { + inputs: [{ internalType: 'address', name: 'profile', type: 'address' }], + name: 'usernames', + outputs: [{ internalType: 'bytes32', name: 'username', type: 'bytes32' }], + stateMutability: 'view', + type: 'function' + } +]; + +export const PROFILE_BYTECODE = + '60a080604052346100dd57306080526000549060ff8260081c1661008b575060ff80821603610050575b604051612e7a9081620000e3823960805181818161128d0152818161137901526118c30152f35b60ff90811916176000557f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498602060405160ff8152a138610029565b62461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b6064820152608490fd5b600080fdfe6080604081815260048036101561001557600080fd5b600092833560e01c90816301ffc9a714611e335750806306fdde0314611d89578063081812fc14611d69578063095ea7b314611bf957806323b872dd14611bcf578063248a9ca314611ba55780632f2ff15d14611af957806336568abe14611a675780633659cfe61461189c57806342842e0e1461187357806342966c68146115d85780634f1ef2861461133a57806352d1902d1461127857806352f33682146112455780635971834a1461120a5780636352211e146111d957806370a0823114611143578063715018a6146110e6578063892195aa146110b85780638da5cb5b1461108f57806391d148541461104957806395d89b4114610f6457806398cd54be14610f3d5780639d91dd7d146109cf578063a217fddf146109b4578063a22cb465146108e7578063b88d4fde14610893578063be83cdc914610812578063c2bc2efc146107e2578063c4d66de81461033b578063c87b56dd14610300578063d547741f146102c5578063e985e9c514610275578063ee91877c146102385763f2fde38b146101a457600080fd5b34610234576020366003190112610234576101bd611f1b565b916101c661246a565b6001600160a01b038316156101e257836101df846124c2565b80f35b906020608492519162461bcd60e51b8352820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152fd5b8280fd5b5050346102715760203660031901126102715760209181906001600160a01b03610260611f1b565b168152610191845220549051908152f35b5080fd5b505034610271578060031936011261027157602091610292611f1b565b8261029b611f36565b9260018060a01b038093168152606a8652209116600052825260ff81600020541690519015158152f35b5090346102345780600319360112610234576101df91356102fb60016102e9611f36565b9383875260fb602052862001546120de565b6123f4565b50913461033857602036600319011261033857506103216103349235612607565b9051918291602083526020830190611ef6565b0390f35b80fd5b503461023457602090816003193601126107de57610357611f1b565b84549060ff91828160081c1615928380946107d2575b80156107bc575b156107625760019460ff19928587858316178b55610751575b5087519061039a82611fcf565b600782526650726f66696c6560c81b888301528851906103b982611fcf565b600382526228292360e91b898301526103e0848c5460081c166103db8161207e565b61207e565b825167ffffffffffffffff9384821161073e5790808d8c9594936104056065546125cd565b601f978882116106f2575b50508d91878411600114610666579261065b575b5050600019600383901b1c1916908a1b176065555b815193841161064857509082918b8a6104536066546125cd565b8481116105f2575b50505089918311600114610573578b92610568575b5050600019600383901b1c191690861b176066555b61049881895460081c166103db8161207e565b6104a1336124c2565b6104b481895460081c166103db8161207e565b87805260fb86528688206001600160a01b0390931660008181529387529287902054161561051e575b50506104e7578380f35b7f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989261ff0019855416855551908152a13880808380f35b86805260fb85528587208260005285528386600020918254161790553390867f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d8180a438806104dd565b015190503880610470565b60668c528893507f46501879b8ca8525e8c2fd519e2fbfcfa2ebea26501294aa02cbfcfb12e943549190601f1984168d5b8c8282106105dc57505084116105c3575b505050811b01606655610485565b015160001960f88460031b161c191690553880806105b5565b8385015186558c979095019493840193016105a4565b60666106379352847f46501879b8ca8525e8c2fd519e2fbfcfa2ebea26501294aa02cbfcfb12e943549181880160051c830193881061063f575b0160051c01906126e5565b8b8a3861045b565b9250819261062c565b634e487b7160e01b8c526041905260248bfd5b015190503880610424565b91908d94508e601f19851690606585527f8ff97419363ffd7000167f130ef7168fbea05faf9251824ca5043f113cc6a7c794905b8282106106d157505084116106b8575b505050811b01606555610439565b015160001960f88460031b161c191690553880806106aa565b91929395968291958786015181550195019301908f918f969594939261069a565b6107379160658552897f8ff97419363ffd7000167f130ef7168fbea05faf9251824ca5043f113cc6a7c79181880160051c830193881061063f570160051c01906126e5565b388e610410565b634e487b7160e01b8d526041835260248dfd5b61ffff19166101011789553861038d565b865162461bcd60e51b8152808601879052602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608490fd5b50303b1580156103745750600181831614610374565b5060018183161061036d565b8380fd5b50503461027157602036600319011261027157610334906103216001600160a01b0361080c611f1b565b16612607565b5082346103385760203660031901126103385781358152610192602052829020546001600160a01b0316908115610850576103348361032184612607565b606490602084519162461bcd60e51b8352820152601d60248201527f5468697320757365726e616d6520646f6573206e6f742065786973742e0000006044820152fd5b838234610271576080366003190112610271576108ae611f1b565b6108b6611f36565b9060643567ffffffffffffffff81116108e3576101df936108d991369101612060565b916044359161298b565b8480fd5b509034610234578060031936011261023457610901611f1b565b90602435918215158093036108e3576001600160a01b0316923384146109725750338452606a602052808420836000526020528060002060ff1981541660ff8416179055519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a380f35b6020606492519162461bcd60e51b8352820152601960248201527f4552433732313a20617070726f766520746f2063616c6c6572000000000000006044820152fd5b50503461027157816003193601126102715751908152602090f35b50919034610271576060366003190112610271576109eb611f1b565b92602480359367ffffffffffffffff91604435838111610234573660238201121561023457610a2290369083818801359101612029565b9060018060a01b03978860c9541633148015610f32575b8015610ef4575b15610e9557881696878452610191602099818b5288862054908115908b8280610e66575b8315610e3b575b50505015610df95760008a8152606760205260409020546001600160a01b031615610d08575b8203610cae575b5050610aa387612607565b8651610acb8a8281610abe8183019687815193849201611ed3565b8101038084520182611feb565b519020865189810190610ae88b828751610abe8187858c01611ed3565b51902003610afa575b87878751908152f35b6000878152606760205260409020546001600160a01b031615610c565786835260978852858320948251948511610c45575050908291610b3a85546125cd565b601f8111610c0c575b508791601f8411600114610ba95792610b9e575b50508160011b916000199060031b1c19161790555b7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7838251848152a13880808080610af1565b015190503880610b57565b8581528881209350601f198516905b89828210610bf6575050908460019594939210610bdd575b505050811b019055610b6c565b015160001960f88460031b161c19169055388080610bd0565b6001859682939686015181550195019301610bb8565b610c3590868452898420601f860160051c8101918b8710610c3b575b601f0160051c01906126e5565b38610b43565b9091508190610c28565b634e487b7160e01b84526041905282fd5b84602e6084928a89519362461bcd60e51b85528401528201527f45524337323155524953746f726167653a2055524920736574206f66206e6f6e60448201526d32bc34b9ba32b73a103a37b5b2b760911b6064820152fd5b888552808a528785205480610cea575b508185526101928a5287852080546001600160a01b0319168a1790558885528952868420553880610a98565b85526101928a5287852080546001600160a01b031916905538610cbe565b948915610db95760008a815260676020526040902054839190610d37906001600160a01b031615155b15612a84565b60008b815260676020526040902054909690610d5d906001600160a01b03161515610d31565b8a60005260688c52896000206001815401905560678c52896000208b6001600160601b0360a01b8254161790558a8060007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a49050610a91565b6064888c86818d519362461bcd60e51b85528401528201527f4552433732313a206d696e7420746f20746865207a65726f20616464726573736044820152fd5b885162461bcd60e51b81528089018c9052601f818601527f5468697320757365726e616d6520697320616c72656164792074616b656e2e006044820152606490fd5b1592509082610e4f575b5050388b81610a6b565b8389526101928e528b892054161490508a38610e45565b9250508488526101928d528b818c8a205416818115918215610e8b575b505092610a64565b1490508138610e83565b865162461bcd60e51b81526020818801526034818401527f4f6e6c79207468652070726f66696c65206f776e6572206f7220636f6e74726160448201527331ba1037bbb732b91031b0b71039b2ba1034ba1760611b6064820152608490fd5b507f224b562a599bb6f57441f98a50de513dff0de3d9b620f342c27a4e4a898ce8e2845260fb60205286842033855260205260ff8785205416610a40565b503389821614610a39565b509034610234576020366003190112610234575190356001600160a01b0316815260209150f35b50503461027157816003193601126102715780519082606654610f86816125cd565b808552916001918083169081156110215750600114610fc4575b505050610fb282610334940383611feb565b51918291602083526020830190611ef6565b9450606685527f46501879b8ca8525e8c2fd519e2fbfcfa2ebea26501294aa02cbfcfb12e943545b82861061100957505050610fb28260206103349582010194610fa0565b80546020878701810191909152909501948101610fec565b610334975086935060209250610fb294915060ff191682840152151560051b82010194610fa0565b50346102345781600319360112610234578160209360ff92611069611f36565b9035825260fb86528282206001600160a01b039091168252855220549151911615158152f35b50503461027157816003193601126102715760c95490516001600160a01b039091168152602090f35b505034610271576020366003190112610271576020906001600160a01b036110de611f1b565b169051908152f35b83346103385780600319360112610338576110ff61246a565b60c980546001600160a01b0319811690915581906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b50829034610271576020366003190112610271576001600160a01b03611167611f1b565b169081156111845760208480858581526068845220549051908152f35b608490602085519162461bcd60e51b8352820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b6064820152fd5b50913461033857602036600319011261033857506111f9602092356128c8565b90516001600160a01b039091168152f35b505034610271578160031936011261027157602090517f224b562a599bb6f57441f98a50de513dff0de3d9b620f342c27a4e4a898ce8e28152f35b5034610234576020366003190112610234573582526101926020908152918190205490516001600160a01b039091168152f35b508234610338578060031936011261033857507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031630036112d25760208251600080516020612e258339815191528152f35b6020608492519162461bcd60e51b8352820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152fd5b5090806003193601126102345761134f611f1b565b9060243567ffffffffffffffff81116108e35761136f9036908501612060565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081169291906113a93085141561250b565b6113c6600080516020612e2583398151915294828654161461256c565b6113ce61246a565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff161561140657505050506101df9150612723565b8491929394168351946352d1902d60e01b865260209586818981865afa8991816115a5575b5061148a57855162461bcd60e51b8152808901889052602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608490fd5b969192949593960361155057509085916114a384612723565b7fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b8380a2845115801590611548575b6114df575b505050505080f35b61153d948291660819985a5b195960ca1b8651966114fc88611fb3565b602788527f416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c8389015287015281519101845af46115376127b3565b916127e3565b5038808083816114d7565b5060016114d2565b845162461bcd60e51b8152908101839052602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b6064820152608490fd5b9091508781813d83116115d1575b6115bd8183611feb565b810103126115cd5751903861142b565b8980fd5b503d6115b3565b5091903461027157602090816003193601126102345760c9546001600160a01b0385358181169690923390831614801561186a575b801561182e575b156117cf578686526101918086528487205487526101928652848720976001600160601b0360a01b9889815416905587528552858481205581611656846128c8565b161580156117c7575b1561173857508480968392611673846128c8565b848452606988528684208381541690551690818352606887528583206000198154019055838352606787528583209081541690557fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4609783526116db828520546125cd565b6116e457505050f35b8352609782528220906116f782546125cd565b908161170257505050f35b8390601f8311600114611716575050505580f35b838252812092909161173390601f0160051c8401600185016126e5565b555580f35b835162461bcd60e51b8152908101859052605b60248201527f54686973206120536f756c626f756e6420746f6b656e2e2049742063616e6e6f60448201527f74206265207472616e736665727265642e2049742063616e206f6e6c7920626560648201527f206275726e65642062792074686520746f6b656e206f776e65722e0000000000608482015260a490fd5b50600161165f565b835162461bcd60e51b8152908101859052603360248201527f4f6e6c7920746865206f776e6572206f662074686520746f6b656e206f7220706044820152723937b334b6329031b0b710313ab9371034ba1760691b6064820152608490fd5b507f224b562a599bb6f57441f98a50de513dff0de3d9b620f342c27a4e4a898ce8e2865260fb8552838620338752855260ff8487205416611614565b5033871461160d565b505034610271576101df9061188736611f4c565b9192519261189484611f81565b85845261298b565b509034610234576020806003193601126107de576118b8611f1b565b916001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166118f03082141561250b565b61190d600080516020612e2583398151915291838354161461256c565b61191561246a565b82519161192183611f81565b8783527f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff161561195d5750505050506101df9150612723565b8592939495169084516352d1902d60e01b815286818981865afa899181611a38575b506119de57855162461bcd60e51b8152808901889052602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b6064820152608490fd5b969192949593960361155057509085916119f784612723565b7fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b8380a2845115801590611a31576114df57505050505080f35b50816114d2565b9091508781813d8311611a60575b611a508183611feb565b810103126115cd5751903861197f565b503d611a46565b50829034610271578260031936011261027157611a82611f36565b90336001600160a01b03831603611a9e57906101df91356123f4565b608490602085519162461bcd60e51b8352820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152fd5b50346102345781600319360112610234573590611b14611f36565b9082845260fb602052611b2c600182862001546120de565b82845260fb60209081528185206001600160a01b039093168086529290528084205460ff1615611b5a578380f35b82845260fb6020528084208285526020528320600160ff1982541617905533917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d8480a43880808380f35b5034610234576020366003190112610234578160209360019235815260fb85522001549051908152f35b8334610338576101df611be136611f4c565b91611bf4611bef8433612a16565b612929565b612b2a565b5034610234578160031936011261023457611c12611f1b565b6024359290916001600160a01b0391908280611c2d876128c8565b16941693808514611d1c57803314908115611cfd575b5015611c9557508385526069602052842080546001600160a01b03191683179055611c6d836128c8565b167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258480a480f35b6020608492519162461bcd60e51b8352820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c0000006064820152fd5b90508652606a60205281862033875260205260ff828720541638611c43565b506020608492519162461bcd60e51b8352820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b6064820152fd5b50913461033857602036600319011261033857506111f9602092356128eb565b50503461027157816003193601126102715780519082606554611dab816125cd565b808552916001918083169081156110215750600114611dd657505050610fb282610334940383611feb565b9450606585527f8ff97419363ffd7000167f130ef7168fbea05faf9251824ca5043f113cc6a7c75b828610611e1b57505050610fb28260206103349582010194610fa0565b80546020878701810191909152909501948101611dfe565b92505034610234576020366003190112610234573563ffffffff60e01b81168091036102345760209250637965db0b60e01b8114908115611e76575b5015158152f35b632483248360e11b811491508115611e90575b5038611e6f565b6380ac58cd60e01b811491508115611ec2575b8115611eb1575b5038611e89565b6301ffc9a760e01b14905038611eaa565b635b5e139f60e01b81149150611ea3565b60005b838110611ee65750506000910152565b8181015183820152602001611ed6565b90602091611f0f81518092818552858086019101611ed3565b601f01601f1916010190565b600435906001600160a01b0382168203611f3157565b600080fd5b602435906001600160a01b0382168203611f3157565b6060906003190112611f31576001600160a01b03906004358281168103611f3157916024359081168103611f31579060443590565b6020810190811067ffffffffffffffff821117611f9d57604052565b634e487b7160e01b600052604160045260246000fd5b6060810190811067ffffffffffffffff821117611f9d57604052565b6040810190811067ffffffffffffffff821117611f9d57604052565b90601f8019910116810190811067ffffffffffffffff821117611f9d57604052565b67ffffffffffffffff8111611f9d57601f01601f191660200190565b9291926120358261200d565b916120436040519384611feb565b829481845281830111611f31578281602093846000960137010152565b9080601f83011215611f315781602061207b93359101612029565b90565b1561208557565b60405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608490fd5b60009080825260209060fb8252604092838120338252835260ff8482205416156121085750505050565b3384519261211584611fb3565b602a845284840190863683378451156123e057603082538451926001938410156123cc576078602187015360295b8481116123625750612320578651926080840184811067ffffffffffffffff82111761230c578852604284528684019460603687378451156122f8576030865384518210156122f85790607860218601536041915b81831161228a5750505061224857612244938693612228936122196048946121f09a519a8b957f416363657373436f6e74726f6c3a206163636f756e74200000000000000000008c8801525180926037880190611ed3565b8401917001034b99036b4b9b9b4b733903937b6329607d1b603784015251809386840190611ed3565b01036028810187520185611feb565b5192839262461bcd60e51b845260048401526024830190611ef6565b0390fd5b60648587519062461bcd60e51b825280600483015260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152fd5b909192600f811660108110156122e4576f181899199a1a9b1b9c1cb0b131b232b360811b901a6122ba85886126fc565b5360041c9280156122d057600019019190612198565b634e487b7160e01b82526011600452602482fd5b634e487b7160e01b83526032600452602483fd5b634e487b7160e01b81526032600452602490fd5b634e487b7160e01b86526041600452602486fd5b60648688519062461bcd60e51b825280600483015260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152fd5b90600f811660108110156123b8576f181899199a1a9b1b9c1cb0b131b232b360811b901a61239083896126fc565b5360041c9080156123a45760001901612143565b634e487b7160e01b86526011600452602486fd5b634e487b7160e01b87526032600452602487fd5b634e487b7160e01b85526032600452602485fd5b634e487b7160e01b84526032600452602484fd5b9060009180835260fb602052604083209160018060a01b03169182845260205260ff60408420541661242557505050565b80835260fb602052604083208284526020526040832060ff1981541690557ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b339380a4565b60c9546001600160a01b0316330361247e57565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b60c980546001600160a01b039283166001600160a01b0319821681179092559091167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3565b1561251257565b60405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201526b19195b1959d85d1958d85b1b60a21b6064820152608490fd5b1561257357565b60405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201526b6163746976652070726f787960a01b6064820152608490fd5b90600182811c921680156125fd575b60208310146125e757565b634e487b7160e01b600052602260045260246000fd5b91607f16916125dc565b60008181526067602052604090205461262a906001600160a01b0316151561287c565b600090815260209060978252604081209160405180938390805461264d816125cd565b808552916001918083169081156126c35750600114612686575b50505061267692500383611feb565b60405161268281611f81565b5290565b86528486209492508591905b8183106126ab5750506126769350820101388080612667565b85548884018501529485019487945091830191612692565b9250505061267694925060ff191682840152151560051b820101388080612667565b8181106126f0575050565b600081556001016126e5565b90815181101561270d570160200190565b634e487b7160e01b600052603260045260246000fd5b803b1561275857600080516020612e2583398151915280546001600160a01b0319166001600160a01b03909216919091179055565b60405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608490fd5b3d156127de573d906127c48261200d565b916127d26040519384611feb565b82523d6000602084013e565b606090565b9192901561284557508151156127f7575090565b3b156128005790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b8251909150156128585750805190602001fd5b60405162461bcd60e51b815260206004820152908190612244906024830190611ef6565b1561288357565b60405162461bcd60e51b815260206004820152601860248201527f4552433732313a20696e76616c696420746f6b656e20494400000000000000006044820152606490fd5b6000908152606760205260409020546001600160a01b031661207b81151561287c565b60008181526067602052604090205461290e906001600160a01b0316151561287c565b6000908152606960205260409020546001600160a01b031690565b1561293057565b60405162461bcd60e51b815260206004820152602d60248201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560448201526c1c881bdc88185c1c1c9bdd9959609a1b6064820152608490fd5b906129af93929161299f611bef8433612a16565b6129aa838383612b2a565b612ce2565b156129b657565b60405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b6064820152608490fd5b906001600160a01b038080612a2a846128c8565b16931691838314938415612a5d575b508315612a47575b50505090565b612a53919293506128eb565b1614388080612a41565b909350600052606a60205260406000208260005260205260ff604060002054169238612a39565b15612a8b57565b60405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e746564000000006044820152606490fd5b15612ad757565b60405162461bcd60e51b815260206004820152602560248201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060448201526437bbb732b960d91b6064820152608490fd5b90612b5291612b38846128c8565b6001600160a01b0393918416928492909183168414612ad0565b16918215612c915781158015612c89575b15612bf85781612b7d91612b76866128c8565b1614612ad0565b7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60008481526069602052604081206001600160601b0360a01b9081815416905583825260686020526040822060001981540190558482526040822060018154019055858252606760205284604083209182541617905580a4565b60405162461bcd60e51b815260206004820152605b60248201527f54686973206120536f756c626f756e6420746f6b656e2e2049742063616e6e6f60448201527f74206265207472616e736665727265642e2049742063616e206f6e6c7920626560648201527f206275726e65642062792074686520746f6b656e206f776e65722e0000000000608482015260a490fd5b506000612b63565b60405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b6064820152608490fd5b919290803b15612e1b57604051630a85bd0160e11b8082523360048301526001600160a01b03948516602483015260448201959095526080606482015291602091839182908190612d37906084830190611ef6565b03916000968791165af190829082612dd3575b5050612dc557612d586127b3565b80519081612dc05760405162461bcd60e51b815260206004820152603260248201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560448201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b6064820152608490fd5b602001fd5b6001600160e01b0319161490565b909192506020813d8211612e13575b81612def60209383611feb565b810103126102715751906001600160e01b0319821682036103385750903880612d4a565b3d9150612de2565b5050505060019056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca2646970667358221220e8f7685d818a5268c65c5d1c6649912a27067099631f54badf6551d90a84ff8264736f6c63430008140033'; diff --git a/app/[alias]/(dashboard)/checkout/contract/token_contract.ts b/app/[alias]/(dashboard)/checkout/contract/token_contract.ts index b26e7c94..f396b637 100644 --- a/app/[alias]/(dashboard)/checkout/contract/token_contract.ts +++ b/app/[alias]/(dashboard)/checkout/contract/token_contract.ts @@ -1,917 +1,917 @@ -export const TOKEN_ABI = [ - { - type: 'function', - name: 'DEFAULT_ADMIN_ROLE', - inputs: [], - outputs: [ - { - name: '', - type: 'bytes32', - internalType: 'bytes32' - } - ], - stateMutability: 'view' - }, - { - type: 'function', - name: 'MINTER_ROLE', - inputs: [], - outputs: [ - { - name: '', - type: 'bytes32', - internalType: 'bytes32' - } - ], - stateMutability: 'view' - }, - { - type: 'function', - name: 'PAUSER_ROLE', - inputs: [], - outputs: [ - { - name: '', - type: 'bytes32', - internalType: 'bytes32' - } - ], - stateMutability: 'view' - }, - { - type: 'function', - name: 'UPGRADE_INTERFACE_VERSION', - inputs: [], - outputs: [ - { - name: '', - type: 'string', - internalType: 'string' - } - ], - stateMutability: 'view' - }, - { - type: 'function', - name: 'allowance', - inputs: [ - { - name: 'owner', - type: 'address', - internalType: 'address' - }, - { - name: 'spender', - type: 'address', - internalType: 'address' - } - ], - outputs: [ - { - name: '', - type: 'uint256', - internalType: 'uint256' - } - ], - stateMutability: 'view' - }, - { - type: 'function', - name: 'approve', - inputs: [ - { - name: 'spender', - type: 'address', - internalType: 'address' - }, - { - name: 'value', - type: 'uint256', - internalType: 'uint256' - } - ], - outputs: [ - { - name: '', - type: 'bool', - internalType: 'bool' - } - ], - stateMutability: 'nonpayable' - }, - { - type: 'function', - name: 'balanceOf', - inputs: [ - { - name: 'account', - type: 'address', - internalType: 'address' - } - ], - outputs: [ - { - name: '', - type: 'uint256', - internalType: 'uint256' - } - ], - stateMutability: 'view' - }, - { - type: 'function', - name: 'burn', - inputs: [ - { - name: 'value', - type: 'uint256', - internalType: 'uint256' - } - ], - outputs: [], - stateMutability: 'nonpayable' - }, - { - type: 'function', - name: 'burnFrom', - inputs: [ - { - name: 'from', - type: 'address', - internalType: 'address' - }, - { - name: 'amount', - type: 'uint256', - internalType: 'uint256' - } - ], - outputs: [], - stateMutability: 'nonpayable' - }, - { - type: 'function', - name: 'decimals', - inputs: [], - outputs: [ - { - name: '', - type: 'uint8', - internalType: 'uint8' - } - ], - stateMutability: 'view' - }, - { - type: 'function', - name: 'getRoleAdmin', - inputs: [ - { - name: 'role', - type: 'bytes32', - internalType: 'bytes32' - } - ], - outputs: [ - { - name: '', - type: 'bytes32', - internalType: 'bytes32' - } - ], - stateMutability: 'view' - }, - { - type: 'function', - name: 'grantRole', - inputs: [ - { - name: 'role', - type: 'bytes32', - internalType: 'bytes32' - }, - { - name: 'account', - type: 'address', - internalType: 'address' - } - ], - outputs: [], - stateMutability: 'nonpayable' - }, - { - type: 'function', - name: 'hasRole', - inputs: [ - { - name: 'role', - type: 'bytes32', - internalType: 'bytes32' - }, - { - name: 'account', - type: 'address', - internalType: 'address' - } - ], - outputs: [ - { - name: '', - type: 'bool', - internalType: 'bool' - } - ], - stateMutability: 'view' - }, - { - type: 'function', - name: 'initialize', - inputs: [ - { - name: '_owner', - type: 'address', - internalType: 'address' - }, - { - name: 'minters', - type: 'address[]', - internalType: 'address[]' - }, - { - name: 'name', - type: 'string', - internalType: 'string' - }, - { - name: 'symbol', - type: 'string', - internalType: 'string' - } - ], - outputs: [], - stateMutability: 'nonpayable' - }, - { - type: 'function', - name: 'mint', - inputs: [ - { - name: 'to', - type: 'address', - internalType: 'address' - }, - { - name: 'amount', - type: 'uint256', - internalType: 'uint256' - } - ], - outputs: [], - stateMutability: 'nonpayable' - }, - { - type: 'function', - name: 'name', - inputs: [], - outputs: [ - { - name: '', - type: 'string', - internalType: 'string' - } - ], - stateMutability: 'view' - }, - { - type: 'function', - name: 'owner', - inputs: [], - outputs: [ - { - name: '', - type: 'address', - internalType: 'address' - } - ], - stateMutability: 'view' - }, - { - type: 'function', - name: 'pause', - inputs: [], - outputs: [], - stateMutability: 'nonpayable' - }, - { - type: 'function', - name: 'paused', - inputs: [], - outputs: [ - { - name: '', - type: 'bool', - internalType: 'bool' - } - ], - stateMutability: 'view' - }, - { - type: 'function', - name: 'proxiableUUID', - inputs: [], - outputs: [ - { - name: '', - type: 'bytes32', - internalType: 'bytes32' - } - ], - stateMutability: 'view' - }, - { - type: 'function', - name: 'renounceOwnership', - inputs: [], - outputs: [], - stateMutability: 'nonpayable' - }, - { - type: 'function', - name: 'renounceRole', - inputs: [ - { - name: 'role', - type: 'bytes32', - internalType: 'bytes32' - }, - { - name: 'callerConfirmation', - type: 'address', - internalType: 'address' - } - ], - outputs: [], - stateMutability: 'nonpayable' - }, - { - type: 'function', - name: 'revokeRole', - inputs: [ - { - name: 'role', - type: 'bytes32', - internalType: 'bytes32' - }, - { - name: 'account', - type: 'address', - internalType: 'address' - } - ], - outputs: [], - stateMutability: 'nonpayable' - }, - { - type: 'function', - name: 'supportsInterface', - inputs: [ - { - name: 'interfaceId', - type: 'bytes4', - internalType: 'bytes4' - } - ], - outputs: [ - { - name: '', - type: 'bool', - internalType: 'bool' - } - ], - stateMutability: 'view' - }, - { - type: 'function', - name: 'symbol', - inputs: [], - outputs: [ - { - name: '', - type: 'string', - internalType: 'string' - } - ], - stateMutability: 'view' - }, - { - type: 'function', - name: 'totalSupply', - inputs: [], - outputs: [ - { - name: '', - type: 'uint256', - internalType: 'uint256' - } - ], - stateMutability: 'view' - }, - { - type: 'function', - name: 'transfer', - inputs: [ - { - name: 'to', - type: 'address', - internalType: 'address' - }, - { - name: 'value', - type: 'uint256', - internalType: 'uint256' - } - ], - outputs: [ - { - name: '', - type: 'bool', - internalType: 'bool' - } - ], - stateMutability: 'nonpayable' - }, - { - type: 'function', - name: 'transferFrom', - inputs: [ - { - name: 'from', - type: 'address', - internalType: 'address' - }, - { - name: 'to', - type: 'address', - internalType: 'address' - }, - { - name: 'value', - type: 'uint256', - internalType: 'uint256' - } - ], - outputs: [ - { - name: '', - type: 'bool', - internalType: 'bool' - } - ], - stateMutability: 'nonpayable' - }, - { - type: 'function', - name: 'transferOwnership', - inputs: [ - { - name: 'newOwner', - type: 'address', - internalType: 'address' - } - ], - outputs: [], - stateMutability: 'nonpayable' - }, - { - type: 'function', - name: 'unpause', - inputs: [], - outputs: [], - stateMutability: 'nonpayable' - }, - { - type: 'function', - name: 'upgradeToAndCall', - inputs: [ - { - name: 'newImplementation', - type: 'address', - internalType: 'address' - }, - { - name: 'data', - type: 'bytes', - internalType: 'bytes' - } - ], - outputs: [], - stateMutability: 'payable' - }, - { - type: 'event', - name: 'Approval', - inputs: [ - { - name: 'owner', - type: 'address', - indexed: true, - internalType: 'address' - }, - { - name: 'spender', - type: 'address', - indexed: true, - internalType: 'address' - }, - { - name: 'value', - type: 'uint256', - indexed: false, - internalType: 'uint256' - } - ], - anonymous: false - }, - { - type: 'event', - name: 'Initialized', - inputs: [ - { - name: 'version', - type: 'uint64', - indexed: false, - internalType: 'uint64' - } - ], - anonymous: false - }, - { - type: 'event', - name: 'OwnershipTransferred', - inputs: [ - { - name: 'previousOwner', - type: 'address', - indexed: true, - internalType: 'address' - }, - { - name: 'newOwner', - type: 'address', - indexed: true, - internalType: 'address' - } - ], - anonymous: false - }, - { - type: 'event', - name: 'Paused', - inputs: [ - { - name: 'account', - type: 'address', - indexed: false, - internalType: 'address' - } - ], - anonymous: false - }, - { - type: 'event', - name: 'RoleAdminChanged', - inputs: [ - { - name: 'role', - type: 'bytes32', - indexed: true, - internalType: 'bytes32' - }, - { - name: 'previousAdminRole', - type: 'bytes32', - indexed: true, - internalType: 'bytes32' - }, - { - name: 'newAdminRole', - type: 'bytes32', - indexed: true, - internalType: 'bytes32' - } - ], - anonymous: false - }, - { - type: 'event', - name: 'RoleGranted', - inputs: [ - { - name: 'role', - type: 'bytes32', - indexed: true, - internalType: 'bytes32' - }, - { - name: 'account', - type: 'address', - indexed: true, - internalType: 'address' - }, - { - name: 'sender', - type: 'address', - indexed: true, - internalType: 'address' - } - ], - anonymous: false - }, - { - type: 'event', - name: 'RoleRevoked', - inputs: [ - { - name: 'role', - type: 'bytes32', - indexed: true, - internalType: 'bytes32' - }, - { - name: 'account', - type: 'address', - indexed: true, - internalType: 'address' - }, - { - name: 'sender', - type: 'address', - indexed: true, - internalType: 'address' - } - ], - anonymous: false - }, - { - type: 'event', - name: 'Transfer', - inputs: [ - { - name: 'from', - type: 'address', - indexed: true, - internalType: 'address' - }, - { - name: 'to', - type: 'address', - indexed: true, - internalType: 'address' - }, - { - name: 'value', - type: 'uint256', - indexed: false, - internalType: 'uint256' - } - ], - anonymous: false - }, - { - type: 'event', - name: 'Unpaused', - inputs: [ - { - name: 'account', - type: 'address', - indexed: false, - internalType: 'address' - } - ], - anonymous: false - }, - { - type: 'event', - name: 'Upgraded', - inputs: [ - { - name: 'implementation', - type: 'address', - indexed: true, - internalType: 'address' - } - ], - anonymous: false - }, - { - type: 'error', - name: 'AccessControlBadConfirmation', - inputs: [] - }, - { - type: 'error', - name: 'AccessControlUnauthorizedAccount', - inputs: [ - { - name: 'account', - type: 'address', - internalType: 'address' - }, - { - name: 'neededRole', - type: 'bytes32', - internalType: 'bytes32' - } - ] - }, - { - type: 'error', - name: 'AddressEmptyCode', - inputs: [ - { - name: 'target', - type: 'address', - internalType: 'address' - } - ] - }, - { - type: 'error', - name: 'ERC1967InvalidImplementation', - inputs: [ - { - name: 'implementation', - type: 'address', - internalType: 'address' - } - ] - }, - { - type: 'error', - name: 'ERC1967NonPayable', - inputs: [] - }, - { - type: 'error', - name: 'ERC20InsufficientAllowance', - inputs: [ - { - name: 'spender', - type: 'address', - internalType: 'address' - }, - { - name: 'allowance', - type: 'uint256', - internalType: 'uint256' - }, - { - name: 'needed', - type: 'uint256', - internalType: 'uint256' - } - ] - }, - { - type: 'error', - name: 'ERC20InsufficientBalance', - inputs: [ - { - name: 'sender', - type: 'address', - internalType: 'address' - }, - { - name: 'balance', - type: 'uint256', - internalType: 'uint256' - }, - { - name: 'needed', - type: 'uint256', - internalType: 'uint256' - } - ] - }, - { - type: 'error', - name: 'ERC20InvalidApprover', - inputs: [ - { - name: 'approver', - type: 'address', - internalType: 'address' - } - ] - }, - { - type: 'error', - name: 'ERC20InvalidReceiver', - inputs: [ - { - name: 'receiver', - type: 'address', - internalType: 'address' - } - ] - }, - { - type: 'error', - name: 'ERC20InvalidSender', - inputs: [ - { - name: 'sender', - type: 'address', - internalType: 'address' - } - ] - }, - { - type: 'error', - name: 'ERC20InvalidSpender', - inputs: [ - { - name: 'spender', - type: 'address', - internalType: 'address' - } - ] - }, - { - type: 'error', - name: 'EnforcedPause', - inputs: [] - }, - { - type: 'error', - name: 'ExpectedPause', - inputs: [] - }, - { - type: 'error', - name: 'FailedInnerCall', - inputs: [] - }, - { - type: 'error', - name: 'InvalidInitialization', - inputs: [] - }, - { - type: 'error', - name: 'MustHaveMinterRole', - inputs: [ - { - name: 'account', - type: 'address', - internalType: 'address' - } - ] - }, - { - type: 'error', - name: 'NotInitializing', - inputs: [] - }, - { - type: 'error', - name: 'OwnableInvalidOwner', - inputs: [ - { - name: 'owner', - type: 'address', - internalType: 'address' - } - ] - }, - { - type: 'error', - name: 'OwnableUnauthorizedAccount', - inputs: [ - { - name: 'account', - type: 'address', - internalType: 'address' - } - ] - }, - { - type: 'error', - name: 'UUPSUnauthorizedCallContext', - inputs: [] - }, - { - type: 'error', - name: 'UUPSUnsupportedProxiableUUID', - inputs: [ - { - name: 'slot', - type: 'bytes32', - internalType: 'bytes32' - } - ] - } -]; - -export const TOKEN_BYTECODE = - '0x60a06040523060805234801561001457600080fd5b50608051611db461003e60003960008181610e8d01528181610eb60152610ff70152611db46000f3fe6080604052600436106101d85760003560e01c806370a0823111610102578063a9059cbb11610095578063d547741f11610064578063d547741f14610583578063dd62ed3e146105a3578063e63ab1e9146105c3578063f2fde38b146105e557600080fd5b8063a9059cbb146104f0578063ad3cb1cc14610510578063c1abece914610541578063d53913931461056157600080fd5b80638da5cb5b116100d15780638da5cb5b1461045f57806391d14854146104a657806395d89b41146104c6578063a217fddf146104db57600080fd5b806370a08231146103d2578063715018a61461041557806379cc67901461042a5780638456cb591461044a57600080fd5b8063313ce5671161017a57806342966c681161014957806342966c68146103655780634f1ef2861461038557806352d1902d146103985780635c975abb146103ad57600080fd5b8063313ce567146102f457806336568abe146103105780633f4ba83a1461033057806340c10f191461034557600080fd5b806318160ddd116101b657806318160ddd1461025457806323b872dd14610292578063248a9ca3146102b25780632f2ff15d146102d257600080fd5b806301ffc9a7146101dd57806306fdde0314610212578063095ea7b314610234575b600080fd5b3480156101e957600080fd5b506101fd6101f8366004611735565b610605565b60405190151581526020015b60405180910390f35b34801561021e57600080fd5b5061022761063c565b6040516102099190611783565b34801561024057600080fd5b506101fd61024f3660046117d2565b6106ff565b34801561026057600080fd5b507f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace02545b604051908152602001610209565b34801561029e57600080fd5b506101fd6102ad3660046117fc565b610717565b3480156102be57600080fd5b506102846102cd366004611838565b61073d565b3480156102de57600080fd5b506102f26102ed366004611851565b61075f565b005b34801561030057600080fd5b5060405160068152602001610209565b34801561031c57600080fd5b506102f261032b366004611851565b610781565b34801561033c57600080fd5b506102f26107b9565b34801561035157600080fd5b506102f26103603660046117d2565b6107dc565b34801561037157600080fd5b506102f2610380366004611838565b610826565b6102f261039336600461191c565b610830565b3480156103a457600080fd5b5061028461084b565b3480156103b957600080fd5b50600080516020611d5f8339815191525460ff166101fd565b3480156103de57600080fd5b506102846103ed36600461197e565b6001600160a01b03166000908152600080516020611cbf833981519152602052604090205490565b34801561042157600080fd5b506102f2610868565b34801561043657600080fd5b506102f26104453660046117d2565b61087c565b34801561045657600080fd5b506102f26108bd565b34801561046b57600080fd5b507f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546040516001600160a01b039091168152602001610209565b3480156104b257600080fd5b506101fd6104c1366004611851565b6108dd565b3480156104d257600080fd5b50610227610915565b3480156104e757600080fd5b50610284600081565b3480156104fc57600080fd5b506101fd61050b3660046117d2565b610954565b34801561051c57600080fd5b50610227604051806040016040528060058152602001640352e302e360dc1b81525081565b34801561054d57600080fd5b506102f261055c3660046119b9565b610962565b34801561056d57600080fd5b50610284600080516020611d1f83398151915281565b34801561058f57600080fd5b506102f261059e366004611851565b610b1e565b3480156105af57600080fd5b506102846105be366004611abf565b610b3a565b3480156105cf57600080fd5b50610284600080516020611cff83398151915281565b3480156105f157600080fd5b506102f261060036600461197e565b610b84565b60006001600160e01b03198216637965db0b60e01b148061063657506301ffc9a760e01b6001600160e01b03198316145b92915050565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace038054606091600080516020611cbf8339815191529161067b90611ae9565b80601f01602080910402602001604051908101604052809291908181526020018280546106a790611ae9565b80156106f45780601f106106c9576101008083540402835291602001916106f4565b820191906000526020600020905b8154815290600101906020018083116106d757829003601f168201915b505050505091505090565b60003361070d818585610bbf565b5060019392505050565b600033610725858285610bcc565b610730858585610c2c565b60019150505b9392505050565b6000908152600080516020611d3f833981519152602052604090206001015490565b6107688261073d565b61077181610c8b565b61077b8383610c95565b50505050565b6001600160a01b03811633146107aa5760405163334bd91960e11b815260040160405180910390fd5b6107b48282610d3a565b505050565b600080516020611cff8339815191526107d181610c8b565b6107d9610db6565b50565b6107f4600080516020611d1f833981519152336108dd565b61081857604051636690b7c160e01b81523360048201526024015b60405180910390fd5b6108228282610e16565b5050565b6107d93382610e4c565b610838610e82565b61084182610f27565b6108228282610f2f565b6000610855610fec565b50600080516020611cdf83398151915290565b610870611035565b61087a6000611090565b565b610894600080516020611d1f833981519152336108dd565b6108b357604051636690b7c160e01b815233600482015260240161080f565b6108228282610e4c565b600080516020611cff8339815191526108d581610c8b565b6107d9611101565b6000918252600080516020611d3f833981519152602090815260408084206001600160a01b0393909316845291905290205460ff1690565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace048054606091600080516020611cbf8339815191529161067b90611ae9565b60003361070d818585610c2c565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff16159067ffffffffffffffff166000811580156109a85750825b905060008267ffffffffffffffff1660011480156109c55750303b155b9050811580156109d3575080155b156109f15760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff191660011785558315610a1b57845460ff60401b1916600160401b1785555b610a25878761114a565b610a2e8961115c565b610a3661116d565b610a3e61116d565b610a4960008a610c95565b50610a63600080516020611d1f8339815191526000611175565b610a7c600080516020611cff8339815191526000611175565b60005b8851811015610acc57610ab9600080516020611d1f8339815191528a8381518110610aac57610aac611b23565b6020026020010151610c95565b5080610ac481611b4f565b915050610a7f565b508315610b1357845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b505050505050505050565b610b278261073d565b610b3081610c8b565b61077b8383610d3a565b6001600160a01b0391821660009081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace016020908152604080832093909416825291909152205490565b610b8c611035565b6001600160a01b038116610bb657604051631e4fbdf760e01b81526000600482015260240161080f565b6107d981611090565b6107b483838360016111d8565b6000610bd88484610b3a565b9050600019811461077b5781811015610c1d57604051637dc7a0d960e11b81526001600160a01b0384166004820152602481018290526044810183905260640161080f565b61077b848484840360006111d8565b6001600160a01b038316610c5657604051634b637e8f60e11b81526000600482015260240161080f565b6001600160a01b038216610c805760405163ec442f0560e01b81526000600482015260240161080f565b6107b48383836112c0565b6107d981336112d3565b6000600080516020611d3f833981519152610cb084846108dd565b610d30576000848152602082815260408083206001600160a01b03871684529091529020805460ff19166001179055610ce63390565b6001600160a01b0316836001600160a01b0316857f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a46001915050610636565b6000915050610636565b6000600080516020611d3f833981519152610d5584846108dd565b15610d30576000848152602082815260408083206001600160a01b0387168085529252808320805460ff1916905551339287917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a46001915050610636565b610dbe61130c565b600080516020611d5f833981519152805460ff191681557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a150565b6001600160a01b038216610e405760405163ec442f0560e01b81526000600482015260240161080f565b610822600083836112c0565b6001600160a01b038216610e7657604051634b637e8f60e11b81526000600482015260240161080f565b610822826000836112c0565b306001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161480610f0957507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316610efd600080516020611cdf833981519152546001600160a01b031690565b6001600160a01b031614155b1561087a5760405163703e46dd60e11b815260040160405180910390fd5b6107d9611035565b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015610f89575060408051601f3d908101601f19168201909252610f8691810190611b68565b60015b610fb157604051634c9c8ce360e01b81526001600160a01b038316600482015260240161080f565b600080516020611cdf8339815191528114610fe257604051632a87526960e21b81526004810182905260240161080f565b6107b4838361133c565b306001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461087a5760405163703e46dd60e11b815260040160405180910390fd5b336110677f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b6001600160a01b03161461087a5760405163118cdaa760e01b815233600482015260240161080f565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b611109611392565b600080516020611d5f833981519152805460ff191660011781557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25833610df8565b6111526113c3565b610822828261140c565b6111646113c3565b6107d98161145d565b61087a6113c3565b600080516020611d3f833981519152600061118f8461073d565b600085815260208490526040808220600101869055519192508491839187917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a450505050565b600080516020611cbf8339815191526001600160a01b0385166112115760405163e602df0560e01b81526000600482015260240161080f565b6001600160a01b03841661123b57604051634a1406b160e11b81526000600482015260240161080f565b6001600160a01b038086166000908152600183016020908152604080832093881683529290522083905581156112b957836001600160a01b0316856001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925856040516112b091815260200190565b60405180910390a35b5050505050565b6112c8611392565b6107b4838383611465565b6112dd82826108dd565b6108225760405163e2517d3f60e01b81526001600160a01b03821660048201526024810183905260440161080f565b600080516020611d5f8339815191525460ff1661087a57604051638dfc202b60e01b815260040160405180910390fd5b61134582611478565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a280511561138a576107b482826114dd565b610822611553565b600080516020611d5f8339815191525460ff161561087a5760405163d93c066560e01b815260040160405180910390fd5b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff1661087a57604051631afcd79f60e31b815260040160405180910390fd5b6114146113c3565b600080516020611cbf8339815191527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0361144e8482611bcf565b506004810161077b8382611bcf565b610b8c6113c3565b61146d611392565b6107b4838383611572565b806001600160a01b03163b6000036114ae57604051634c9c8ce360e01b81526001600160a01b038216600482015260240161080f565b600080516020611cdf83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b6060600080846001600160a01b0316846040516114fa9190611c8f565b600060405180830381855af49150503d8060008114611535576040519150601f19603f3d011682016040523d82523d6000602084013e61153a565b606091505b509150915061154a8583836116b0565b95945050505050565b341561087a5760405163b398979f60e01b815260040160405180910390fd5b600080516020611cbf8339815191526001600160a01b0384166115ae57818160020160008282546115a39190611cab565b909155506116209050565b6001600160a01b038416600090815260208290526040902054828110156116015760405163391434e360e21b81526001600160a01b0386166004820152602481018290526044810184905260640161080f565b6001600160a01b03851660009081526020839052604090209083900390555b6001600160a01b03831661163e57600281018054839003905561165d565b6001600160a01b03831660009081526020829052604090208054830190555b826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516116a291815260200190565b60405180910390a350505050565b6060826116c5576116c08261170c565b610736565b81511580156116dc57506001600160a01b0384163b155b1561170557604051639996b31560e01b81526001600160a01b038516600482015260240161080f565b5080610736565b80511561171c5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b60006020828403121561174757600080fd5b81356001600160e01b03198116811461073657600080fd5b60005b8381101561177a578181015183820152602001611762565b50506000910152565b60208152600082518060208401526117a281604085016020870161175f565b601f01601f19169190910160400192915050565b80356001600160a01b03811681146117cd57600080fd5b919050565b600080604083850312156117e557600080fd5b6117ee836117b6565b946020939093013593505050565b60008060006060848603121561181157600080fd5b61181a846117b6565b9250611828602085016117b6565b9150604084013590509250925092565b60006020828403121561184a57600080fd5b5035919050565b6000806040838503121561186457600080fd5b82359150611874602084016117b6565b90509250929050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff811182821017156118bc576118bc61187d565b604052919050565b600067ffffffffffffffff8311156118de576118de61187d565b6118f1601f8401601f1916602001611893565b905082815283838301111561190557600080fd5b828260208301376000602084830101529392505050565b6000806040838503121561192f57600080fd5b611938836117b6565b9150602083013567ffffffffffffffff81111561195457600080fd5b8301601f8101851361196557600080fd5b611974858235602084016118c4565b9150509250929050565b60006020828403121561199057600080fd5b610736826117b6565b600082601f8301126119aa57600080fd5b610736838335602085016118c4565b600080600080608085870312156119cf57600080fd5b6119d8856117b6565b935060208086013567ffffffffffffffff808211156119f657600080fd5b818801915088601f830112611a0a57600080fd5b813581811115611a1c57611a1c61187d565b8060051b611a2b858201611893565b918252838101850191858101908c841115611a4557600080fd5b948601945b83861015611a6a57611a5b866117b6565b82529486019490860190611a4a565b98505050506040880135925080831115611a8357600080fd5b611a8f89848a01611999565b94506060880135925080831115611aa557600080fd5b5050611ab387828801611999565b91505092959194509250565b60008060408385031215611ad257600080fd5b611adb836117b6565b9150611874602084016117b6565b600181811c90821680611afd57607f821691505b602082108103611b1d57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201611b6157611b61611b39565b5060010190565b600060208284031215611b7a57600080fd5b5051919050565b601f8211156107b457600081815260208120601f850160051c81016020861015611ba85750805b601f850160051c820191505b81811015611bc757828155600101611bb4565b505050505050565b815167ffffffffffffffff811115611be957611be961187d565b611bfd81611bf78454611ae9565b84611b81565b602080601f831160018114611c325760008415611c1a5750858301515b600019600386901b1c1916600185901b178555611bc7565b600085815260208120601f198616915b82811015611c6157888601518255948401946001909101908401611c42565b5085821015611c7f5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60008251611ca181846020870161175f565b9190910192915050565b8082018082111561063657610636611b3956fe52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a602dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800cd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300a26469706673582212208eafdded02d0ded1b81e9117ce8d3c308edf5880a224d8acd82bd3fe0174eb3b64736f6c63430008140033'; +export const TOKEN_ABI = [ + { + type: 'function', + name: 'DEFAULT_ADMIN_ROLE', + inputs: [], + outputs: [ + { + name: '', + type: 'bytes32', + internalType: 'bytes32' + } + ], + stateMutability: 'view' + }, + { + type: 'function', + name: 'MINTER_ROLE', + inputs: [], + outputs: [ + { + name: '', + type: 'bytes32', + internalType: 'bytes32' + } + ], + stateMutability: 'view' + }, + { + type: 'function', + name: 'PAUSER_ROLE', + inputs: [], + outputs: [ + { + name: '', + type: 'bytes32', + internalType: 'bytes32' + } + ], + stateMutability: 'view' + }, + { + type: 'function', + name: 'UPGRADE_INTERFACE_VERSION', + inputs: [], + outputs: [ + { + name: '', + type: 'string', + internalType: 'string' + } + ], + stateMutability: 'view' + }, + { + type: 'function', + name: 'allowance', + inputs: [ + { + name: 'owner', + type: 'address', + internalType: 'address' + }, + { + name: 'spender', + type: 'address', + internalType: 'address' + } + ], + outputs: [ + { + name: '', + type: 'uint256', + internalType: 'uint256' + } + ], + stateMutability: 'view' + }, + { + type: 'function', + name: 'approve', + inputs: [ + { + name: 'spender', + type: 'address', + internalType: 'address' + }, + { + name: 'value', + type: 'uint256', + internalType: 'uint256' + } + ], + outputs: [ + { + name: '', + type: 'bool', + internalType: 'bool' + } + ], + stateMutability: 'nonpayable' + }, + { + type: 'function', + name: 'balanceOf', + inputs: [ + { + name: 'account', + type: 'address', + internalType: 'address' + } + ], + outputs: [ + { + name: '', + type: 'uint256', + internalType: 'uint256' + } + ], + stateMutability: 'view' + }, + { + type: 'function', + name: 'burn', + inputs: [ + { + name: 'value', + type: 'uint256', + internalType: 'uint256' + } + ], + outputs: [], + stateMutability: 'nonpayable' + }, + { + type: 'function', + name: 'burnFrom', + inputs: [ + { + name: 'from', + type: 'address', + internalType: 'address' + }, + { + name: 'amount', + type: 'uint256', + internalType: 'uint256' + } + ], + outputs: [], + stateMutability: 'nonpayable' + }, + { + type: 'function', + name: 'decimals', + inputs: [], + outputs: [ + { + name: '', + type: 'uint8', + internalType: 'uint8' + } + ], + stateMutability: 'view' + }, + { + type: 'function', + name: 'getRoleAdmin', + inputs: [ + { + name: 'role', + type: 'bytes32', + internalType: 'bytes32' + } + ], + outputs: [ + { + name: '', + type: 'bytes32', + internalType: 'bytes32' + } + ], + stateMutability: 'view' + }, + { + type: 'function', + name: 'grantRole', + inputs: [ + { + name: 'role', + type: 'bytes32', + internalType: 'bytes32' + }, + { + name: 'account', + type: 'address', + internalType: 'address' + } + ], + outputs: [], + stateMutability: 'nonpayable' + }, + { + type: 'function', + name: 'hasRole', + inputs: [ + { + name: 'role', + type: 'bytes32', + internalType: 'bytes32' + }, + { + name: 'account', + type: 'address', + internalType: 'address' + } + ], + outputs: [ + { + name: '', + type: 'bool', + internalType: 'bool' + } + ], + stateMutability: 'view' + }, + { + type: 'function', + name: 'initialize', + inputs: [ + { + name: '_owner', + type: 'address', + internalType: 'address' + }, + { + name: 'minters', + type: 'address[]', + internalType: 'address[]' + }, + { + name: 'name', + type: 'string', + internalType: 'string' + }, + { + name: 'symbol', + type: 'string', + internalType: 'string' + } + ], + outputs: [], + stateMutability: 'nonpayable' + }, + { + type: 'function', + name: 'mint', + inputs: [ + { + name: 'to', + type: 'address', + internalType: 'address' + }, + { + name: 'amount', + type: 'uint256', + internalType: 'uint256' + } + ], + outputs: [], + stateMutability: 'nonpayable' + }, + { + type: 'function', + name: 'name', + inputs: [], + outputs: [ + { + name: '', + type: 'string', + internalType: 'string' + } + ], + stateMutability: 'view' + }, + { + type: 'function', + name: 'owner', + inputs: [], + outputs: [ + { + name: '', + type: 'address', + internalType: 'address' + } + ], + stateMutability: 'view' + }, + { + type: 'function', + name: 'pause', + inputs: [], + outputs: [], + stateMutability: 'nonpayable' + }, + { + type: 'function', + name: 'paused', + inputs: [], + outputs: [ + { + name: '', + type: 'bool', + internalType: 'bool' + } + ], + stateMutability: 'view' + }, + { + type: 'function', + name: 'proxiableUUID', + inputs: [], + outputs: [ + { + name: '', + type: 'bytes32', + internalType: 'bytes32' + } + ], + stateMutability: 'view' + }, + { + type: 'function', + name: 'renounceOwnership', + inputs: [], + outputs: [], + stateMutability: 'nonpayable' + }, + { + type: 'function', + name: 'renounceRole', + inputs: [ + { + name: 'role', + type: 'bytes32', + internalType: 'bytes32' + }, + { + name: 'callerConfirmation', + type: 'address', + internalType: 'address' + } + ], + outputs: [], + stateMutability: 'nonpayable' + }, + { + type: 'function', + name: 'revokeRole', + inputs: [ + { + name: 'role', + type: 'bytes32', + internalType: 'bytes32' + }, + { + name: 'account', + type: 'address', + internalType: 'address' + } + ], + outputs: [], + stateMutability: 'nonpayable' + }, + { + type: 'function', + name: 'supportsInterface', + inputs: [ + { + name: 'interfaceId', + type: 'bytes4', + internalType: 'bytes4' + } + ], + outputs: [ + { + name: '', + type: 'bool', + internalType: 'bool' + } + ], + stateMutability: 'view' + }, + { + type: 'function', + name: 'symbol', + inputs: [], + outputs: [ + { + name: '', + type: 'string', + internalType: 'string' + } + ], + stateMutability: 'view' + }, + { + type: 'function', + name: 'totalSupply', + inputs: [], + outputs: [ + { + name: '', + type: 'uint256', + internalType: 'uint256' + } + ], + stateMutability: 'view' + }, + { + type: 'function', + name: 'transfer', + inputs: [ + { + name: 'to', + type: 'address', + internalType: 'address' + }, + { + name: 'value', + type: 'uint256', + internalType: 'uint256' + } + ], + outputs: [ + { + name: '', + type: 'bool', + internalType: 'bool' + } + ], + stateMutability: 'nonpayable' + }, + { + type: 'function', + name: 'transferFrom', + inputs: [ + { + name: 'from', + type: 'address', + internalType: 'address' + }, + { + name: 'to', + type: 'address', + internalType: 'address' + }, + { + name: 'value', + type: 'uint256', + internalType: 'uint256' + } + ], + outputs: [ + { + name: '', + type: 'bool', + internalType: 'bool' + } + ], + stateMutability: 'nonpayable' + }, + { + type: 'function', + name: 'transferOwnership', + inputs: [ + { + name: 'newOwner', + type: 'address', + internalType: 'address' + } + ], + outputs: [], + stateMutability: 'nonpayable' + }, + { + type: 'function', + name: 'unpause', + inputs: [], + outputs: [], + stateMutability: 'nonpayable' + }, + { + type: 'function', + name: 'upgradeToAndCall', + inputs: [ + { + name: 'newImplementation', + type: 'address', + internalType: 'address' + }, + { + name: 'data', + type: 'bytes', + internalType: 'bytes' + } + ], + outputs: [], + stateMutability: 'payable' + }, + { + type: 'event', + name: 'Approval', + inputs: [ + { + name: 'owner', + type: 'address', + indexed: true, + internalType: 'address' + }, + { + name: 'spender', + type: 'address', + indexed: true, + internalType: 'address' + }, + { + name: 'value', + type: 'uint256', + indexed: false, + internalType: 'uint256' + } + ], + anonymous: false + }, + { + type: 'event', + name: 'Initialized', + inputs: [ + { + name: 'version', + type: 'uint64', + indexed: false, + internalType: 'uint64' + } + ], + anonymous: false + }, + { + type: 'event', + name: 'OwnershipTransferred', + inputs: [ + { + name: 'previousOwner', + type: 'address', + indexed: true, + internalType: 'address' + }, + { + name: 'newOwner', + type: 'address', + indexed: true, + internalType: 'address' + } + ], + anonymous: false + }, + { + type: 'event', + name: 'Paused', + inputs: [ + { + name: 'account', + type: 'address', + indexed: false, + internalType: 'address' + } + ], + anonymous: false + }, + { + type: 'event', + name: 'RoleAdminChanged', + inputs: [ + { + name: 'role', + type: 'bytes32', + indexed: true, + internalType: 'bytes32' + }, + { + name: 'previousAdminRole', + type: 'bytes32', + indexed: true, + internalType: 'bytes32' + }, + { + name: 'newAdminRole', + type: 'bytes32', + indexed: true, + internalType: 'bytes32' + } + ], + anonymous: false + }, + { + type: 'event', + name: 'RoleGranted', + inputs: [ + { + name: 'role', + type: 'bytes32', + indexed: true, + internalType: 'bytes32' + }, + { + name: 'account', + type: 'address', + indexed: true, + internalType: 'address' + }, + { + name: 'sender', + type: 'address', + indexed: true, + internalType: 'address' + } + ], + anonymous: false + }, + { + type: 'event', + name: 'RoleRevoked', + inputs: [ + { + name: 'role', + type: 'bytes32', + indexed: true, + internalType: 'bytes32' + }, + { + name: 'account', + type: 'address', + indexed: true, + internalType: 'address' + }, + { + name: 'sender', + type: 'address', + indexed: true, + internalType: 'address' + } + ], + anonymous: false + }, + { + type: 'event', + name: 'Transfer', + inputs: [ + { + name: 'from', + type: 'address', + indexed: true, + internalType: 'address' + }, + { + name: 'to', + type: 'address', + indexed: true, + internalType: 'address' + }, + { + name: 'value', + type: 'uint256', + indexed: false, + internalType: 'uint256' + } + ], + anonymous: false + }, + { + type: 'event', + name: 'Unpaused', + inputs: [ + { + name: 'account', + type: 'address', + indexed: false, + internalType: 'address' + } + ], + anonymous: false + }, + { + type: 'event', + name: 'Upgraded', + inputs: [ + { + name: 'implementation', + type: 'address', + indexed: true, + internalType: 'address' + } + ], + anonymous: false + }, + { + type: 'error', + name: 'AccessControlBadConfirmation', + inputs: [] + }, + { + type: 'error', + name: 'AccessControlUnauthorizedAccount', + inputs: [ + { + name: 'account', + type: 'address', + internalType: 'address' + }, + { + name: 'neededRole', + type: 'bytes32', + internalType: 'bytes32' + } + ] + }, + { + type: 'error', + name: 'AddressEmptyCode', + inputs: [ + { + name: 'target', + type: 'address', + internalType: 'address' + } + ] + }, + { + type: 'error', + name: 'ERC1967InvalidImplementation', + inputs: [ + { + name: 'implementation', + type: 'address', + internalType: 'address' + } + ] + }, + { + type: 'error', + name: 'ERC1967NonPayable', + inputs: [] + }, + { + type: 'error', + name: 'ERC20InsufficientAllowance', + inputs: [ + { + name: 'spender', + type: 'address', + internalType: 'address' + }, + { + name: 'allowance', + type: 'uint256', + internalType: 'uint256' + }, + { + name: 'needed', + type: 'uint256', + internalType: 'uint256' + } + ] + }, + { + type: 'error', + name: 'ERC20InsufficientBalance', + inputs: [ + { + name: 'sender', + type: 'address', + internalType: 'address' + }, + { + name: 'balance', + type: 'uint256', + internalType: 'uint256' + }, + { + name: 'needed', + type: 'uint256', + internalType: 'uint256' + } + ] + }, + { + type: 'error', + name: 'ERC20InvalidApprover', + inputs: [ + { + name: 'approver', + type: 'address', + internalType: 'address' + } + ] + }, + { + type: 'error', + name: 'ERC20InvalidReceiver', + inputs: [ + { + name: 'receiver', + type: 'address', + internalType: 'address' + } + ] + }, + { + type: 'error', + name: 'ERC20InvalidSender', + inputs: [ + { + name: 'sender', + type: 'address', + internalType: 'address' + } + ] + }, + { + type: 'error', + name: 'ERC20InvalidSpender', + inputs: [ + { + name: 'spender', + type: 'address', + internalType: 'address' + } + ] + }, + { + type: 'error', + name: 'EnforcedPause', + inputs: [] + }, + { + type: 'error', + name: 'ExpectedPause', + inputs: [] + }, + { + type: 'error', + name: 'FailedInnerCall', + inputs: [] + }, + { + type: 'error', + name: 'InvalidInitialization', + inputs: [] + }, + { + type: 'error', + name: 'MustHaveMinterRole', + inputs: [ + { + name: 'account', + type: 'address', + internalType: 'address' + } + ] + }, + { + type: 'error', + name: 'NotInitializing', + inputs: [] + }, + { + type: 'error', + name: 'OwnableInvalidOwner', + inputs: [ + { + name: 'owner', + type: 'address', + internalType: 'address' + } + ] + }, + { + type: 'error', + name: 'OwnableUnauthorizedAccount', + inputs: [ + { + name: 'account', + type: 'address', + internalType: 'address' + } + ] + }, + { + type: 'error', + name: 'UUPSUnauthorizedCallContext', + inputs: [] + }, + { + type: 'error', + name: 'UUPSUnsupportedProxiableUUID', + inputs: [ + { + name: 'slot', + type: 'bytes32', + internalType: 'bytes32' + } + ] + } +]; + +export const TOKEN_BYTECODE = + '0x60a06040523060805234801561001457600080fd5b50608051611db461003e60003960008181610e8d01528181610eb60152610ff70152611db46000f3fe6080604052600436106101d85760003560e01c806370a0823111610102578063a9059cbb11610095578063d547741f11610064578063d547741f14610583578063dd62ed3e146105a3578063e63ab1e9146105c3578063f2fde38b146105e557600080fd5b8063a9059cbb146104f0578063ad3cb1cc14610510578063c1abece914610541578063d53913931461056157600080fd5b80638da5cb5b116100d15780638da5cb5b1461045f57806391d14854146104a657806395d89b41146104c6578063a217fddf146104db57600080fd5b806370a08231146103d2578063715018a61461041557806379cc67901461042a5780638456cb591461044a57600080fd5b8063313ce5671161017a57806342966c681161014957806342966c68146103655780634f1ef2861461038557806352d1902d146103985780635c975abb146103ad57600080fd5b8063313ce567146102f457806336568abe146103105780633f4ba83a1461033057806340c10f191461034557600080fd5b806318160ddd116101b657806318160ddd1461025457806323b872dd14610292578063248a9ca3146102b25780632f2ff15d146102d257600080fd5b806301ffc9a7146101dd57806306fdde0314610212578063095ea7b314610234575b600080fd5b3480156101e957600080fd5b506101fd6101f8366004611735565b610605565b60405190151581526020015b60405180910390f35b34801561021e57600080fd5b5061022761063c565b6040516102099190611783565b34801561024057600080fd5b506101fd61024f3660046117d2565b6106ff565b34801561026057600080fd5b507f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace02545b604051908152602001610209565b34801561029e57600080fd5b506101fd6102ad3660046117fc565b610717565b3480156102be57600080fd5b506102846102cd366004611838565b61073d565b3480156102de57600080fd5b506102f26102ed366004611851565b61075f565b005b34801561030057600080fd5b5060405160068152602001610209565b34801561031c57600080fd5b506102f261032b366004611851565b610781565b34801561033c57600080fd5b506102f26107b9565b34801561035157600080fd5b506102f26103603660046117d2565b6107dc565b34801561037157600080fd5b506102f2610380366004611838565b610826565b6102f261039336600461191c565b610830565b3480156103a457600080fd5b5061028461084b565b3480156103b957600080fd5b50600080516020611d5f8339815191525460ff166101fd565b3480156103de57600080fd5b506102846103ed36600461197e565b6001600160a01b03166000908152600080516020611cbf833981519152602052604090205490565b34801561042157600080fd5b506102f2610868565b34801561043657600080fd5b506102f26104453660046117d2565b61087c565b34801561045657600080fd5b506102f26108bd565b34801561046b57600080fd5b507f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546040516001600160a01b039091168152602001610209565b3480156104b257600080fd5b506101fd6104c1366004611851565b6108dd565b3480156104d257600080fd5b50610227610915565b3480156104e757600080fd5b50610284600081565b3480156104fc57600080fd5b506101fd61050b3660046117d2565b610954565b34801561051c57600080fd5b50610227604051806040016040528060058152602001640352e302e360dc1b81525081565b34801561054d57600080fd5b506102f261055c3660046119b9565b610962565b34801561056d57600080fd5b50610284600080516020611d1f83398151915281565b34801561058f57600080fd5b506102f261059e366004611851565b610b1e565b3480156105af57600080fd5b506102846105be366004611abf565b610b3a565b3480156105cf57600080fd5b50610284600080516020611cff83398151915281565b3480156105f157600080fd5b506102f261060036600461197e565b610b84565b60006001600160e01b03198216637965db0b60e01b148061063657506301ffc9a760e01b6001600160e01b03198316145b92915050565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace038054606091600080516020611cbf8339815191529161067b90611ae9565b80601f01602080910402602001604051908101604052809291908181526020018280546106a790611ae9565b80156106f45780601f106106c9576101008083540402835291602001916106f4565b820191906000526020600020905b8154815290600101906020018083116106d757829003601f168201915b505050505091505090565b60003361070d818585610bbf565b5060019392505050565b600033610725858285610bcc565b610730858585610c2c565b60019150505b9392505050565b6000908152600080516020611d3f833981519152602052604090206001015490565b6107688261073d565b61077181610c8b565b61077b8383610c95565b50505050565b6001600160a01b03811633146107aa5760405163334bd91960e11b815260040160405180910390fd5b6107b48282610d3a565b505050565b600080516020611cff8339815191526107d181610c8b565b6107d9610db6565b50565b6107f4600080516020611d1f833981519152336108dd565b61081857604051636690b7c160e01b81523360048201526024015b60405180910390fd5b6108228282610e16565b5050565b6107d93382610e4c565b610838610e82565b61084182610f27565b6108228282610f2f565b6000610855610fec565b50600080516020611cdf83398151915290565b610870611035565b61087a6000611090565b565b610894600080516020611d1f833981519152336108dd565b6108b357604051636690b7c160e01b815233600482015260240161080f565b6108228282610e4c565b600080516020611cff8339815191526108d581610c8b565b6107d9611101565b6000918252600080516020611d3f833981519152602090815260408084206001600160a01b0393909316845291905290205460ff1690565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace048054606091600080516020611cbf8339815191529161067b90611ae9565b60003361070d818585610c2c565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff16159067ffffffffffffffff166000811580156109a85750825b905060008267ffffffffffffffff1660011480156109c55750303b155b9050811580156109d3575080155b156109f15760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff191660011785558315610a1b57845460ff60401b1916600160401b1785555b610a25878761114a565b610a2e8961115c565b610a3661116d565b610a3e61116d565b610a4960008a610c95565b50610a63600080516020611d1f8339815191526000611175565b610a7c600080516020611cff8339815191526000611175565b60005b8851811015610acc57610ab9600080516020611d1f8339815191528a8381518110610aac57610aac611b23565b6020026020010151610c95565b5080610ac481611b4f565b915050610a7f565b508315610b1357845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b505050505050505050565b610b278261073d565b610b3081610c8b565b61077b8383610d3a565b6001600160a01b0391821660009081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace016020908152604080832093909416825291909152205490565b610b8c611035565b6001600160a01b038116610bb657604051631e4fbdf760e01b81526000600482015260240161080f565b6107d981611090565b6107b483838360016111d8565b6000610bd88484610b3a565b9050600019811461077b5781811015610c1d57604051637dc7a0d960e11b81526001600160a01b0384166004820152602481018290526044810183905260640161080f565b61077b848484840360006111d8565b6001600160a01b038316610c5657604051634b637e8f60e11b81526000600482015260240161080f565b6001600160a01b038216610c805760405163ec442f0560e01b81526000600482015260240161080f565b6107b48383836112c0565b6107d981336112d3565b6000600080516020611d3f833981519152610cb084846108dd565b610d30576000848152602082815260408083206001600160a01b03871684529091529020805460ff19166001179055610ce63390565b6001600160a01b0316836001600160a01b0316857f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a46001915050610636565b6000915050610636565b6000600080516020611d3f833981519152610d5584846108dd565b15610d30576000848152602082815260408083206001600160a01b0387168085529252808320805460ff1916905551339287917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a46001915050610636565b610dbe61130c565b600080516020611d5f833981519152805460ff191681557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a150565b6001600160a01b038216610e405760405163ec442f0560e01b81526000600482015260240161080f565b610822600083836112c0565b6001600160a01b038216610e7657604051634b637e8f60e11b81526000600482015260240161080f565b610822826000836112c0565b306001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161480610f0957507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316610efd600080516020611cdf833981519152546001600160a01b031690565b6001600160a01b031614155b1561087a5760405163703e46dd60e11b815260040160405180910390fd5b6107d9611035565b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015610f89575060408051601f3d908101601f19168201909252610f8691810190611b68565b60015b610fb157604051634c9c8ce360e01b81526001600160a01b038316600482015260240161080f565b600080516020611cdf8339815191528114610fe257604051632a87526960e21b81526004810182905260240161080f565b6107b4838361133c565b306001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461087a5760405163703e46dd60e11b815260040160405180910390fd5b336110677f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b6001600160a01b03161461087a5760405163118cdaa760e01b815233600482015260240161080f565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b611109611392565b600080516020611d5f833981519152805460ff191660011781557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25833610df8565b6111526113c3565b610822828261140c565b6111646113c3565b6107d98161145d565b61087a6113c3565b600080516020611d3f833981519152600061118f8461073d565b600085815260208490526040808220600101869055519192508491839187917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a450505050565b600080516020611cbf8339815191526001600160a01b0385166112115760405163e602df0560e01b81526000600482015260240161080f565b6001600160a01b03841661123b57604051634a1406b160e11b81526000600482015260240161080f565b6001600160a01b038086166000908152600183016020908152604080832093881683529290522083905581156112b957836001600160a01b0316856001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925856040516112b091815260200190565b60405180910390a35b5050505050565b6112c8611392565b6107b4838383611465565b6112dd82826108dd565b6108225760405163e2517d3f60e01b81526001600160a01b03821660048201526024810183905260440161080f565b600080516020611d5f8339815191525460ff1661087a57604051638dfc202b60e01b815260040160405180910390fd5b61134582611478565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a280511561138a576107b482826114dd565b610822611553565b600080516020611d5f8339815191525460ff161561087a5760405163d93c066560e01b815260040160405180910390fd5b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff1661087a57604051631afcd79f60e31b815260040160405180910390fd5b6114146113c3565b600080516020611cbf8339815191527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0361144e8482611bcf565b506004810161077b8382611bcf565b610b8c6113c3565b61146d611392565b6107b4838383611572565b806001600160a01b03163b6000036114ae57604051634c9c8ce360e01b81526001600160a01b038216600482015260240161080f565b600080516020611cdf83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b6060600080846001600160a01b0316846040516114fa9190611c8f565b600060405180830381855af49150503d8060008114611535576040519150601f19603f3d011682016040523d82523d6000602084013e61153a565b606091505b509150915061154a8583836116b0565b95945050505050565b341561087a5760405163b398979f60e01b815260040160405180910390fd5b600080516020611cbf8339815191526001600160a01b0384166115ae57818160020160008282546115a39190611cab565b909155506116209050565b6001600160a01b038416600090815260208290526040902054828110156116015760405163391434e360e21b81526001600160a01b0386166004820152602481018290526044810184905260640161080f565b6001600160a01b03851660009081526020839052604090209083900390555b6001600160a01b03831661163e57600281018054839003905561165d565b6001600160a01b03831660009081526020829052604090208054830190555b826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516116a291815260200190565b60405180910390a350505050565b6060826116c5576116c08261170c565b610736565b81511580156116dc57506001600160a01b0384163b155b1561170557604051639996b31560e01b81526001600160a01b038516600482015260240161080f565b5080610736565b80511561171c5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b60006020828403121561174757600080fd5b81356001600160e01b03198116811461073657600080fd5b60005b8381101561177a578181015183820152602001611762565b50506000910152565b60208152600082518060208401526117a281604085016020870161175f565b601f01601f19169190910160400192915050565b80356001600160a01b03811681146117cd57600080fd5b919050565b600080604083850312156117e557600080fd5b6117ee836117b6565b946020939093013593505050565b60008060006060848603121561181157600080fd5b61181a846117b6565b9250611828602085016117b6565b9150604084013590509250925092565b60006020828403121561184a57600080fd5b5035919050565b6000806040838503121561186457600080fd5b82359150611874602084016117b6565b90509250929050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff811182821017156118bc576118bc61187d565b604052919050565b600067ffffffffffffffff8311156118de576118de61187d565b6118f1601f8401601f1916602001611893565b905082815283838301111561190557600080fd5b828260208301376000602084830101529392505050565b6000806040838503121561192f57600080fd5b611938836117b6565b9150602083013567ffffffffffffffff81111561195457600080fd5b8301601f8101851361196557600080fd5b611974858235602084016118c4565b9150509250929050565b60006020828403121561199057600080fd5b610736826117b6565b600082601f8301126119aa57600080fd5b610736838335602085016118c4565b600080600080608085870312156119cf57600080fd5b6119d8856117b6565b935060208086013567ffffffffffffffff808211156119f657600080fd5b818801915088601f830112611a0a57600080fd5b813581811115611a1c57611a1c61187d565b8060051b611a2b858201611893565b918252838101850191858101908c841115611a4557600080fd5b948601945b83861015611a6a57611a5b866117b6565b82529486019490860190611a4a565b98505050506040880135925080831115611a8357600080fd5b611a8f89848a01611999565b94506060880135925080831115611aa557600080fd5b5050611ab387828801611999565b91505092959194509250565b60008060408385031215611ad257600080fd5b611adb836117b6565b9150611874602084016117b6565b600181811c90821680611afd57607f821691505b602082108103611b1d57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201611b6157611b61611b39565b5060010190565b600060208284031215611b7a57600080fd5b5051919050565b601f8211156107b457600081815260208120601f850160051c81016020861015611ba85750805b601f850160051c820191505b81811015611bc757828155600101611bb4565b505050505050565b815167ffffffffffffffff811115611be957611be961187d565b611bfd81611bf78454611ae9565b84611b81565b602080601f831160018114611c325760008415611c1a5750858301515b600019600386901b1c1916600185901b178555611bc7565b600085815260208120601f198616915b82811015611c6157888601518255948401946001909101908401611c42565b5085821015611c7f5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60008251611ca181846020870161175f565b9190910192915050565b8082018082111561063657610636611b3956fe52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a602dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800cd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300a26469706673582212208eafdded02d0ded1b81e9117ce8d3c308edf5880a224d8acd82bd3fe0174eb3b64736f6c63430008140033'; diff --git a/app/[alias]/(dashboard)/checkout/page.tsx b/app/[alias]/(dashboard)/checkout/page.tsx index ea221732..4f174330 100644 --- a/app/[alias]/(dashboard)/checkout/page.tsx +++ b/app/[alias]/(dashboard)/checkout/page.tsx @@ -1,156 +1,156 @@ -import { auth } from '@/auth'; -import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; -import { Skeleton } from '@/components/ui/skeleton'; -import { getServiceRoleClient } from '@/services/top-db'; -import { getCommunityByAlias } from '@/services/top-db/community'; -import { CommunityConfig, Config, getAccountBalance, getTwoFAAddress } from '@citizenwallet/sdk'; -import { formatUnits } from 'ethers'; -import { Suspense } from 'react'; -import { CheckoutFlow } from './checkout-flow'; - -interface CheckoutPageProps { - params: Promise<{ alias: string }>; - searchParams: Promise<{ - option: 'byoc' | 'create'; - address: string; - }>; -} - -export default async function CheckoutPage(props: CheckoutPageProps) { - const { alias } = await props.params; - - const { option, address } = await props.searchParams; - - const client = getServiceRoleClient(); - const { data, error } = await getCommunityByAlias(client, alias); - - if (error || !data) { - throw new Error('Failed to get community by alias'); - } - - const config = data.json; - - - const { data: ctzn_data, error: ctzn_error } = await getCommunityByAlias(client, 'ctzn'); - - if (ctzn_error || !ctzn_data) { - throw new Error('Failed to get CTZN community by alias'); - } - - const CTZN_config = ctzn_data.json; - - - const chains = [ - { id: '100', name: 'Gnosis' }, - { id: '42220', name: 'Celo' }, - { id: '42161', name: 'Arbitrum' }, - { id: '137', name: 'Polygon' } - ]; - - return ( -
-
-
-

Activate your token

-

- In order to get started, we need to set up a few things on {chains.find(chain => Number(chain.id) === data.chain_id)?.name}. This process is powered by CTZN tokens. -

-
-
- - { - option !== 'byoc' && option !== 'create' ? ( -
-

- Invalid option -

-
- ) : ( - }> - - - ) - } - -
- ); -} - -async function CheckoutLoader({ - option, config, address, ctzn_config -}: { - option: 'byoc' | 'create', - config: Config, - address: string, - ctzn_config: Config -}) { - - const communityConfig = new CommunityConfig(config); - const tokenName = communityConfig.primaryToken.name; - const tokenSymbol = communityConfig.primaryToken.symbol; - - const session = await auth(); - if (!session) { - throw new Error('You are not logged in'); - } - - const { email } = session.user; - if (!email) { - throw new Error('You are not logged in'); - } - - const ctzn_communityConfig = new CommunityConfig(ctzn_config); - - const accountAddress = await getTwoFAAddress({ - community: ctzn_communityConfig, - source: email, - type: 'email' - }); - - if (!accountAddress) { - throw new Error('Account address not found'); - } - - const balance = await getAccountBalance( - ctzn_communityConfig, - accountAddress - ); - - - return ; -} - -function CheckoutSkeleton() { - return ( - - - - - - - -
- - -
-
- - -
-
- - -
-
-
- ); -} +import { auth } from '@/auth'; +import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; +import { Skeleton } from '@/components/ui/skeleton'; +import { getServiceRoleClient } from '@/services/top-db'; +import { getCommunityByAlias } from '@/services/top-db/community'; +import { CommunityConfig, Config, getAccountBalance, getTwoFAAddress } from '@citizenwallet/sdk'; +import { formatUnits } from 'ethers'; +import { Suspense } from 'react'; +import { CheckoutFlow } from './checkout-flow'; + +interface CheckoutPageProps { + params: Promise<{ alias: string }>; + searchParams: Promise<{ + option: 'byoc' | 'create'; + address: string; + }>; +} + +export default async function CheckoutPage(props: CheckoutPageProps) { + const { alias } = await props.params; + + const { option, address } = await props.searchParams; + + const client = getServiceRoleClient(); + const { data, error } = await getCommunityByAlias(client, alias); + + if (error || !data) { + throw new Error('Failed to get community by alias'); + } + + const config = data.json; + + + const { data: ctzn_data, error: ctzn_error } = await getCommunityByAlias(client, 'ctzn'); + + if (ctzn_error || !ctzn_data) { + throw new Error('Failed to get CTZN community by alias'); + } + + const CTZN_config = ctzn_data.json; + + + const chains = [ + { id: '100', name: 'Gnosis' }, + { id: '42220', name: 'Celo' }, + { id: '42161', name: 'Arbitrum' }, + { id: '137', name: 'Polygon' } + ]; + + return ( +
+
+
+

Activate your token

+

+ In order to get started, we need to set up a few things on {chains.find(chain => Number(chain.id) === data.chain_id)?.name}. This process is powered by CTZN tokens. +

+
+
+ + { + option !== 'byoc' && option !== 'create' ? ( +
+

+ Invalid option +

+
+ ) : ( + }> + + + ) + } + +
+ ); +} + +async function CheckoutLoader({ + option, config, address, ctzn_config +}: { + option: 'byoc' | 'create', + config: Config, + address: string, + ctzn_config: Config +}) { + + const communityConfig = new CommunityConfig(config); + const tokenName = communityConfig.primaryToken.name; + const tokenSymbol = communityConfig.primaryToken.symbol; + + const session = await auth(); + if (!session) { + throw new Error('You are not logged in'); + } + + const { email } = session.user; + if (!email) { + throw new Error('You are not logged in'); + } + + const ctzn_communityConfig = new CommunityConfig(ctzn_config); + + const accountAddress = await getTwoFAAddress({ + community: ctzn_communityConfig, + source: email, + type: 'email' + }); + + if (!accountAddress) { + throw new Error('Account address not found'); + } + + const balance = await getAccountBalance( + ctzn_communityConfig, + accountAddress + ); + + + return ; +} + +function CheckoutSkeleton() { + return ( + + + + + + + +
+ + +
+
+ + +
+
+ + +
+
+
+ ); +} diff --git a/app/[alias]/(dashboard)/configuration/_components/byoc-fallback.tsx b/app/[alias]/(dashboard)/configuration/_components/byoc-fallback.tsx index 8c6d0092..1cc3bdd1 100644 --- a/app/[alias]/(dashboard)/configuration/_components/byoc-fallback.tsx +++ b/app/[alias]/(dashboard)/configuration/_components/byoc-fallback.tsx @@ -1,42 +1,42 @@ -import { Skeleton } from '@/components/ui/skeleton'; - -export default function ByocFallback() { - return ( - <> -
-
-
-

Bring Your Own Currency

-

Configure your existing ERC20 token

-
-
- -
-
- {/* Token Address Field Skeleton */} -
- - - -
- - {/* Icon Upload Field Skeleton */} -
- -
- - - -
- -
- -
- -
-
-
-
- - ) -} +import { Skeleton } from '@/components/ui/skeleton'; + +export default function ByocFallback() { + return ( + <> +
+
+
+

Bring Your Own Currency

+

Configure your existing ERC20 token

+
+
+ +
+
+ {/* Token Address Field Skeleton */} +
+ + + +
+ + {/* Icon Upload Field Skeleton */} +
+ +
+ + + +
+ +
+ +
+ +
+
+
+
+ + ) +} diff --git a/app/[alias]/(dashboard)/configuration/_components/create-fallback.tsx b/app/[alias]/(dashboard)/configuration/_components/create-fallback.tsx index 5b26aae7..7f01510c 100644 --- a/app/[alias]/(dashboard)/configuration/_components/create-fallback.tsx +++ b/app/[alias]/(dashboard)/configuration/_components/create-fallback.tsx @@ -1,49 +1,49 @@ -import { Skeleton } from '@/components/ui/skeleton'; - -export default function CreateFallback() { - return ( - <> -
-
-
-

Create Your Own Currency

-

Design your community token

-
-
- -
-
- {/* Token Name Field Skeleton */} -
- - - -
- - {/* Token Symbol Field Skeleton */} -
- - - -
- - {/* Icon Upload Field Skeleton */} -
- -
- - - -
- -
- -
- -
-
-
-
- - ) -} +import { Skeleton } from '@/components/ui/skeleton'; + +export default function CreateFallback() { + return ( + <> +
+
+
+

Create Your Own Currency

+

Design your community token

+
+
+ +
+
+ {/* Token Name Field Skeleton */} +
+ + + +
+ + {/* Token Symbol Field Skeleton */} +
+ + + +
+ + {/* Icon Upload Field Skeleton */} +
+ +
+ + + +
+ +
+ +
+ +
+
+
+
+ + ) +} diff --git a/app/[alias]/(dashboard)/configuration/_components/fallback.tsx b/app/[alias]/(dashboard)/configuration/_components/fallback.tsx index ab9c8d22..ab059629 100644 --- a/app/[alias]/(dashboard)/configuration/_components/fallback.tsx +++ b/app/[alias]/(dashboard)/configuration/_components/fallback.tsx @@ -1,54 +1,54 @@ -import { Skeleton } from '@/components/ui/skeleton'; - -export default function Fallback() { - return ( -
-
-

Currency Configuration

-

- Choose how you want to set up your community currency -

-
- -
- {/* First Card Skeleton */} -
-
-
- -
- - -
-
-
-
-
- - -
-
-
- - {/* Second Card Skeleton */} -
-
-
- -
- - -
-
-
-
-
- - -
-
-
-
-
- ); -} +import { Skeleton } from '@/components/ui/skeleton'; + +export default function Fallback() { + return ( +
+
+

Currency Configuration

+

+ Choose how you want to set up your community currency +

+
+ +
+ {/* First Card Skeleton */} +
+
+
+ +
+ + +
+
+
+
+
+ + +
+
+
+ + {/* Second Card Skeleton */} +
+
+
+ +
+ + +
+
+
+
+
+ + +
+
+
+
+
+ ); +} diff --git a/app/[alias]/(dashboard)/configuration/_components/iconUpload.tsx b/app/[alias]/(dashboard)/configuration/_components/iconUpload.tsx index 8b2b7ab8..f6327b84 100644 --- a/app/[alias]/(dashboard)/configuration/_components/iconUpload.tsx +++ b/app/[alias]/(dashboard)/configuration/_components/iconUpload.tsx @@ -1,105 +1,105 @@ -'use client' - -import { Button } from "@/components/ui/button"; -import { Upload, X } from "lucide-react"; -import { useEffect, useState } from "react"; -import { toast } from "sonner"; -import Image from "next/image"; - - -export const IconUpload = ({ value, onChange }: { value?: File | string; onChange: (file?: File | string) => void }) => { - const [preview, setPreview] = useState(null); - - // Set initial preview if there's an existing logo URL - useEffect(() => { - if (typeof value === 'string' && value) { - setPreview(value); - } - }, [value]); - - const handleFileChange = (e: React.ChangeEvent) => { - const file = e.target.files?.[0]; - if (file) { - // Validate file type - if (!file.type.match(/^image\/(svg\+xml|png)$/)) { - toast.error('Please select a .svg or .png file'); - return; - } - - // Validate file size (max 5MB) - if (file.size > 5 * 1024 * 1024) { - toast.error('File size must be less than 5MB'); - return; - } - - onChange(file); - - // Create preview - const reader = new FileReader(); - reader.onload = (e) => { - setPreview(e.target?.result as string); - }; - reader.readAsDataURL(file); - } - }; - - const handleRemove = () => { - onChange(undefined); - setPreview(null); - }; - - return ( -
-
- -
- {value && typeof value === 'object' && ( -

- Selected: {value.name} ({(value.size / 1024).toFixed(1)} KB) -

- )} - {value && typeof value === 'string' && ( -

- Current logo: {value} -

- )} -
- ); -}; +'use client' + +import { Button } from "@/components/ui/button"; +import { Upload, X } from "lucide-react"; +import { useEffect, useState } from "react"; +import { toast } from "sonner"; +import Image from "next/image"; + + +export const IconUpload = ({ value, onChange }: { value?: File | string; onChange: (file?: File | string) => void }) => { + const [preview, setPreview] = useState(null); + + // Set initial preview if there's an existing logo URL + useEffect(() => { + if (typeof value === 'string' && value) { + setPreview(value); + } + }, [value]); + + const handleFileChange = (e: React.ChangeEvent) => { + const file = e.target.files?.[0]; + if (file) { + // Validate file type + if (!file.type.match(/^image\/(svg\+xml|png)$/)) { + toast.error('Please select a .svg or .png file'); + return; + } + + // Validate file size (max 5MB) + if (file.size > 5 * 1024 * 1024) { + toast.error('File size must be less than 5MB'); + return; + } + + onChange(file); + + // Create preview + const reader = new FileReader(); + reader.onload = (e) => { + setPreview(e.target?.result as string); + }; + reader.readAsDataURL(file); + } + }; + + const handleRemove = () => { + onChange(undefined); + setPreview(null); + }; + + return ( +
+
+ +
+ {value && typeof value === 'object' && ( +

+ Selected: {value.name} ({(value.size / 1024).toFixed(1)} KB) +

+ )} + {value && typeof value === 'string' && ( +

+ Current logo: {value} +

+ )} +
+ ); +}; diff --git a/app/[alias]/(dashboard)/configuration/action.ts b/app/[alias]/(dashboard)/configuration/action.ts index 6d6c83d4..7ece22f5 100644 --- a/app/[alias]/(dashboard)/configuration/action.ts +++ b/app/[alias]/(dashboard)/configuration/action.ts @@ -1,217 +1,217 @@ -'use server'; - -import { - getAuthUserRoleInAppAction, - getAuthUserRoleInCommunityAction -} from '@/app/_actions/user-actions'; -import { getServiceRoleClient as getServiceRoleClientChainDb } from '@/services/chain-db'; -import { insertEvent } from '@/services/chain-db/event'; -import { uploadImage } from '@/services/storage'; -import { getServiceRoleClient } from '@/services/top-db'; -import { updateCommunityJson } from '@/services/top-db/community'; -import { CommunityConfig, Config, getTokenMetadata } from '@citizenwallet/sdk'; -import { ethers } from 'ethers'; - -const CHAIN_ID_TO_RPC_URL = (chainId: string) => { - switch (chainId) { - case '137': - return process.env.POLYGON_RPC_URL; - case '100': - return process.env.GNOSIS_RPC_URL; - case '42220': - return process.env.CELO_RPC_URL; - case '42161': - return process.env.ARBITRUM_RPC_URL; - default: - return process.env.BASE_RPC_URL; - } -}; - -export async function uploadIconAction(imageFile: File, alias: string) { - const client = getServiceRoleClient(); - - const roleInCommunity = await getAuthUserRoleInCommunityAction({ - alias - }); - - const roleInApp = await getAuthUserRoleInAppAction(); - - if (!roleInApp) { - throw new Error('Unauthenticated user'); - } - - if (roleInApp === 'user' && !roleInCommunity) { - throw new Error('You are not a member of this community'); - } - - try { - // Upload the image to storage - const imageUrl = await uploadImage(client, imageFile, alias); - - return imageUrl; - } catch (error) { - console.error('Error uploading image:', error); - throw new Error('Failed to upload image'); - } -} - -export async function createByocAction( - config: Config, - tokenAddress: string, - icon: string, - decimals: number, - symbol: string, - name: string -) { - const client = getServiceRoleClient(); - - const roleInCommunity = await getAuthUserRoleInCommunityAction({ - alias: config.community.alias - }); - - const roleInApp = await getAuthUserRoleInAppAction(); - - if (!roleInApp) { - throw new Error('Unauthenticated user'); - } - - if (roleInApp === 'user' && !roleInCommunity) { - throw new Error('You are not a member of this community'); - } - - try { - const updateJson = { - ...config, - tokens: { - ...config.tokens, - [`${config.community.primary_token.chain_id}:${tokenAddress}`]: { - name, - symbol, - address: tokenAddress, - chain_id: config.community.primary_token.chain_id, - decimals, - standard: 'erc20' - } - }, - community: { - ...config.community, - logo: icon, - primary_token: { - ...config.community.primary_token, - address: tokenAddress - } - } - }; - - const [updateCommunityJsonPromise] = await Promise.allSettled([ - updateCommunityJson(client, config.community.alias, { - json: updateJson - }), - - insertEvent({ - client: getServiceRoleClientChainDb( - config.community.primary_token.chain_id - ), - chainId: config.community.primary_token.chain_id.toString(), - event: { - name: `${config.community.alias} Transfer`, - contract: tokenAddress, - event_signature: - 'Transfer (index_topic_1 address from, index_topic_2 address to, uint256 value)', - topic: - '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', - alias: config.community.alias - } - }) - ]); - - const data = - updateCommunityJsonPromise.status === 'fulfilled' - ? updateCommunityJsonPromise.value.data - : []; - - return data; - } catch (error) { - console.error('Error creating BYOC:', error); - throw new Error('Failed to create BYOC'); - } -} - -export async function createTokenAction( - config: Config, - icon: string, - symbol: string, - name: string -) { - const client = getServiceRoleClient(); - - const roleInCommunity = await getAuthUserRoleInCommunityAction({ - alias: config.community.alias - }); - - const roleInApp = await getAuthUserRoleInAppAction(); - - if (!roleInApp) { - throw new Error('Unauthenticated user'); - } - - if (roleInApp === 'user' && !roleInCommunity) { - throw new Error('You are not a member of this community'); - } - - try { - const tokenAddress = ethers.ZeroAddress; - - const updateJson = { - ...config, - tokens: { - ...config.tokens, - [`${config.community.primary_token.chain_id}:${tokenAddress}`]: { - name, - symbol, - address: tokenAddress, - chain_id: config.community.primary_token.chain_id, - decimals: 18, - standard: 'erc20' - } - }, - community: { - ...config.community, - logo: icon, - primary_token: { - ...config.community.primary_token, - address: tokenAddress - } - } - }; - - const updateCommunity = await updateCommunityJson( - client, - config.community.alias, - { - json: updateJson - } - ); - - return updateCommunity; - } catch (error) { - console.error('Error creating token:', error); - } -} - -export async function getTokenMetadataAction( - config: Config, - tokenAddress: string -) { - const communityConfig = new CommunityConfig(config); - const rpcUrl = CHAIN_ID_TO_RPC_URL( - config.community.profile.chain_id.toString() - ); - - const tokenMetadata = await getTokenMetadata(communityConfig, { - tokenAddress, - rpcUrl - }); - - return tokenMetadata; -} +'use server'; + +import { + getAuthUserRoleInAppAction, + getAuthUserRoleInCommunityAction +} from '@/app/_actions/user-actions'; +import { getServiceRoleClient as getServiceRoleClientChainDb } from '@/services/chain-db'; +import { insertEvent } from '@/services/chain-db/event'; +import { uploadImage } from '@/services/storage'; +import { getServiceRoleClient } from '@/services/top-db'; +import { updateCommunityJson } from '@/services/top-db/community'; +import { CommunityConfig, Config, getTokenMetadata } from '@citizenwallet/sdk'; +import { ethers } from 'ethers'; + +const CHAIN_ID_TO_RPC_URL = (chainId: string) => { + switch (chainId) { + case '137': + return process.env.POLYGON_RPC_URL; + case '100': + return process.env.GNOSIS_RPC_URL; + case '42220': + return process.env.CELO_RPC_URL; + case '42161': + return process.env.ARBITRUM_RPC_URL; + default: + return process.env.BASE_RPC_URL; + } +}; + +export async function uploadIconAction(imageFile: File, alias: string) { + const client = getServiceRoleClient(); + + const roleInCommunity = await getAuthUserRoleInCommunityAction({ + alias + }); + + const roleInApp = await getAuthUserRoleInAppAction(); + + if (!roleInApp) { + throw new Error('Unauthenticated user'); + } + + if (roleInApp === 'user' && !roleInCommunity) { + throw new Error('You are not a member of this community'); + } + + try { + // Upload the image to storage + const imageUrl = await uploadImage(client, imageFile, alias); + + return imageUrl; + } catch (error) { + console.error('Error uploading image:', error); + throw new Error('Failed to upload image'); + } +} + +export async function createByocAction( + config: Config, + tokenAddress: string, + icon: string, + decimals: number, + symbol: string, + name: string +) { + const client = getServiceRoleClient(); + + const roleInCommunity = await getAuthUserRoleInCommunityAction({ + alias: config.community.alias + }); + + const roleInApp = await getAuthUserRoleInAppAction(); + + if (!roleInApp) { + throw new Error('Unauthenticated user'); + } + + if (roleInApp === 'user' && !roleInCommunity) { + throw new Error('You are not a member of this community'); + } + + try { + const updateJson = { + ...config, + tokens: { + ...config.tokens, + [`${config.community.primary_token.chain_id}:${tokenAddress}`]: { + name, + symbol, + address: tokenAddress, + chain_id: config.community.primary_token.chain_id, + decimals, + standard: 'erc20' + } + }, + community: { + ...config.community, + logo: icon, + primary_token: { + ...config.community.primary_token, + address: tokenAddress + } + } + }; + + const [updateCommunityJsonPromise] = await Promise.allSettled([ + updateCommunityJson(client, config.community.alias, { + json: updateJson + }), + + insertEvent({ + client: getServiceRoleClientChainDb( + config.community.primary_token.chain_id + ), + chainId: config.community.primary_token.chain_id.toString(), + event: { + name: `${config.community.alias} Transfer`, + contract: tokenAddress, + event_signature: + 'Transfer (index_topic_1 address from, index_topic_2 address to, uint256 value)', + topic: + '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', + alias: config.community.alias + } + }) + ]); + + const data = + updateCommunityJsonPromise.status === 'fulfilled' + ? updateCommunityJsonPromise.value.data + : []; + + return data; + } catch (error) { + console.error('Error creating BYOC:', error); + throw new Error('Failed to create BYOC'); + } +} + +export async function createTokenAction( + config: Config, + icon: string, + symbol: string, + name: string +) { + const client = getServiceRoleClient(); + + const roleInCommunity = await getAuthUserRoleInCommunityAction({ + alias: config.community.alias + }); + + const roleInApp = await getAuthUserRoleInAppAction(); + + if (!roleInApp) { + throw new Error('Unauthenticated user'); + } + + if (roleInApp === 'user' && !roleInCommunity) { + throw new Error('You are not a member of this community'); + } + + try { + const tokenAddress = ethers.ZeroAddress; + + const updateJson = { + ...config, + tokens: { + ...config.tokens, + [`${config.community.primary_token.chain_id}:${tokenAddress}`]: { + name, + symbol, + address: tokenAddress, + chain_id: config.community.primary_token.chain_id, + decimals: 18, + standard: 'erc20' + } + }, + community: { + ...config.community, + logo: icon, + primary_token: { + ...config.community.primary_token, + address: tokenAddress + } + } + }; + + const updateCommunity = await updateCommunityJson( + client, + config.community.alias, + { + json: updateJson + } + ); + + return updateCommunity; + } catch (error) { + console.error('Error creating token:', error); + } +} + +export async function getTokenMetadataAction( + config: Config, + tokenAddress: string +) { + const communityConfig = new CommunityConfig(config); + const rpcUrl = CHAIN_ID_TO_RPC_URL( + config.community.profile.chain_id.toString() + ); + + const tokenMetadata = await getTokenMetadata(communityConfig, { + tokenAddress, + rpcUrl + }); + + return tokenMetadata; +} diff --git a/app/[alias]/(dashboard)/configuration/byoc/byoc.tsx b/app/[alias]/(dashboard)/configuration/byoc/byoc.tsx index 453cdc1d..b72c472b 100644 --- a/app/[alias]/(dashboard)/configuration/byoc/byoc.tsx +++ b/app/[alias]/(dashboard)/configuration/byoc/byoc.tsx @@ -1,209 +1,209 @@ -'use client'; - -import { Button } from '@/components/ui/button'; -import { Card, CardContent } from '@/components/ui/card'; -import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form'; -import { Input } from '@/components/ui/input'; -import { Config } from '@citizenwallet/sdk'; -import { zodResolver } from '@hookform/resolvers/zod'; -import { isAddress } from 'ethers'; -import { Coins, Loader2 } from 'lucide-react'; -import { useRouter } from 'next/navigation'; -import { useEffect, useState } from 'react'; -import { useForm } from 'react-hook-form'; -import { toast } from 'sonner'; -import { useDebounce } from 'use-debounce'; -import { z } from 'zod'; -import { IconUpload } from '../_components/iconUpload'; -import { createByocAction, getTokenMetadataAction, uploadIconAction } from '../action'; - - -// Form validation schema -const byocFormSchema = z.object({ - tokenAddress: z.string() - .min(1, 'Token address is required') - .regex(/^0x[a-fA-F0-9]{40}$/, 'Please enter a valid Ethereum address'), - icon: z.any().optional(), -}); - -interface TokenMetadata { - decimals: number; - symbol: string; - name: string; -} - -const chains = [ - { id: '100', name: 'Gnosis' }, - { id: '42220', name: 'Celo' }, - { id: '42161', name: 'Arbitrum' }, - { id: '137', name: 'Polygon' } -]; - -type BYOCFormValues = z.infer; - -export default function BYOCForm({ config }: { config: Config }) { - - const [isLoading, setIsLoading] = useState(false); - const [tokenData, setTokenData] = useState(null); - const router = useRouter(); - - const form = useForm({ - resolver: zodResolver(byocFormSchema), - defaultValues: { - tokenAddress: '', - icon: undefined, - }, - }); - - const [debouncedTokenAddress] = useDebounce(form.watch('tokenAddress'), 1000); - - useEffect(() => { - const validateAddress = async () => { - if (debouncedTokenAddress) { - const isValid = isAddress(debouncedTokenAddress); - if (isValid) { - - - const tokenMetadata = await getTokenMetadataAction(config, debouncedTokenAddress); - - if (tokenMetadata?.decimals == null || tokenMetadata?.symbol == null || tokenMetadata?.name == null) { - - form.setError('tokenAddress', { message: `Unable to find token, are you sure it is published on ${chains.find(chain => Number(chain.id) === config.community.primary_token.chain_id)?.name}?` }); - - } else { - - form.clearErrors('tokenAddress'); - setTokenData({ - decimals: Number(tokenMetadata.decimals), - symbol: String(tokenMetadata.symbol), - name: String(tokenMetadata.name) - }); - - } - } else { - form.setError('tokenAddress', { message: 'Invalid token address' }); - } - } - }; - validateAddress(); - }, [debouncedTokenAddress, form, config]); - - const onSubmit = async (data: BYOCFormValues) => { - try { - setIsLoading(true); - - // Handle icon upload if provided - let iconUrl; - if (data.icon && data.icon instanceof File) { - iconUrl = await uploadIconAction(data.icon, config.community.alias); - } else { - form.setError('icon', { message: 'Icon is required' }); - return; - } - - await createByocAction(config, data.tokenAddress, iconUrl, tokenData?.decimals ?? 0, tokenData?.symbol ?? '', tokenData?.name ?? ''); - toast.success('Configuration created successfully!', - { - onAutoClose: () => { - router.push(`/${config.community.alias}/checkout?option=byoc&address=${data.tokenAddress}`); - }, - onDismiss: () => { - router.push(`/${config.community.alias}/checkout?option=byoc&address=${data.tokenAddress}`); - } - } - ); - form.reset(); - } catch (error) { - console.error('Error creating configuration:', error); - toast.error('Failed to create configuration. Please try again.'); - } finally { - setIsLoading(false); - } - }; - - return ( -
-
-
-

Bring your own token (BYOT)

-

Use an existing ERC20 token

-
-
- - - -
- - {/* Token Address Field */} - ( - - Currency address (ERC20 Token) - - - - - Enter the contract address of your ERC20 token. - - - - )} - /> - {tokenData && ( -
-
- -
-
- {tokenData?.name} - {tokenData?.symbol} -
-
- )} - - {/* Icon Upload Field */} - ( - - Icon - - - - - Upload your logo in SVG or PNG format. It will be stored securely in our storage. - - - - )} - /> - -
- -
- - -
-
-
- ); +'use client'; + +import { Button } from '@/components/ui/button'; +import { Card, CardContent } from '@/components/ui/card'; +import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form'; +import { Input } from '@/components/ui/input'; +import { Config } from '@citizenwallet/sdk'; +import { zodResolver } from '@hookform/resolvers/zod'; +import { isAddress } from 'ethers'; +import { Coins, Loader2 } from 'lucide-react'; +import { useRouter } from 'next/navigation'; +import { useEffect, useState } from 'react'; +import { useForm } from 'react-hook-form'; +import { toast } from 'sonner'; +import { useDebounce } from 'use-debounce'; +import { z } from 'zod'; +import { IconUpload } from '../_components/iconUpload'; +import { createByocAction, getTokenMetadataAction, uploadIconAction } from '../action'; + + +// Form validation schema +const byocFormSchema = z.object({ + tokenAddress: z.string() + .min(1, 'Token address is required') + .regex(/^0x[a-fA-F0-9]{40}$/, 'Please enter a valid Ethereum address'), + icon: z.any().optional(), +}); + +interface TokenMetadata { + decimals: number; + symbol: string; + name: string; +} + +const chains = [ + { id: '100', name: 'Gnosis' }, + { id: '42220', name: 'Celo' }, + { id: '42161', name: 'Arbitrum' }, + { id: '137', name: 'Polygon' } +]; + +type BYOCFormValues = z.infer; + +export default function BYOCForm({ config }: { config: Config }) { + + const [isLoading, setIsLoading] = useState(false); + const [tokenData, setTokenData] = useState(null); + const router = useRouter(); + + const form = useForm({ + resolver: zodResolver(byocFormSchema), + defaultValues: { + tokenAddress: '', + icon: undefined, + }, + }); + + const [debouncedTokenAddress] = useDebounce(form.watch('tokenAddress'), 1000); + + useEffect(() => { + const validateAddress = async () => { + if (debouncedTokenAddress) { + const isValid = isAddress(debouncedTokenAddress); + if (isValid) { + + + const tokenMetadata = await getTokenMetadataAction(config, debouncedTokenAddress); + + if (tokenMetadata?.decimals == null || tokenMetadata?.symbol == null || tokenMetadata?.name == null) { + + form.setError('tokenAddress', { message: `Unable to find token, are you sure it is published on ${chains.find(chain => Number(chain.id) === config.community.primary_token.chain_id)?.name}?` }); + + } else { + + form.clearErrors('tokenAddress'); + setTokenData({ + decimals: Number(tokenMetadata.decimals), + symbol: String(tokenMetadata.symbol), + name: String(tokenMetadata.name) + }); + + } + } else { + form.setError('tokenAddress', { message: 'Invalid token address' }); + } + } + }; + validateAddress(); + }, [debouncedTokenAddress, form, config]); + + const onSubmit = async (data: BYOCFormValues) => { + try { + setIsLoading(true); + + // Handle icon upload if provided + let iconUrl; + if (data.icon && data.icon instanceof File) { + iconUrl = await uploadIconAction(data.icon, config.community.alias); + } else { + form.setError('icon', { message: 'Icon is required' }); + return; + } + + await createByocAction(config, data.tokenAddress, iconUrl, tokenData?.decimals ?? 0, tokenData?.symbol ?? '', tokenData?.name ?? ''); + toast.success('Configuration created successfully!', + { + onAutoClose: () => { + router.push(`/${config.community.alias}/checkout?option=byoc&address=${data.tokenAddress}`); + }, + onDismiss: () => { + router.push(`/${config.community.alias}/checkout?option=byoc&address=${data.tokenAddress}`); + } + } + ); + form.reset(); + } catch (error) { + console.error('Error creating configuration:', error); + toast.error('Failed to create configuration. Please try again.'); + } finally { + setIsLoading(false); + } + }; + + return ( +
+
+
+

Bring your own token (BYOT)

+

Use an existing ERC20 token

+
+
+ + + +
+ + {/* Token Address Field */} + ( + + Currency address (ERC20 Token) + + + + + Enter the contract address of your ERC20 token. + + + + )} + /> + {tokenData && ( +
+
+ +
+
+ {tokenData?.name} + {tokenData?.symbol} +
+
+ )} + + {/* Icon Upload Field */} + ( + + Icon + + + + + Upload your logo in SVG or PNG format. It will be stored securely in our storage. + + + + )} + /> + +
+ +
+ + +
+
+
+ ); } \ No newline at end of file diff --git a/app/[alias]/(dashboard)/configuration/byoc/page.tsx b/app/[alias]/(dashboard)/configuration/byoc/page.tsx index dfcea866..7acb4ff2 100644 --- a/app/[alias]/(dashboard)/configuration/byoc/page.tsx +++ b/app/[alias]/(dashboard)/configuration/byoc/page.tsx @@ -1,30 +1,30 @@ -import { getServiceRoleClient } from '@/services/top-db'; -import { getCommunityByAlias } from '@/services/top-db/community'; -import { Suspense } from 'react'; -import ByocFallback from '../_components/byoc-fallback'; -import BYOCForm from './byoc'; - -export default async function page(props: { - params: Promise<{ alias: string }>; -}) { - const { alias } = await props.params; - - const client = getServiceRoleClient(); - const { data, error } = await getCommunityByAlias(client, alias); - - if (error || !data) { - throw new Error('Failed to get community by alias'); - } - - const config = data.json; - - - return ( - } - > - - - ) -} +import { getServiceRoleClient } from '@/services/top-db'; +import { getCommunityByAlias } from '@/services/top-db/community'; +import { Suspense } from 'react'; +import ByocFallback from '../_components/byoc-fallback'; +import BYOCForm from './byoc'; + +export default async function page(props: { + params: Promise<{ alias: string }>; +}) { + const { alias } = await props.params; + + const client = getServiceRoleClient(); + const { data, error } = await getCommunityByAlias(client, alias); + + if (error || !data) { + throw new Error('Failed to get community by alias'); + } + + const config = data.json; + + + return ( + } + > + + + ) +} diff --git a/app/[alias]/(dashboard)/configuration/configuration.tsx b/app/[alias]/(dashboard)/configuration/configuration.tsx index 00890f95..a384a1e5 100644 --- a/app/[alias]/(dashboard)/configuration/configuration.tsx +++ b/app/[alias]/(dashboard)/configuration/configuration.tsx @@ -1,74 +1,74 @@ -'use client'; - -import { Badge } from '@/components/ui/badge'; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; -import Image from 'next/image'; -import { useRouter } from 'next/navigation'; - - -export default function ConfigurationPage({ alias }: { alias: string }) { - - const router = useRouter(); - - return ( -
-
-

Token Configuration

-

- Choose how you would like to set up your token -

-
- -
- { - router.push(`/${alias}/configuration/byoc`); - } - }> - -
-
- BYOC -
-
- Bring your own token (BYOT) - ERC20 Token -
-
-
- - - Provide the address of any ERC20 token. It must be on the same - chain as the chain on which your community was configured. - - -
- - { - router.push(`/${alias}/configuration/create`); - } - }> - -
-
- Create Currency -
-
- Create your own token - New Token -
-
-
- - - Provide some basic information and get started with your very own community token. - - -
-
-
- ); -} +'use client'; + +import { Badge } from '@/components/ui/badge'; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; +import Image from 'next/image'; +import { useRouter } from 'next/navigation'; + + +export default function ConfigurationPage({ alias }: { alias: string }) { + + const router = useRouter(); + + return ( +
+
+

Token Configuration

+

+ Choose how you would like to set up your token +

+
+ +
+ { + router.push(`/${alias}/configuration/byoc`); + } + }> + +
+
+ BYOC +
+
+ Bring your own token (BYOT) + ERC20 Token +
+
+
+ + + Provide the address of any ERC20 token. It must be on the same + chain as the chain on which your community was configured. + + +
+ + { + router.push(`/${alias}/configuration/create`); + } + }> + +
+
+ Create Currency +
+
+ Create your own token + New Token +
+
+
+ + + Provide some basic information and get started with your very own community token. + + +
+
+
+ ); +} diff --git a/app/[alias]/(dashboard)/configuration/create/create.tsx b/app/[alias]/(dashboard)/configuration/create/create.tsx index 9c576b34..abc13297 100644 --- a/app/[alias]/(dashboard)/configuration/create/create.tsx +++ b/app/[alias]/(dashboard)/configuration/create/create.tsx @@ -1,191 +1,191 @@ -'use client'; - -import { Button } from '@/components/ui/button'; -import { Card, CardContent } from '@/components/ui/card'; -import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form'; -import { Input } from '@/components/ui/input'; -import { Config } from '@citizenwallet/sdk'; -import { zodResolver } from '@hookform/resolvers/zod'; -import { Coins, Loader2 } from 'lucide-react'; -import { useRouter } from 'next/navigation'; -import { useState } from 'react'; -import { useForm } from 'react-hook-form'; -import { toast } from 'sonner'; -import { z } from 'zod'; -import { IconUpload } from '../_components/iconUpload'; -import { createTokenAction, uploadIconAction } from '../action'; - -// Form validation schema -const createFormSchema = z.object({ - tokenName: z.string() - .min(1, 'Token name is required') - .max(50, 'Token name must be less than 50 characters'), - tokenSymbol: z.string() - .min(1, 'Token symbol is required') - .max(4, 'Token symbol must be 4 characters or less') - .regex(/^[A-Z0-9]+$/, 'Token symbol must contain only uppercase letters and numbers'), - icon: z.any().refine((val) => val instanceof File, { - message: 'Icon is required', - }), -}); - -type CreateFormValues = z.infer; - -export default function CreateForm({ config }: { config: Config }) { - const [isLoading, setIsLoading] = useState(false); - const router = useRouter(); - - const form = useForm({ - resolver: zodResolver(createFormSchema), - defaultValues: { - tokenName: '', - tokenSymbol: '', - icon: undefined, - }, - }); - - const onSubmit = async (data: CreateFormValues) => { - try { - setIsLoading(true); - - // Handle icon upload if provided - let iconUrl; - if (data.icon && data.icon instanceof File) { - iconUrl = await uploadIconAction(data.icon, config.community.alias); - } - - await createTokenAction(config, iconUrl || '', data.tokenSymbol, data.tokenName); - - // Show success message - toast.success(`Token created successfully!`, { - onAutoClose: () => { - router.push(`/${config.community.alias}/checkout?option=create`) - }, - onDismiss: () => { - router.push(`/${config.community.alias}/checkout?option=create`) - } - }); - form.reset(); - - } catch (error) { - console.error('Error creating token configuration:', error); - toast.error('Failed to create token configuration. Please try again.'); - } finally { - setIsLoading(false); - } - }; - - return ( -
-
-
-

Create Your Own Token

-

Design your token

-
-
- - - -
- - {/* Token Name Field */} - ( - - Name - - - - - Enter the name of your token. - - - - )} - /> - - {/* Token Symbol Field */} - ( - - Symbol (typically 2-4 characters) - - { - // Convert to uppercase as user types - field.onChange(e.target.value.toUpperCase()); - }} - /> - - - A short abbreviation for your token (e.g., BTC, ETH). - - - - )} - /> - - {form.getValues('tokenName') && form.getValues('tokenSymbol') && ( -
-
- -
-
- {form.getValues('tokenName')} - {form.getValues('tokenSymbol')} -
-
- )} - - - {/* Icon Upload Field */} - ( - - Icon - - - - - Upload your logo in SVG or PNG format. It will be stored securely in our storage. - - - - )} - /> - -
- -
- - -
-
-
- ); +'use client'; + +import { Button } from '@/components/ui/button'; +import { Card, CardContent } from '@/components/ui/card'; +import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form'; +import { Input } from '@/components/ui/input'; +import { Config } from '@citizenwallet/sdk'; +import { zodResolver } from '@hookform/resolvers/zod'; +import { Coins, Loader2 } from 'lucide-react'; +import { useRouter } from 'next/navigation'; +import { useState } from 'react'; +import { useForm } from 'react-hook-form'; +import { toast } from 'sonner'; +import { z } from 'zod'; +import { IconUpload } from '../_components/iconUpload'; +import { createTokenAction, uploadIconAction } from '../action'; + +// Form validation schema +const createFormSchema = z.object({ + tokenName: z.string() + .min(1, 'Token name is required') + .max(50, 'Token name must be less than 50 characters'), + tokenSymbol: z.string() + .min(1, 'Token symbol is required') + .max(4, 'Token symbol must be 4 characters or less') + .regex(/^[A-Z0-9]+$/, 'Token symbol must contain only uppercase letters and numbers'), + icon: z.any().refine((val) => val instanceof File, { + message: 'Icon is required', + }), +}); + +type CreateFormValues = z.infer; + +export default function CreateForm({ config }: { config: Config }) { + const [isLoading, setIsLoading] = useState(false); + const router = useRouter(); + + const form = useForm({ + resolver: zodResolver(createFormSchema), + defaultValues: { + tokenName: '', + tokenSymbol: '', + icon: undefined, + }, + }); + + const onSubmit = async (data: CreateFormValues) => { + try { + setIsLoading(true); + + // Handle icon upload if provided + let iconUrl; + if (data.icon && data.icon instanceof File) { + iconUrl = await uploadIconAction(data.icon, config.community.alias); + } + + await createTokenAction(config, iconUrl || '', data.tokenSymbol, data.tokenName); + + // Show success message + toast.success(`Token created successfully!`, { + onAutoClose: () => { + router.push(`/${config.community.alias}/checkout?option=create`) + }, + onDismiss: () => { + router.push(`/${config.community.alias}/checkout?option=create`) + } + }); + form.reset(); + + } catch (error) { + console.error('Error creating token configuration:', error); + toast.error('Failed to create token configuration. Please try again.'); + } finally { + setIsLoading(false); + } + }; + + return ( +
+
+
+

Create Your Own Token

+

Design your token

+
+
+ + + +
+ + {/* Token Name Field */} + ( + + Name + + + + + Enter the name of your token. + + + + )} + /> + + {/* Token Symbol Field */} + ( + + Symbol (typically 2-4 characters) + + { + // Convert to uppercase as user types + field.onChange(e.target.value.toUpperCase()); + }} + /> + + + A short abbreviation for your token (e.g., BTC, ETH). + + + + )} + /> + + {form.getValues('tokenName') && form.getValues('tokenSymbol') && ( +
+
+ +
+
+ {form.getValues('tokenName')} + {form.getValues('tokenSymbol')} +
+
+ )} + + + {/* Icon Upload Field */} + ( + + Icon + + + + + Upload your logo in SVG or PNG format. It will be stored securely in our storage. + + + + )} + /> + +
+ +
+ + +
+
+
+ ); } \ No newline at end of file diff --git a/app/[alias]/(dashboard)/configuration/create/page.tsx b/app/[alias]/(dashboard)/configuration/create/page.tsx index e5ea7fe9..826927df 100644 --- a/app/[alias]/(dashboard)/configuration/create/page.tsx +++ b/app/[alias]/(dashboard)/configuration/create/page.tsx @@ -1,28 +1,28 @@ -import { getServiceRoleClient } from '@/services/top-db'; -import { getCommunityByAlias } from '@/services/top-db/community'; -import { Suspense } from 'react'; -import CreateFallback from '../_components/create-fallback'; -import CreateForm from './create'; - -export default async function page(props: { - params: Promise<{ alias: string }>; -}) { - const { alias } = await props.params; - const client = getServiceRoleClient(); - const { data, error } = await getCommunityByAlias(client, alias); - - if (error || !data) { - throw new Error('Failed to get community by alias'); - } - - const config = data.json; - - return ( - } - > - - - ) -} +import { getServiceRoleClient } from '@/services/top-db'; +import { getCommunityByAlias } from '@/services/top-db/community'; +import { Suspense } from 'react'; +import CreateFallback from '../_components/create-fallback'; +import CreateForm from './create'; + +export default async function page(props: { + params: Promise<{ alias: string }>; +}) { + const { alias } = await props.params; + const client = getServiceRoleClient(); + const { data, error } = await getCommunityByAlias(client, alias); + + if (error || !data) { + throw new Error('Failed to get community by alias'); + } + + const config = data.json; + + return ( + } + > + + + ) +} diff --git a/app/[alias]/(dashboard)/configuration/page.tsx b/app/[alias]/(dashboard)/configuration/page.tsx index 590345f7..3bf3606f 100644 --- a/app/[alias]/(dashboard)/configuration/page.tsx +++ b/app/[alias]/(dashboard)/configuration/page.tsx @@ -1,20 +1,20 @@ -import React, { Suspense } from 'react' -import ConfigurationPage from './configuration'; -import Fallback from './_components/fallback'; - -export default async function page(props: { - params: Promise<{ alias: string }>; -}) { - const { alias } = await props.params; - return ( - <> - } - > - - - - ) -} - +import React, { Suspense } from 'react' +import ConfigurationPage from './configuration'; +import Fallback from './_components/fallback'; + +export default async function page(props: { + params: Promise<{ alias: string }>; +}) { + const { alias } = await props.params; + return ( + <> + } + > + + + + ) +} + diff --git a/app/[alias]/(dashboard)/layout.tsx b/app/[alias]/(dashboard)/layout.tsx index 7638cbe3..3eace831 100644 --- a/app/[alias]/(dashboard)/layout.tsx +++ b/app/[alias]/(dashboard)/layout.tsx @@ -1,92 +1,92 @@ -import { getAuthUserAction } from '@/app/_actions/user-actions'; -import { - SidebarInset, - SidebarProvider, - SidebarTrigger -} from '@/components/ui/sidebar'; -import { getServiceRoleClient } from '@/services/top-db'; -import { - getCommunities, - getCommunityByAlias -} from '@/services/top-db/community'; -import { redirect } from 'next/navigation'; -import { AppSidebar } from './_components/app-sidebar'; - -export default async function DashboardLayout({ - children, - params -}: { - children: React.ReactNode; - params: Promise<{ alias: string }>; -}) { - const { alias } = await params; - let hasAccess = false; - - const client = getServiceRoleClient(); - - const { data: communityRow, error } = await getCommunityByAlias( - client, - alias - ); - - if (error || !communityRow) { - redirect('/'); - } - - - const community_chain_id = communityRow.chain_id; - - const response = await getAuthUserAction({ chain_id: community_chain_id }); - - if (!response || !response.data) { - redirect(`/${alias}/login`); - } - const { data: user } = response; - - const { role } = user; - const accessList = user?.users_community_access.map((access) => access) ?? []; - - if (role === 'user' && accessList.length < 1) { - redirect('/'); - } - - if (role === 'user' && accessList.length > 0) { - const chain_id = accessList[0].chain_id; - - if (chain_id == community_chain_id && accessList[0].alias == alias) { - hasAccess = true; - } - } - - if (role === 'admin') { - hasAccess = true; - } - - const { data: communities, error: communitiesError } = await getCommunities(client); - if (communitiesError || !communities) { - redirect('/'); - } - - - return ( - - community.json)} - config={communityRow.json} - active={communityRow.active} - hasAccess={hasAccess} - /> - -
-
- -
-
-
- {children} -
-
-
- ); -} +import { getAuthUserAction } from '@/app/_actions/user-actions'; +import { + SidebarInset, + SidebarProvider, + SidebarTrigger +} from '@/components/ui/sidebar'; +import { getServiceRoleClient } from '@/services/top-db'; +import { + getCommunities, + getCommunityByAlias +} from '@/services/top-db/community'; +import { redirect } from 'next/navigation'; +import { AppSidebar } from './_components/app-sidebar'; + +export default async function DashboardLayout({ + children, + params +}: { + children: React.ReactNode; + params: Promise<{ alias: string }>; +}) { + const { alias } = await params; + let hasAccess = false; + + const client = getServiceRoleClient(); + + const { data: communityRow, error } = await getCommunityByAlias( + client, + alias + ); + + if (error || !communityRow) { + redirect('/'); + } + + + const community_chain_id = communityRow.chain_id; + + const response = await getAuthUserAction({ chain_id: community_chain_id }); + + if (!response || !response.data) { + redirect(`/${alias}/login`); + } + const { data: user } = response; + + const { role } = user; + const accessList = user?.users_community_access.map((access) => access) ?? []; + + if (role === 'user' && accessList.length < 1) { + redirect('/'); + } + + if (role === 'user' && accessList.length > 0) { + const chain_id = accessList[0].chain_id; + + if (chain_id == community_chain_id && accessList[0].alias == alias) { + hasAccess = true; + } + } + + if (role === 'admin') { + hasAccess = true; + } + + const { data: communities, error: communitiesError } = await getCommunities(client); + if (communitiesError || !communities) { + redirect('/'); + } + + + return ( + + community.json)} + config={communityRow.json} + active={communityRow.active} + hasAccess={hasAccess} + /> + +
+
+ +
+
+
+ {children} +
+
+
+ ); +} diff --git a/app/[alias]/(dashboard)/members/[account]/action.ts b/app/[alias]/(dashboard)/members/[account]/action.ts index a3829cb5..88e7e0f0 100644 --- a/app/[alias]/(dashboard)/members/[account]/action.ts +++ b/app/[alias]/(dashboard)/members/[account]/action.ts @@ -1,156 +1,156 @@ -'use server'; - -import { - getAuthUserRoleInAppAction, - getAuthUserRoleInCommunityAction -} from '@/app/_actions/user-actions'; -import { pinFileToIPFS, pinJSONToIPFS, unpin } from '@/services/pinata/pinata'; -import { - BundlerService, - CommunityConfig, - Config, - waitForTxSuccess -} from '@citizenwallet/sdk'; -import { Wallet } from 'ethers'; -import { getServiceRoleClient } from '@/services/chain-db'; -import { - MemberT, - removeMember, - updateMember -} from '@/services/chain-db/members'; -import { revalidatePath } from 'next/cache'; - -export type Profile = Pick< - MemberT, - | 'account' - | 'description' - | 'image' - | 'image_medium' - | 'image_small' - | 'name' - | 'username' ->; - -function convertIpfsUrl(ipfsUrl: string) { - if (ipfsUrl.startsWith('ipfs://')) { - return ipfsUrl.replace( - 'ipfs://', - 'https://ipfs.internal.citizenwallet.xyz/' - ); - } - return ipfsUrl; -} - -export async function updateProfileImageAction(file: File, alias: string) { - const roleInApp = await getAuthUserRoleInAppAction(); - const roleResult = await getAuthUserRoleInCommunityAction({ alias }); - - if (roleInApp != 'admin' && roleResult != 'owner') { - throw new Error('You are not authorized to update profile image'); - } - - const result = await pinFileToIPFS(file); - return result; -} - -export async function updateProfileAction( - profile: Profile, - alias: string, - config: Config -) { - const roleInApp = await getAuthUserRoleInAppAction(); - const roleResult = await getAuthUserRoleInCommunityAction({ alias }); - - if (roleInApp != 'admin' && roleResult != 'owner') { - throw new Error('You are not authorized to update profile image'); - } - - const result = await pinJSONToIPFS(profile); - const profileCid = result.IpfsHash; - - const community = new CommunityConfig(config); - const bundler = new BundlerService(community); - - const signer = new Wallet(process.env.SERVER_PRIVATE_KEY as string); - const signerAccountAddress = process.env.SERVER_ACCOUNT_ADDRESS as string; - - const account = profile.account; - const username = profile.username; - - const txHash = await bundler.setProfile( - signer, - signerAccountAddress, - account, - username, - profileCid - ); - const isSuccess = await waitForTxSuccess(community, txHash); - - if (isSuccess) { - const supabase = getServiceRoleClient(config.community.profile.chain_id); - const profileContract = config.community.profile.address; - - //convert ipfs url to https url - profile.image = convertIpfsUrl(profile.image); - profile.image_medium = convertIpfsUrl(profile.image_medium); - profile.image_small = convertIpfsUrl(profile.image_small); - - await updateMember({ - client: supabase, - account, - profileContract, - profile - }); - - revalidatePath(`/${alias}/members`, 'page'); - } -} - -export async function deleteProfileAction( - imageCid: string, - alias: string, - config: Config, - account: string -) { - const roleInApp = await getAuthUserRoleInAppAction(); - const roleResult = await getAuthUserRoleInCommunityAction({ alias }); - - if (roleInApp != 'admin' && roleResult != 'owner') { - throw new Error('You are not authorized to update profile image'); - } - - try { - //unpin profile image - const cid = imageCid.split('/').pop(); - await unpin(cid as string); - - const community = new CommunityConfig(config); - const bundler = new BundlerService(community); - - const signer = new Wallet(process.env.SERVER_PRIVATE_KEY as string); - const signerAccountAddress = process.env.SERVER_ACCOUNT_ADDRESS as string; - - const txHash = await bundler.burnProfile( - signer, - signerAccountAddress, - account - ); - - const isSuccess = await waitForTxSuccess(community, txHash); - - if (isSuccess) { - const supabase = getServiceRoleClient(config.community.profile.chain_id); - const profileContract = config.community.profile.address; - - await removeMember({ - client: supabase, - account, - profileContract - }); - - revalidatePath(`/${alias}/members`, 'page'); - } - } catch (error) { - console.error(error); - } -} +'use server'; + +import { + getAuthUserRoleInAppAction, + getAuthUserRoleInCommunityAction +} from '@/app/_actions/user-actions'; +import { pinFileToIPFS, pinJSONToIPFS, unpin } from '@/services/pinata/pinata'; +import { + BundlerService, + CommunityConfig, + Config, + waitForTxSuccess +} from '@citizenwallet/sdk'; +import { Wallet } from 'ethers'; +import { getServiceRoleClient } from '@/services/chain-db'; +import { + MemberT, + removeMember, + updateMember +} from '@/services/chain-db/members'; +import { revalidatePath } from 'next/cache'; + +export type Profile = Pick< + MemberT, + | 'account' + | 'description' + | 'image' + | 'image_medium' + | 'image_small' + | 'name' + | 'username' +>; + +function convertIpfsUrl(ipfsUrl: string) { + if (ipfsUrl.startsWith('ipfs://')) { + return ipfsUrl.replace( + 'ipfs://', + 'https://ipfs.internal.citizenwallet.xyz/' + ); + } + return ipfsUrl; +} + +export async function updateProfileImageAction(file: File, alias: string) { + const roleInApp = await getAuthUserRoleInAppAction(); + const roleResult = await getAuthUserRoleInCommunityAction({ alias }); + + if (roleInApp != 'admin' && roleResult != 'owner') { + throw new Error('You are not authorized to update profile image'); + } + + const result = await pinFileToIPFS(file); + return result; +} + +export async function updateProfileAction( + profile: Profile, + alias: string, + config: Config +) { + const roleInApp = await getAuthUserRoleInAppAction(); + const roleResult = await getAuthUserRoleInCommunityAction({ alias }); + + if (roleInApp != 'admin' && roleResult != 'owner') { + throw new Error('You are not authorized to update profile image'); + } + + const result = await pinJSONToIPFS(profile); + const profileCid = result.IpfsHash; + + const community = new CommunityConfig(config); + const bundler = new BundlerService(community); + + const signer = new Wallet(process.env.SERVER_PRIVATE_KEY as string); + const signerAccountAddress = process.env.SERVER_ACCOUNT_ADDRESS as string; + + const account = profile.account; + const username = profile.username; + + const txHash = await bundler.setProfile( + signer, + signerAccountAddress, + account, + username, + profileCid + ); + const isSuccess = await waitForTxSuccess(community, txHash); + + if (isSuccess) { + const supabase = getServiceRoleClient(config.community.profile.chain_id); + const profileContract = config.community.profile.address; + + //convert ipfs url to https url + profile.image = convertIpfsUrl(profile.image); + profile.image_medium = convertIpfsUrl(profile.image_medium); + profile.image_small = convertIpfsUrl(profile.image_small); + + await updateMember({ + client: supabase, + account, + profileContract, + profile + }); + + revalidatePath(`/${alias}/members`, 'page'); + } +} + +export async function deleteProfileAction( + imageCid: string, + alias: string, + config: Config, + account: string +) { + const roleInApp = await getAuthUserRoleInAppAction(); + const roleResult = await getAuthUserRoleInCommunityAction({ alias }); + + if (roleInApp != 'admin' && roleResult != 'owner') { + throw new Error('You are not authorized to update profile image'); + } + + try { + //unpin profile image + const cid = imageCid.split('/').pop(); + await unpin(cid as string); + + const community = new CommunityConfig(config); + const bundler = new BundlerService(community); + + const signer = new Wallet(process.env.SERVER_PRIVATE_KEY as string); + const signerAccountAddress = process.env.SERVER_ACCOUNT_ADDRESS as string; + + const txHash = await bundler.burnProfile( + signer, + signerAccountAddress, + account + ); + + const isSuccess = await waitForTxSuccess(community, txHash); + + if (isSuccess) { + const supabase = getServiceRoleClient(config.community.profile.chain_id); + const profileContract = config.community.profile.address; + + await removeMember({ + client: supabase, + account, + profileContract + }); + + revalidatePath(`/${alias}/members`, 'page'); + } + } catch (error) { + console.error(error); + } +} diff --git a/app/[alias]/(dashboard)/members/[account]/add/page.tsx b/app/[alias]/(dashboard)/members/[account]/add/page.tsx index 3018120a..27204f20 100644 --- a/app/[alias]/(dashboard)/members/[account]/add/page.tsx +++ b/app/[alias]/(dashboard)/members/[account]/add/page.tsx @@ -1,59 +1,59 @@ -import { Skeleton } from '@/components/ui/skeleton'; -import { getServiceRoleClient } from '@/services/top-db'; -import { getCommunityByAlias } from '@/services/top-db/community'; -import { Config } from '@citizenwallet/sdk'; -import { Suspense } from 'react'; -import Profile from './profile'; - -interface PageProps { - params: Promise<{ - account: string; - alias: string; - }>; -} - -export default async function page(props: PageProps) { - const { account, alias } = await props.params; - const client = getServiceRoleClient(); - const { data, error } = await getCommunityByAlias(client, alias); - - if (error || !data) { - throw new Error('Failed to get community by alias'); - } - - const config = data.json; - - return ( -
-
-
-

Member Profile

-

- {config.community.name} -

-
-
- -
-
- } - > - - -
-
-
- ); -} - -async function AsyncPage({ - config, - account -}: { - config: Config; - account: string; -}) { - return ; -} +import { Skeleton } from '@/components/ui/skeleton'; +import { getServiceRoleClient } from '@/services/top-db'; +import { getCommunityByAlias } from '@/services/top-db/community'; +import { Config } from '@citizenwallet/sdk'; +import { Suspense } from 'react'; +import Profile from './profile'; + +interface PageProps { + params: Promise<{ + account: string; + alias: string; + }>; +} + +export default async function page(props: PageProps) { + const { account, alias } = await props.params; + const client = getServiceRoleClient(); + const { data, error } = await getCommunityByAlias(client, alias); + + if (error || !data) { + throw new Error('Failed to get community by alias'); + } + + const config = data.json; + + return ( +
+
+
+

Member Profile

+

+ {config.community.name} +

+
+
+ +
+
+ } + > + + +
+
+
+ ); +} + +async function AsyncPage({ + config, + account +}: { + config: Config; + account: string; +}) { + return ; +} diff --git a/app/[alias]/(dashboard)/members/[account]/add/profile.tsx b/app/[alias]/(dashboard)/members/[account]/add/profile.tsx index 92c9aefb..3754d048 100644 --- a/app/[alias]/(dashboard)/members/[account]/add/profile.tsx +++ b/app/[alias]/(dashboard)/members/[account]/add/profile.tsx @@ -1,264 +1,264 @@ -'use client'; - -import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; -import { Button } from '@/components/ui/button'; -import { Card, CardContent, CardFooter } from '@/components/ui/card'; -import { - Form, - FormControl, - FormField, - FormItem, - FormLabel, - FormMessage -} from '@/components/ui/form'; -import { Input } from '@/components/ui/input'; -import { Textarea } from '@/components/ui/textarea'; -import { - CommunityConfig, - Config, - checkUsernameAvailability -} from '@citizenwallet/sdk'; -import { zodResolver } from '@hookform/resolvers/zod'; -import { Upload, User } from 'lucide-react'; -import { useRouter } from 'next/navigation'; -import { useEffect, useMemo, useRef, useState } from 'react'; -import { useForm } from 'react-hook-form'; -import { toast } from 'sonner'; -import { useDebounce } from 'use-debounce'; -import * as z from 'zod'; -import type { Profile } from '../action'; -import { updateProfileAction, updateProfileImageAction } from '../action'; - -const profileFormSchema = z.object({ - username: z.string().min(1, 'Username is required'), - name: z.string().optional(), - description: z.string().optional() -}); - -export default function Profile({ - config, - account -}: { - config: Config; - account: string; -}) { - const community = useMemo(() => new CommunityConfig(config), [config]); - const router = useRouter(); - - const [imageFile, setImageFile] = useState(null); - const [avatarUrl, setAvatarUrl] = useState(''); - const [isAvailable, setIsAvailable] = useState(true); - const [usernameEdit, setUsernameEdit] = useState(false); - const fileInputRef = useRef(null); - const [isLoading, setIsLoading] = useState(false); - - const form = useForm>({ - resolver: zodResolver(profileFormSchema), - defaultValues: { - username: '', - name: '', - description: '' - } - }); - - const username = form.watch('username'); - const [debouncedUsername] = useDebounce(username, 1000); - - useEffect(() => { - if (debouncedUsername && usernameEdit) { - const checkUsername = async () => { - try { - const isAvailable = await checkUsernameAvailability( - community, - debouncedUsername - ); - if (!isAvailable) { - toast.error('Username is already taken'); - setIsAvailable(false); - } else { - setIsAvailable(true); - } - } catch (error) { - console.error('Error checking username availability:', error); - } - }; - - checkUsername(); - } - }, [debouncedUsername, usernameEdit, community]); - - const handleImageUpload = (e: React.ChangeEvent) => { - const file = e.target.files?.[0]; - if (file) { - setImageFile(file); - const imageUrl = URL.createObjectURL(file); - setAvatarUrl(imageUrl); - } - }; - - const triggerFileInput = () => { - fileInputRef.current?.click(); - }; - - const onSubmit = async (values: z.infer) => { - try { - setIsLoading(true); - - if (!values.username || !values.name) { - toast.error('Please enter a username and name'); - setIsLoading(false); - return; - } - - if (!isAvailable) { - toast.error('Username is already taken, you cannot save it'); - setIsLoading(false); - return; - } - - // Default image - let cid = 'QmZjzYmcbxj6Yr9EBmuMu3knYd25oYvnTu92yLWhiajvMr'; - - if (imageFile) { - const response = await updateProfileImageAction( - imageFile, - community.community.alias - ); - cid = response.IpfsHash; - } - - const profile: Profile = { - account, - description: values.description || '', - image: `ipfs://${cid}`, - image_medium: `ipfs://${cid}`, - image_small: `ipfs://${cid}`, - name: values.name || '', - username: values.username - }; - - await updateProfileAction(profile, config.community.alias, config); - toast.success('Profile updated successfully'); - router.push(`/${config.community.alias}/members`); - } catch (error) { - console.error('Error adding member:', error); - toast.error('Error updating profile'); - } finally { - setIsLoading(false); - } - }; - - return ( - - -
- -
- - - - - - - - -
- -
-
- ( - - Username - - { - setUsernameEdit(true); - field.onChange(e); - }} - className={`bg-white ${isAvailable ? '' : 'border-red-500'}`} - /> - - - - )} - /> - ( - - Name - - - - - - )} - /> -
- ( - - Description - -