diff --git a/src/components/NTFImage.tsx b/src/components/NTFImage.tsx index dd3656d9e..66b8e6fc9 100644 --- a/src/components/NTFImage.tsx +++ b/src/components/NTFImage.tsx @@ -15,7 +15,7 @@ interface Nft { } interface NftImageProps { - nft: Nft; + nft?: Nft; ipfs_cid?: string; alt: string; } diff --git a/src/components/tools/FungibleToken/CreateTokenForm.tsx b/src/components/tools/FungibleToken/CreateTokenForm.tsx new file mode 100644 index 000000000..93528081c --- /dev/null +++ b/src/components/tools/FungibleToken/CreateTokenForm.tsx @@ -0,0 +1,190 @@ +import { Button, FileInput, Flex, Form, Grid, Input, openToast, Text } from '@near-pagoda/ui'; +import React, { useContext } from 'react'; +import type { SubmitHandler } from 'react-hook-form'; +import { Controller, useForm } from 'react-hook-form'; + +import { NearContext } from '@/components/WalletSelector'; + +type FormData = { + total_supply: string; + name: string; + symbol: string; + icon: FileList; + decimals: number; +}; + +const FACTORY_CONTRACT = 'tkn.primitives.near'; + +const MAX_FILE_SIZE = 10 * 1024; +const ACCEPTED_IMAGE_TYPES = ['image/jpeg', 'image/png', 'image/gif', 'image/svg+xml']; + +const CreateTokenForm: React.FC = () => { + const { + control, + register, + handleSubmit, + formState: { errors, isSubmitting }, + } = useForm(); + + const { wallet, signedAccountId } = useContext(NearContext); + + const validateImage = (files: FileList) => { + if (files.length === 0) return 'Image is required'; + const file = files[0]; + if (file.size > MAX_FILE_SIZE) return 'Image size should be less than 10KB'; + if (!ACCEPTED_IMAGE_TYPES.includes(file.type)) return 'Not a valid image format'; + return true; + }; + + const convertToBase64 = (file: File): Promise => { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.readAsDataURL(file); + reader.onload = () => resolve(reader.result as string); + reader.onerror = (error) => reject(error); + }); + }; + + const onSubmit: SubmitHandler = async (data) => { + let base64Image = ''; + if (data.icon[0]) { + base64Image = await convertToBase64(data.icon[0]); + } + + const total_supply = BigInt(data.total_supply) * BigInt(Math.pow(10, Number(data.decimals))); + + const args = { + args: { + owner_id: signedAccountId, + total_supply: total_supply.toString(), + metadata: { + spec: 'ft-1.0.0', + name: data.name, + symbol: data.symbol, + icon: base64Image, + decimals: data.decimals, + }, + }, + account_id: signedAccountId, + }; + + const requiredDeposit = await wallet?.viewMethod({ contractId: FACTORY_CONTRACT, method: 'get_required', args }); + + try { + const result = await wallet?.signAndSendTransactions({ + transactions: [ + { + receiverId: FACTORY_CONTRACT, + actions: [ + { + type: 'FunctionCall', + params: { + methodName: 'create_token', + args, + gas: '300000000000000', + deposit: requiredDeposit, + }, + }, + ], + }, + ], + }); + + if (result) { + const transactionId = result[0].transaction_outcome.id; + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + window.open(`https://nearblocks.io/txns/${transactionId}`, '_blank')!.focus(); + } + + openToast({ + type: 'success', + title: 'Token Created', + description: `Token ${data.name} (${data.symbol}) created successfully`, + duration: 5000, + }); + } catch (error) { + openToast({ + type: 'error', + title: 'Error', + description: 'Failed to create token', + duration: 5000, + }); + } + }; + + return ( + <> + + Mint a Fungible Token + +
+ + + + + + + + + +
+ ( + { + const files = value; + field.onChange(files); + }} + /> + )} + /> + + Accepted Formats: PNG, JPEG, GIF, SVG | Ideal dimension: 1:1 | Max size: 10kb + +
+ +