diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..140ea9ee --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "lib/openzeppelin-contracts"] + path = lib/openzeppelin-contracts + url = https://github.com/OpenZeppelin/openzeppelin-contracts diff --git a/contracts/CATFactory.sol b/contracts/CATFactory.sol index 73fb5010..6c0ee169 100644 --- a/contracts/CATFactory.sol +++ b/contracts/CATFactory.sol @@ -2,14 +2,14 @@ pragma solidity ^0.8.20; import "@openzeppelin/contracts/access/Ownable.sol"; -import "./ContributionAccountingToken.sol"; // Ensure this import points to your CAT contract file +import "./ContributionAccountingToken.sol"; contract CATFactory is Ownable { uint256 private _nextTokenId; // Mapping from owner address to token addresses - mapping(address => address[]) public administerableTokens; // Now public - mapping(address => address[]) public mintableTokens; // Now public + mapping(address => address[]) public administerableTokens; + mapping(address => address[]) public mintableTokens; // Event emitted when a new CAT is created event CATCreated(address indexed owner, address catAddress, uint256 tokenId); @@ -66,4 +66,8 @@ contract CATFactory is Ownable { function totalCATs() public view returns (uint256) { return _nextTokenId; } + + function getCATAddresses(address _creator) external view returns (address[] memory) { + return administerableTokens[_creator]; + } } diff --git a/web/.env.examples b/web/.env.examples new file mode 100644 index 00000000..3fa16368 --- /dev/null +++ b/web/.env.examples @@ -0,0 +1 @@ +NEXT_PUBLIC_PROJECT_ID=2c8ea0e714279107a73b8e52561345a6 \ No newline at end of file diff --git a/web/src/app/[cat]/InteractionClient.tsx b/web/src/app/[cat]/InteractionClient.tsx new file mode 100644 index 00000000..3085c962 --- /dev/null +++ b/web/src/app/[cat]/InteractionClient.tsx @@ -0,0 +1,210 @@ +'use client' + +import React, { useEffect, useState } from "react"; +import { Info } from "lucide-react"; +import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card"; +import { useAccount } from "wagmi"; +import { getPublicClient } from "@wagmi/core"; +import { config } from "@/utils/config"; +import { useSearchParams } from "next/navigation"; +import CONTRIBUTION_ACCOUNTING_TOKEN_ABI from "@/contractsABI/ContributionAccountingTokenABI"; + +interface TokenDetailsState { + tokenName: string; + tokenSymbol: string; + maxSupply: number; + thresholdSupply: number; + maxExpansionRate: number; + transactionHash: string; + timestamp: string; +} + +export default function InteractionClient() { + + const searchParams = useSearchParams(); + const [isLoading, setIsLoading] = useState(true); + const [error, setError] = useState(null); + + const [tokenAddress, setTokenAddress] = useState<`0x${string}`>("0x0"); + const [chainId, setChainId] = useState(0); + + const [tokenDetails, setTokenDetails] = useState({ + tokenName: "", + tokenSymbol: "", + maxSupply: 0, + thresholdSupply: 0, + maxExpansionRate: 0, + transactionHash: "", + timestamp: "", + }); + + // Get vault address and chainId from URL parameters + useEffect(() => { + const vault = searchParams.get("vault"); + const chain = searchParams.get("chainId"); + + if (vault && chain) { + setTokenAddress(vault as `0x${string}`); + setChainId(Number(chain)); + } + }, [searchParams]); + + const getTokenDetails = async () => { + if (!tokenAddress || !chainId) { + setError("Invalid token address or chain ID"); + return; + } + + try { + setIsLoading(true); + setError(null); + + const publicClient = getPublicClient(config as any, { chainId }); + + if (!publicClient) { + throw new Error(`No public client available for chain ${chainId}`); + } + + // Replace CONTRIBUTION_ACCOUNTING_TOKEN_ABI with your actual token contract ABI + const [name, symbol, maxSupply, threshold, expansionRate] = + (await Promise.all([ + publicClient.readContract({ + address: tokenAddress, + abi: CONTRIBUTION_ACCOUNTING_TOKEN_ABI, + functionName: "name", + }), + publicClient.readContract({ + address: tokenAddress, + abi: CONTRIBUTION_ACCOUNTING_TOKEN_ABI, + functionName: "symbol", + }), + publicClient.readContract({ + address: tokenAddress, + abi: CONTRIBUTION_ACCOUNTING_TOKEN_ABI, + functionName: "maxSupply", + }), + publicClient.readContract({ + address: tokenAddress, + abi: CONTRIBUTION_ACCOUNTING_TOKEN_ABI, + functionName: "thresholdSupply", + }), + publicClient.readContract({ + address: tokenAddress, + abi: CONTRIBUTION_ACCOUNTING_TOKEN_ABI, + functionName: "maxExpansionRate", + }), + ])) as [string, string, bigint, bigint, bigint]; + + setTokenDetails({ + tokenName: name, + tokenSymbol: symbol, + maxSupply: Number(maxSupply) / 10 ** 18, + thresholdSupply: Number(threshold) / 10 ** 18, + maxExpansionRate: Number(expansionRate) / 100, + transactionHash: tokenAddress, + timestamp: new Date().toISOString(), + }); + } catch (error) { + console.error("Error fetching token details:", error); + setError("Failed to fetch token details"); + } finally { + setIsLoading(false); + } + }; + + useEffect(() => { + if (tokenAddress && chainId) { + getTokenDetails(); + } + }, [tokenAddress, chainId]); + + if (isLoading) { + return ( +
+
+ Loading token details... +
+
+ ); + } + + if (error) { + return ( +
+
{error}
+
+ ); + } + + return ( +
+ + + +
+ + Token Information +
+
+
+ +
+
+
+
+ Token Name +
+
+ {tokenDetails.tokenName} +
+
+
+
+ Token Symbol +
+
+ {tokenDetails.tokenSymbol} +
+
+
+
+ Max Supply +
+
+ {tokenDetails.maxSupply} +
+
+
+
+
+
+ Threshold Supply +
+
+ {tokenDetails.thresholdSupply} +
+
+
+
+ Max Expansion Rate +
+
+ {tokenDetails.maxExpansionRate}% +
+
+
+
+
+
+ Transaction Hash +
+
+ {tokenDetails.transactionHash} +
+
+
+
+
+ ); +}; + diff --git a/web/src/app/[cat]/page.tsx b/web/src/app/[cat]/page.tsx new file mode 100644 index 00000000..01c92eb8 --- /dev/null +++ b/web/src/app/[cat]/page.tsx @@ -0,0 +1,18 @@ +import { notFound } from "next/navigation"; +import InteractionClient from "./InteractionClient"; +import { Suspense } from "react"; +import Layout from "@/components/Layout"; + +export async function generateStaticParams() { + return [{ cat: "c" }]; +} + +export default function VaultPage() { + return ( + + + + + + ); +} diff --git a/web/src/app/create/page.tsx b/web/src/app/create/page.tsx index 0fdf9c9a..e4ca4327 100644 --- a/web/src/app/create/page.tsx +++ b/web/src/app/create/page.tsx @@ -5,10 +5,22 @@ import Layout from "@/components/Layout"; import { Button } from "@/components/ui/button"; import { Label } from "@/components/ui/label"; import { Input } from "@/components/ui/input"; -import { useWallet } from "@/hooks/WalletConnectProvider"; -import ConnectWallet from "@/components/ConnectWallet"; +import { ConnectButton } from "@rainbow-me/rainbowkit"; import toast from "react-hot-toast"; import { useRouter } from "next/navigation"; +import { ClowderVaultFactories } from "@/utils/address"; +import { useAccount } from "wagmi"; +import { config } from "@/utils/config"; +import { writeContract } from "@wagmi/core"; +import { CAT_FACTORY_ABI } from "@/contractsABI/CatFactoryABI"; +import { + Card, + CardContent, + CardHeader, + CardTitle, + CardDescription, +} from "../../components/ui/card"; +import { Info } from "lucide-react"; interface DeployContractProps { tokenName: string; @@ -19,11 +31,41 @@ interface DeployContractProps { } const fields = [ - { id: "tokenName", label: "Token Name", type: "text" }, - { id: "tokenSymbol", label: "Token Symbol", type: "text" }, - { id: "maxSupply", label: "Maximum Supply", type: "number" }, - { id: "thresholdSupply", label: "Threshold Supply", type: "number" }, - { id: "maxExpansionRate", label: "Maximum Expansion Rate (%)", type: "number" }, + { + id: "tokenName", + label: "Token Name", + type: "text", + placeholder: "My Token", + description: "The name of your token", + }, + { + id: "tokenSymbol", + label: "Token Symbol", + type: "text", + placeholder: "TKN", + description: "A short identifier for your token (2-4 characters)", + }, + { + id: "maxSupply", + label: "Maximum Supply", + type: "number", + placeholder: "1000000", + description: "The maximum number of tokens that can exist", + }, + { + id: "thresholdSupply", + label: "Threshold Supply", + type: "number", + placeholder: "500000", + description: "The supply threshold that triggers expansion", + }, + { + id: "maxExpansionRate", + label: "Maximum Expansion Rate", + type: "number", + placeholder: "5", + description: "Maximum percentage the supply can expand (1-100)", + }, ]; export default function CreateCAT() { @@ -34,17 +76,16 @@ export default function CreateCAT() { thresholdSupply: "", maxExpansionRate: "", }); + const [isDeploying, setIsDeploying] = useState(false); - const { address, catsContractFactoryInstance } = useWallet(); + const { address } = useAccount(); const router = useRouter(); - // Retrieve transaction history from localStorage const getTransactionHistory = () => { const history = localStorage.getItem("transactionHistory"); return history ? JSON.parse(history) : []; }; - // Save transaction to localStorage const saveTransaction = (txDetails: object) => { const history = getTransactionHistory(); history.push(txDetails); @@ -53,43 +94,52 @@ export default function CreateCAT() { const deployContract = async () => { try { - if (!catsContractFactoryInstance) { + setIsDeploying(true); + const chainId = config.state.chainId; + if (!ClowderVaultFactories[chainId]) { toast.error("Contract factory instance not available"); return; } - const { maxSupply, thresholdSupply, maxExpansionRate, tokenName, tokenSymbol } = formData; + const { + maxSupply, + thresholdSupply, + maxExpansionRate, + tokenName, + tokenSymbol, + } = formData; - // Send the transaction to deploy the contract - const tx = await catsContractFactoryInstance.methods - .createCAT( + const tx = await writeContract(config as any, { + address: ClowderVaultFactories[chainId], + abi: CAT_FACTORY_ABI, + functionName: "createCAT", + args: [ parseInt(maxSupply), parseInt(thresholdSupply), maxExpansionRate.toString(), tokenName, - tokenSymbol - ) - .send({ from: address, gas: 3000000, gasPrice: 10000000000 }); + tokenSymbol, + ], + }); - // Prepare transaction details to store const txDetails = { tokenName, tokenSymbol, maxSupply, thresholdSupply, maxExpansionRate, - transactionHash: tx.transactionHash, + transactionHash: tx, timestamp: new Date().toISOString(), }; - // Save transaction details in localStorage saveTransaction(txDetails); - - toast.success("CAT contract deployed!"); - console.log("Deployment successful:", tx); + toast.success("CAT contract deployed successfully!"); + router.push("/my-cats"); } catch (error) { console.error("Error deploying CAT:", error); - toast.error("Error deploying CAT"); + toast.error("Failed to deploy CAT contract"); + } finally { + setIsDeploying(false); } }; @@ -103,41 +153,71 @@ export default function CreateCAT() { const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); await deployContract(); - router.push("/my-cats"); }; return ( -
-
-

Create CAT

- {!address ? ( - - ) : ( -
- {fields.map(({ id, label, type }) => ( -
- - +
+
+ + + + Create CAT + + + Deploy a new Contribution Accounting Token + + + + {!address ? ( +
+

+ Connect your wallet to create a new CAT +

+
- ))} - - - )} + ) : ( +
+ {fields.map( + ({ id, label, type, placeholder, description }) => ( +
+
+ +
+ + + {description} + +
+
+ +
+ ) + )} +
+ +
+
+ )} +
+
diff --git a/web/src/app/layout.tsx b/web/src/app/layout.tsx index 83cc5d60..53971afd 100644 --- a/web/src/app/layout.tsx +++ b/web/src/app/layout.tsx @@ -3,8 +3,9 @@ import localFont from "next/font/local"; import "./globals.css"; import { CatsProvider } from "@/hooks/CatsProvider"; import { WalletConnectProvider } from "@/hooks/WalletConnectProvider"; -import { ThemeProvider } from "@/components/theme-provider"; +import { ThemeProvider } from "@/hooks/ThemeProvider"; import { Toaster } from "react-hot-toast"; +import { WalletProvider } from "@/hooks/WalletProvider"; const geistSans = localFont({ src: "./fonts/GeistVF.woff", @@ -24,14 +25,17 @@ const bebasNueue = localFont({ export const metadata: Metadata = { title: "Clowder - Contribution Accounting Tokens (CATs)", - description: "Clowder helps you track contributions to your projects with Contribution Accounting Tokens (CATs). Secure, semi-transferable, and easy to mint.", - keywords: "Clowder, Contribution Accounting Tokens, CATs, secure, mint tokens, projects, community, Stability Nexus", + description: + "Clowder helps you track contributions to your projects with Contribution Accounting Tokens (CATs). Secure, semi-transferable, and easy to mint.", + keywords: + "Clowder, Contribution Accounting Tokens, CATs, secure, mint tokens, projects, community, Stability Nexus", robots: "index, follow", openGraph: { type: "website", url: "https://clowder.stability.nexus/", title: "Clowder - Contribution Accounting Tokens (CATs)", - description: "Track contributions to your projects with Contribution Accounting Tokens (CATs) on Clowder. Simple to mint, secure against inflation.", + description: + "Track contributions to your projects with Contribution Accounting Tokens (CATs) on Clowder. Simple to mint, secure against inflation.", images: [ { url: "https://stability.nexus/logos/clowder.png", @@ -45,11 +49,16 @@ export const metadata: Metadata = { card: "summary_large_image", site: "@StabilityNexus", title: "Clowder - Contribution Accounting Tokens (CATs)", - description: "Track contributions to your projects using Contribution Accounting Tokens (CATs) on Clowder. Simple to mint, secure against inflation.", + description: + "Track contributions to your projects using Contribution Accounting Tokens (CATs) on Clowder. Simple to mint, secure against inflation.", }, }; -export default function RootLayout({ children }: { children: React.ReactNode; }) { +export default function RootLayout({ + children, +}: { + children: React.ReactNode; +}) { return ( - + {children} - + diff --git a/web/src/app/my-cats/page.tsx b/web/src/app/my-cats/page.tsx index 196cd5b6..dd5e33c7 100644 --- a/web/src/app/my-cats/page.tsx +++ b/web/src/app/my-cats/page.tsx @@ -2,76 +2,163 @@ import { useCallback, useEffect, useState } from "react"; import Layout from "@/components/Layout"; -import { CatsProps } from "@/types/cats"; import Link from "next/link"; -import { useWallet } from "@/hooks/WalletConnectProvider"; +import { useAccount } from "wagmi"; +import { ClowderVaultFactories } from "@/utils/address"; +import { config } from "@/utils/config"; +import { getPublicClient } from "@wagmi/core"; +import { CAT_FACTORY_ABI } from "@/contractsABI/CatFactoryABI"; import detectEthereumProvider from "@metamask/detect-provider"; import Web3 from "web3"; import CONTRIBUTION_ACCOUNTING_TOKEN_ABI from "@/contractsABI/ContributionAccountingTokenABI"; +interface CatDetails { + chainId: string; + address: `0x${string}`; + tokenName: string; + tokenSymbol: string; +} + export default function MyCATsPage() { - const [ownedCATs, setOwnedCATs] = useState(null); - const { address, catsContractFactoryInstance, isLoading } = useWallet(); - - const getOwnedCATs = useCallback(async () => { - if (!catsContractFactoryInstance) return []; - const cats = await catsContractFactoryInstance.methods - .getOwnedCATs(address) - .call(); - return cats; - }, [catsContractFactoryInstance, address]); - - const getCatDetails = async (catAddress: string) => { - const provider = await detectEthereumProvider(); - if (provider) { - const web3 = new Web3(provider as unknown as Web3["givenProvider"]); - const catsContractInstance = new web3.eth.Contract( - CONTRIBUTION_ACCOUNTING_TOKEN_ABI, - catAddress + const [ownedCATs, setOwnedCATs] = useState(null); + const [isLoading, setIsLoading] = useState(true); + const [error, setError] = useState(null); + const { address } = useAccount(); + + const fetchCATsFromAllChains = async () => { + try { + setIsLoading(true); + setError(null); + let allCATs: CatDetails[] = []; + + const chainPromises = Object.entries(ClowderVaultFactories).map( + ([chainId, factoryAddress]) => + fetchCATsForChain(chainId, factoryAddress) ); - const tokenName = await catsContractInstance.methods.tokenName().call(); - const tokenSymbol = await catsContractInstance.methods.tokenSymbol().call(); - return { address: catAddress, tokenName, tokenSymbol }; - } else { - throw new Error("Ethereum provider not found"); + + const results = await Promise.all(chainPromises); + allCATs = results.flat().filter((cat): cat is CatDetails => cat !== null); + + setOwnedCATs(allCATs); + } catch (error) { + console.error("Error fetching CATs:", error); + setError("Failed to fetch CATs. Please try again later."); + } finally { + setIsLoading(false); } }; - useEffect(() => { - const fetchOwnedCATs = async () => { - const catAddresses = await getOwnedCATs(); - const catDetailsPromises = catAddresses.map((catAddress: string) => - getCatDetails(catAddress) - ); - const cats = await Promise.all(catDetailsPromises); - setOwnedCATs(cats); - }; + const fetchCATsForChain = async ( + chainId: string, + factoryAddress: string + ): Promise => { + try { + const publicClient = getPublicClient(config as any, { + chainId: parseInt(chainId), + }); + + if (!publicClient || !address) { + console.error(`No public client available for chain ${chainId}`); + return []; + } + + console.log(chainId); + console.log(factoryAddress); + + const catAddresses = (await publicClient.readContract({ + address: factoryAddress as `0x${string}`, + abi: CAT_FACTORY_ABI, + functionName: "getVaultAddresses", + args: [address as `0x${string}`], + })) as `0x${string}`[]; - if (address && !isLoading) { - fetchOwnedCATs(); + console.log(catAddresses) + + const provider = await detectEthereumProvider(); + if (!provider) { + throw new Error("Ethereum provider not found"); + } + + const web3 = new Web3(provider as unknown as Web3["givenProvider"]); + + const catPromises = catAddresses.map(async (catAddress) => { + try { + const [tokenName, tokenSymbol] = await Promise.all([ + publicClient.readContract({ + address: catAddress, + abi: CONTRIBUTION_ACCOUNTING_TOKEN_ABI, + functionName: "tokenName", + }) as Promise, + publicClient.readContract({ + address: catAddress, + abi: CONTRIBUTION_ACCOUNTING_TOKEN_ABI, + functionName: "tokenSymbol", + }) as Promise, + ]); + + console.log(tokenName, tokenSymbol) + + return { + chainId, + address: catAddress, + tokenName: tokenName || "", + tokenSymbol: tokenSymbol || "", + }; + } catch (error) { + console.error( + `Error fetching CAT ${catAddress} on chain ${chainId}:`, + error + ); + return null; + } + }); + + const results = await Promise.all(catPromises); + return results.filter((cat): cat is CatDetails => cat !== null); + } catch (error) { + console.error(`Error fetching CATs for chain ${chainId}:`, error); + return []; + } + }; + + useEffect(() => { + if (address) { + fetchCATsFromAllChains(); } - }, [address, isLoading, getOwnedCATs]); + }, [address]); return ( -
-

My CATs

- {ownedCATs && ownedCATs.length > 0 ? ( -
    - {ownedCATs.map((cat) => ( -
  • - +
    +

    My CATs

    + {isLoading ? ( +

    Loading your CATs...

    + ) : error ? ( +

    {error}

    + ) : ownedCATs?.length ? ( +
      + {ownedCATs.map((cat) => ( +
    • - {cat.tokenName || cat.address} ({cat.tokenSymbol}) - -
    • - ))} -
    - ) : ( -

    You don't own any CATs yet.

    - )} + + {cat.tokenName || cat.address} ({cat.tokenSymbol}) + + (Chain: {cat.chainId}) + + +
  • + ))} +
+ ) : ( +

You don't own any CATs yet.

+ )} +
); diff --git a/web/src/app/page.tsx b/web/src/app/page.tsx index 5caa71ea..724d385f 100644 --- a/web/src/app/page.tsx +++ b/web/src/app/page.tsx @@ -7,8 +7,7 @@ import Layout from "@/components/Layout"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { useRouter } from "next/navigation"; -import { useWallet } from "@/hooks/WalletConnectProvider"; -import ConnectWallet from "@/components/ConnectWallet"; +import { ConnectButton } from "@rainbow-me/rainbowkit"; import Service_1 from "../images/Service_1.png"; import Service_2 from "../images/Service_2.png"; import Service_3 from "../images/Service_3.png"; @@ -16,6 +15,14 @@ import catLight from "../images/Light_cat.png"; import catDark from "../images/Dark_cat.png"; import { useTheme } from "next-themes"; import { faGithub, faDiscord, faTwitter, faTelegram } from "@fortawesome/free-brands-svg-icons"; +import { useAccount } from "wagmi"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; const services = [ { image: Service_1, alt: "Semi-Transferable", description: "Semi-Transferable" }, @@ -23,6 +30,11 @@ const services = [ { image: Service_3, alt: "Simple to Mint", description: "Simple to Mint" }, ]; +const supportedChains = [ + { id: "534351", name: "Scroll Sepolia" }, + { id: "5115", name: "Citrea" }, +]; + const contact_links = [ { href: "https://github.com/StabilityNexus", icon: faGithub }, { href: "https://discord.gg/YzDKeEfWtS", icon: faDiscord }, @@ -35,9 +47,10 @@ export default function Home() { const [isThemeReady, setIsThemeReady] = useState(false); const [catAddress, setCatAddress] = useState(""); const [showPopup, setShowPopup] = useState(false); - const [isWalletConnected, setIsWalletConnected] = useState(false); // Track wallet connection state + const [isWalletConnected, setIsWalletConnected] = useState(''); // Track wallet connection state const router = useRouter(); - const { address } = useWallet(); + const { address } = useAccount(); + const [selectedChain, setSelectedChain] = useState(""); const handleUseCAT = () => { if (catAddress.trim()) { @@ -52,7 +65,7 @@ export default function Home() { }, [resolvedTheme]); useEffect(() => { - setIsWalletConnected(!!address); // Update wallet connection state when address changes + setIsWalletConnected(address as `0x${string}`); // Update wallet connection state when address changes }, [address]); if (!isThemeReady) return null; @@ -65,12 +78,18 @@ export default function Home() {
{/* Heading for Desktop */}

- Welcome to Clowder + Welcome to{" "} + + Clowder +

{/* Heading for Mobile */}

- Welcome to Clowder + Welcome to{" "} + + Clowder +

@@ -92,42 +111,86 @@ export default function Home() { ))}
{!isWalletConnected ? ( - - ) : ( -
- - - - {showPopup && ( -
-
-

Enter CAT Address

- setCatAddress(e.target.value)} - className="mb-4" - style={{ width: "100%" }} - /> -
- - + + ) : ( +
+ + + + {showPopup && ( +
+
+

+ Enter CAT Details +

+ +
+
+ + setCatAddress(e.target.value)} + className="w-full" + /> +
+ +
+ +
-
- )} -
- )} +
+ + +
+
+
+ )} +
+ )} {/* Services Section */}
-

+

Why CATs?

@@ -149,12 +212,15 @@ export default function Home() {
))}
- {/* Contact Us Section */}
-

+

About Us

@@ -165,7 +231,15 @@ export default function Home() { The Stable Order
within the Stability Nexus.

-
+

Contact us through:

diff --git a/web/src/components/Avatar.tsx b/web/src/components/Avatar.tsx index b5b4a072..f1680410 100644 --- a/web/src/components/Avatar.tsx +++ b/web/src/components/Avatar.tsx @@ -3,6 +3,7 @@ import React from "react"; import { useWallet } from "@/hooks/WalletConnectProvider"; import Image from "next/image"; +import { useAccount } from "wagmi"; function generateAvatar(walletAddress: string): string { const baseUrl = "https://api.dicebear.com/6.x/identicon/svg"; @@ -10,14 +11,14 @@ function generateAvatar(walletAddress: string): string { } const Avatar = () => { - const { address } = useWallet(); // Replace with your wallet context or connection logic + const { address } = useAccount(); // Replace with your wallet context or connection logic - if (!address) { + if (address === '0x0') { return

Please connect your wallet to see your avatar.

; } // Generate the avatar URL - const avatarUrl = generateAvatar(address); + const avatarUrl = generateAvatar(address as `0x${string}`); return (
diff --git a/web/src/components/CitreaTestnet.tsx b/web/src/components/CitreaTestnet.tsx new file mode 100644 index 00000000..2c36ef31 --- /dev/null +++ b/web/src/components/CitreaTestnet.tsx @@ -0,0 +1,13 @@ +import { defineChain } from "viem"; + +export const citreaTestnet = defineChain({ + id: 5115, + name: "Citrea Testnet", + nativeCurrency: { name: "cBTC", symbol: "cBTC", decimals: 18 }, + rpcUrls: { + default: { http: ["https://rpc.testnet.citrea.xyz"] }, + }, + blockExplorers: { + default: { name: "citrea", url: "https://explorer.testnet.citrea.xyz" }, + }, +}); diff --git a/web/src/components/Footer.tsx b/web/src/components/Footer.tsx index 0896c86e..95af245d 100644 --- a/web/src/components/Footer.tsx +++ b/web/src/components/Footer.tsx @@ -1,14 +1,68 @@ -import React from "react"; - -const Footer = () => { - return ( -
-

- © - The Stable Order. All rights reserved. -

-
- ); -}; - -export default Footer; +import { + faGithub, + faDiscord, + faTelegram, + faTwitter, +} from "@fortawesome/free-brands-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import Image from "next/image"; +import Link from "next/link"; +import logo from "../images/logo.png"; + +const contact_links = [ + { href: "https://github.com/StabilityNexus", icon: faGithub }, + { href: "https://discord.gg/YzDKeEfWtS", icon: faDiscord }, + { href: "https://t.me/StabilityNexus", icon: faTelegram }, + { href: "https://x.com/StabilityNexus", icon: faTwitter }, +]; + +export default function Footer() { + return ( +
+
+ {/* Logo Section */} +
+ + Stability Nexus Logo + +
+ + {/* Text Section */} +
+ © + The Stable Order. All rights reserved. +
+ + {/* Social Links Section */} +
+ {contact_links.map(({ href, icon }, index) => ( + + + + ))} +
+
+
+ ); +} diff --git a/web/src/components/Layout.tsx b/web/src/components/Layout.tsx index 8297f557..90f94fd1 100644 --- a/web/src/components/Layout.tsx +++ b/web/src/components/Layout.tsx @@ -1,22 +1,43 @@ -import Head from "next/head"; -import React from "react"; +import "@rainbow-me/rainbowkit/styles.css"; +// import "./globals.css"; +import { Metadata } from "next"; +import { Inter } from "next/font/google"; +import { ThemeProvider } from "../hooks/ThemeProvider"; +// import MetamaskProvider from '@/providers' import Navbar from "./Navbar"; -import Footer from "./Footer"; +import Footer from "@/components/Footer"; +import { WalletProvider } from "../hooks/WalletProvider"; -export default function Layout({ children }: { children: React.ReactNode }) { +const inter = Inter({ subsets: ["latin"] }); +export const metadata: Metadata = { + title: "HodlCoin", + description: "Generated by create next app", +}; + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { return (
- - Clowder - - - - -
{children}
-
+ + + +
+ {children} +
+
+ +
); } diff --git a/web/src/components/Navbar.tsx b/web/src/components/Navbar.tsx index 86c685ef..e216c884 100644 --- a/web/src/components/Navbar.tsx +++ b/web/src/components/Navbar.tsx @@ -3,150 +3,145 @@ import Link from "next/link"; import React, { useState, useEffect } from "react"; import Image from "next/image"; -import ConnectWallet from "./ConnectWallet"; import logo_light from "../images/logo_light.png"; import logo_dark from "../images/logo_dark.png"; import { useTheme } from "next-themes"; import { ModeToggle } from "../components/darkModeToggle"; import Avatar from "./Avatar"; -import { useWallet } from "@/hooks/WalletConnectProvider"; +// import { useWallet } from "@/hooks/WalletConnectProvider"; import { Menu, X } from "lucide-react"; +import { ConnectButton } from "@rainbow-me/rainbowkit"; +import { useAccount } from "wagmi"; const Navbar = () => { - const { address } = useWallet(); - const { resolvedTheme } = useTheme(); // Use resolvedTheme for accurate theme detection - const [isThemeReady, setIsThemeReady] = useState(false); // Track theme readiness - const [isMenuOpen, setIsMenuOpen] = useState(false); // State to toggle menu + const { address } = useAccount(); + const { resolvedTheme } = useTheme(); + const [isThemeReady, setIsThemeReady] = useState(false); + const [isMenuOpen, setIsMenuOpen] = useState(false); - useEffect(() => { - // Ensure theme is ready before rendering - if (resolvedTheme) { - setIsThemeReady(true); - } - }, [resolvedTheme]); + useEffect(() => { + if (resolvedTheme) { + setIsThemeReady(true); + } + }, [resolvedTheme]); - // Avoid rendering the navbar until the theme is resolved - if (!isThemeReady) return null; + if (!isThemeReady) return null; - return ( -
-
- {/* Logo and Text */} -
- -
- Clowder -

- LOWDER -

-
- -
+ return ( +
+
+ {/* Logo and Text */} +
+ +
+ Clowder +

+ LOWDER +

+
+ +
- {/* Hamburger Menu and ModeToggle for Small Screens */} -
- - -
+ {/* Hamburger Menu and ModeToggle for Small Screens */} +
+ + +
- {/* Mobile Navigation Links */} - {isMenuOpen && ( -
- -
+ {/* Mobile Navigation Links */} + {isMenuOpen && ( +
+ +
+ )} - {/* Desktop Navigation Links */} - + {/* Desktop Navigation Links */} + - {/* Connect Wallet and Light/Dark Toggle for Desktop */} -
- {address ? ( -
- - - - -
- ) : ( - - )} - -
-
-
- ); + {/* */} +
+
+ ); }; export default Navbar; diff --git a/web/src/components/ui/card.tsx b/web/src/components/ui/card.tsx new file mode 100644 index 00000000..75934036 --- /dev/null +++ b/web/src/components/ui/card.tsx @@ -0,0 +1,86 @@ +import * as React from "react"; + +import { cn } from "@/lib/utils"; + +const Card = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); +Card.displayName = "Card"; + +const CardHeader = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); +CardHeader.displayName = "CardHeader"; + +const CardTitle = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +

+)); +CardTitle.displayName = "CardTitle"; + +const CardDescription = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); +CardDescription.displayName = "CardDescription"; + +const CardContent = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); +CardContent.displayName = "CardContent"; + +const CardFooter = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); +CardFooter.displayName = "CardFooter"; + +export { + Card, + CardHeader, + CardFooter, + CardTitle, + CardDescription, + CardContent, +}; diff --git a/web/src/components/ui/dialog.tsx b/web/src/components/ui/dialog.tsx new file mode 100644 index 00000000..44dafe17 --- /dev/null +++ b/web/src/components/ui/dialog.tsx @@ -0,0 +1,123 @@ +// components/ui/dialog.tsx +"use client"; + +import * as React from "react"; +import * as DialogPrimitive from "@radix-ui/react-dialog"; +import { X } from "lucide-react"; + +import { cn } from "@/lib/utils"; + +const Dialog = DialogPrimitive.Root; + +const DialogTrigger = DialogPrimitive.Trigger; + +const DialogPortal = DialogPrimitive.Portal; + +const DialogClose = DialogPrimitive.Close; + +const DialogOverlay = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +DialogOverlay.displayName = DialogPrimitive.Overlay.displayName; + +const DialogContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + {children} + + + Close + + + +)); +DialogContent.displayName = DialogPrimitive.Content.displayName; + +const DialogHeader = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+); +DialogHeader.displayName = "DialogHeader"; + +const DialogFooter = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+); +DialogFooter.displayName = "DialogFooter"; + +const DialogTitle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +DialogTitle.displayName = DialogPrimitive.Title.displayName; + +const DialogDescription = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +DialogDescription.displayName = DialogPrimitive.Description.displayName; + +export { + Dialog, + DialogPortal, + DialogOverlay, + DialogClose, + DialogTrigger, + DialogContent, + DialogHeader, + DialogFooter, + DialogTitle, + DialogDescription, +}; diff --git a/web/src/components/ui/select.tsx b/web/src/components/ui/select.tsx new file mode 100644 index 00000000..2368407e --- /dev/null +++ b/web/src/components/ui/select.tsx @@ -0,0 +1,156 @@ +import { useState, useRef, useEffect } from "react"; +import { ChevronDown, ChevronUp } from "lucide-react"; +import { cn } from "@/lib/utils"; +import React from "react"; + +interface SelectProps { + value: string; + onValueChange: (value: string) => void; + children: React.ReactNode; +} + +interface SelectTriggerProps { + children: React.ReactNode; + className?: string; +} + +interface SelectContentProps { + children: React.ReactNode; + className?: string; +} + +interface SelectItemProps { + value: string; + children: React.ReactNode; + className?: string; +} + +interface SelectValueProps { + placeholder?: string; +} + +export const Select = ({ value, onValueChange, children }: SelectProps) => { + const [isOpen, setIsOpen] = useState(false); + const selectRef = useRef(null); + + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if ( + selectRef.current && + !selectRef.current.contains(event.target as Node) + ) { + setIsOpen(false); + } + }; + + document.addEventListener("mousedown", handleClickOutside); + return () => document.removeEventListener("mousedown", handleClickOutside); + }, []); + + // Create context to pass down state and handlers + const contextValue = { + isOpen, + setIsOpen, + value, + onValueChange, + }; + + return ( +
+ + {children} + +
+ ); +}; + +// Create context +const SelectContext = React.createContext<{ + isOpen: boolean; + setIsOpen: (isOpen: boolean) => void; + value: string; + onValueChange: (value: string) => void; +} | null>(null); + +// Custom hook to use Select context +const useSelectContext = () => { + const context = React.useContext(SelectContext); + if (!context) { + throw new Error("Select components must be used within a Select component"); + } + return context; +}; + +export const SelectTrigger = ({ children, className }: SelectTriggerProps) => { + const { isOpen, setIsOpen } = useSelectContext(); + + return ( +
setIsOpen(!isOpen)} + > + {children} + {isOpen ? ( + + ) : ( + + )} +
+ ); +}; + +export const SelectContent = ({ children, className }: SelectContentProps) => { + const { isOpen } = useSelectContext(); + + if (!isOpen) return null; + + return ( +
+
{children}
+
+ ); +}; + +export const SelectItem = ({ + value: itemValue, + children, + className, +}: SelectItemProps) => { + const { value, onValueChange, setIsOpen } = useSelectContext(); + const isSelected = value === itemValue; + + const handleClick = () => { + onValueChange(itemValue); + setIsOpen(false); + }; + + return ( +
+ {children} +
+ ); +}; + +export const SelectValue = ({ + placeholder = "Select an option", +}: SelectValueProps) => { + const { value } = useSelectContext(); + return {value || placeholder}; +}; diff --git a/web/src/contractsABI/CatFactoryABI.js b/web/src/contractsABI/CatFactoryABI.js deleted file mode 100644 index b97f4fca..00000000 --- a/web/src/contractsABI/CatFactoryABI.js +++ /dev/null @@ -1,197 +0,0 @@ -const CAT_FACTORY_ABI = [ - { - "inputs": [], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "OwnableInvalidOwner", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "OwnableUnauthorizedAccount", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "catAddress", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "CATCreated", - "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" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "maxSupply", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "thresholdSupply", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "maxExpansionRate", - "type": "uint256" - }, - { - "internalType": "string", - "name": "name", - "type": "string" - }, - { - "internalType": "string", - "name": "symbol", - "type": "string" - } - ], - "name": "createCAT", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "getOwnedCATs", - "outputs": [ - { - "internalType": "address[]", - "name": "", - "type": "address[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "catAddress", - "type": "address" - }, - { - "internalType": "address", - "name": "minter", - "type": "address" - } - ], - "name": "grantMinterRole", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "owner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "renounceOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "totalCATs", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "transferOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } -] - -export default CAT_FACTORY_ABI; \ No newline at end of file diff --git a/web/src/contractsABI/CatFactoryABI.ts b/web/src/contractsABI/CatFactoryABI.ts new file mode 100644 index 00000000..65fe850f --- /dev/null +++ b/web/src/contractsABI/CatFactoryABI.ts @@ -0,0 +1,621 @@ +const CAT_FACTORY = { + "abi": [ + { "type": "constructor", "inputs": [], "stateMutability": "nonpayable" }, + { + "type": "function", + "name": "administerableTokens", + "inputs": [ + { "name": "", "type": "address", "internalType": "address" }, + { "name": "", "type": "uint256", "internalType": "uint256" } + ], + "outputs": [{ "name": "", "type": "address", "internalType": "address" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "createCAT", + "inputs": [ + { "name": "maxSupply", "type": "uint256", "internalType": "uint256" }, + { + "name": "thresholdSupply", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "maxExpansionRate", + "type": "uint256", + "internalType": "uint256" + }, + { "name": "name", "type": "string", "internalType": "string" }, + { "name": "symbol", "type": "string", "internalType": "string" } + ], + "outputs": [{ "name": "", "type": "address", "internalType": "address" }], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "getVaultAddresses", + "inputs": [ + { "name": "_creator", "type": "address", "internalType": "address" } + ], + "outputs": [ + { "name": "", "type": "address[]", "internalType": "address[]" } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "grantMinterRole", + "inputs": [ + { "name": "catAddress", "type": "address", "internalType": "address" }, + { "name": "minter", "type": "address", "internalType": "address" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "mintableTokens", + "inputs": [ + { "name": "", "type": "address", "internalType": "address" }, + { "name": "", "type": "uint256", "internalType": "uint256" } + ], + "outputs": [{ "name": "", "type": "address", "internalType": "address" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "owner", + "inputs": [], + "outputs": [{ "name": "", "type": "address", "internalType": "address" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "renounceOwnership", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "totalCATs", + "inputs": [], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "transferOwnership", + "inputs": [ + { "name": "newOwner", "type": "address", "internalType": "address" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "CATCreated", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "catAddress", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "tokenId", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "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": "error", + "name": "OwnableInvalidOwner", + "inputs": [ + { "name": "owner", "type": "address", "internalType": "address" } + ] + }, + { + "type": "error", + "name": "OwnableUnauthorizedAccount", + "inputs": [ + { "name": "account", "type": "address", "internalType": "address" } + ] + } + ], + "bytecode": { + "object": "0x6080604052348015600e575f5ffd5b503380603357604051631e4fbdf760e01b81525f600482015260240160405180910390fd5b603a81603f565b50608e565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6126be8061009b5f395ff3fe608060405234801561000f575f5ffd5b5060043610610090575f3560e01c8063695ee8de11610063578063695ee8de146100fd578063715018a61461011d5780638da5cb5b14610125578063c76fdf6814610135578063f2fde38b14610148575f5ffd5b8063247db5dd1461009457806325c71938146100aa5780633385ab9c146100bf578063387e8311146100ea575b5f5ffd5b6001546040519081526020015b60405180910390f35b6100bd6100b836600461048c565b61015b565b005b6100d26100cd3660046104bd565b6101f9565b6040516001600160a01b0390911681526020016100a1565b6100d26100f83660046104bd565b61022d565b61011061010b3660046104e5565b610246565b6040516100a19190610505565b6100bd6102b9565b5f546001600160a01b03166100d2565b6100d26101433660046105ef565b6102cc565b6100bd6101563660046104e5565b6103a7565b6101636103e9565b604051633dd1eb6160e01b81526001600160a01b038281166004830152831690633dd1eb61906024015f604051808303815f87803b1580156101a3575f5ffd5b505af11580156101b5573d5f5f3e3d5ffd5b505050506001600160a01b039081165f9081526003602090815260408220805460018101825590835291200180546001600160a01b03191692909116919091179055565b6002602052815f5260405f208181548110610212575f80fd5b5f918252602090912001546001600160a01b03169150829050565b6003602052815f5260405f208181548110610212575f80fd5b6001600160a01b0381165f908152600260209081526040918290208054835181840281018401909452808452606093928301828280156102ad57602002820191905f5260205f20905b81546001600160a01b0316815260019091019060200180831161028f575b50505050509050919050565b6102c16103e9565b6102ca5f610415565b565b5f5f3387878787876040516102e090610464565b6102ef9695949392919061069d565b604051809103905ff080158015610308573d5f5f3e3d5ffd5b50335f8181526002602090815260408083208054600180820183559185529383902090930180546001600160a01b0319166001600160a01b038716908117909155925481519384529183019190915292935083927f054189e2ad79e5c2d10e8da115126520634a6a9b369a130345025ae1ddeafe92910160405180910390a260018054905f610396836106ee565b909155509098975050505050505050565b6103af6103e9565b6001600160a01b0381166103dd57604051631e4fbdf760e01b81525f60048201526024015b60405180910390fd5b6103e681610415565b50565b5f546001600160a01b031633146102ca5760405163118cdaa760e01b81523360048201526024016103d4565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b611f768061071383390190565b80356001600160a01b0381168114610487575f5ffd5b919050565b5f5f6040838503121561049d575f5ffd5b6104a683610471565b91506104b460208401610471565b90509250929050565b5f5f604083850312156104ce575f5ffd5b6104d783610471565b946020939093013593505050565b5f602082840312156104f5575f5ffd5b6104fe82610471565b9392505050565b602080825282518282018190525f918401906040840190835b818110156105455783516001600160a01b031683526020938401939092019160010161051e565b509095945050505050565b634e487b7160e01b5f52604160045260245ffd5b5f82601f830112610573575f5ffd5b813567ffffffffffffffff81111561058d5761058d610550565b604051601f8201601f19908116603f0116810167ffffffffffffffff811182821017156105bc576105bc610550565b6040528181528382016020018510156105d3575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f5f5f5f5f60a08688031215610603575f5ffd5b853594506020860135935060408601359250606086013567ffffffffffffffff81111561062e575f5ffd5b61063a88828901610564565b925050608086013567ffffffffffffffff811115610656575f5ffd5b61066288828901610564565b9150509295509295909350565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b60018060a01b038716815285602082015284604082015283606082015260c060808201525f6106cf60c083018561066f565b82810360a08401526106e1818561066f565b9998505050505050505050565b5f6001820161070b57634e487b7160e01b5f52601160045260245ffd5b506001019056fe610180604052600c805460ff1916600117905573355e559bca86346b82d58be0460d661db481e05e61016052348015610036575f5ffd5b50604051611f76380380611f7683398101604081905261005591610370565b6040805180820190915260018152603160f81b6020820152829081908184600361007f8382610492565b50600461008c8282610492565b5061009c915083905060056101b0565b610120526100ab8160066101b0565b61014052815160208084019190912060e052815190820120610100524660a05261013760e05161010051604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201529081019290925260608201524660808201523060a08201525f9060c00160405160208183030381529060405280519060200120905090565b60805250503060c0525061014b5f876101e2565b506101767f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6876101e2565b506009859055600a849055600b839055600e6101928382610492565b50600f61019f8282610492565b505042600d55506105a49350505050565b5f6020835110156101cb576101c48361028d565b90506101dc565b816101d68482610492565b5060ff90505b92915050565b5f8281526008602090815260408083206001600160a01b038516845290915281205460ff16610286575f8381526008602090815260408083206001600160a01b03861684529091529020805460ff1916600117905561023e3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016101dc565b505f6101dc565b5f5f829050601f815111156102c0578260405163305a27a960e01b81526004016102b7919061054c565b60405180910390fd5b80516102cb82610581565b179392505050565b634e487b7160e01b5f52604160045260245ffd5b5f82601f8301126102f6575f5ffd5b81516001600160401b0381111561030f5761030f6102d3565b604051601f8201601f19908116603f011681016001600160401b038111828210171561033d5761033d6102d3565b604052818152838201602001851015610354575f5ffd5b8160208501602083015e5f918101602001919091529392505050565b5f5f5f5f5f5f60c08789031215610385575f5ffd5b86516001600160a01b038116811461039b575f5ffd5b6020880151604089015160608a015160808b0151939950919750955093506001600160401b038111156103cc575f5ffd5b6103d889828a016102e7565b60a089015190935090506001600160401b038111156103f5575f5ffd5b61040189828a016102e7565b9150509295509295509295565b600181811c9082168061042257607f821691505b60208210810361044057634e487b7160e01b5f52602260045260245ffd5b50919050565b601f82111561048d57805f5260205f20601f840160051c8101602085101561046b5750805b601f840160051c820191505b8181101561048a575f8155600101610477565b50505b505050565b81516001600160401b038111156104ab576104ab6102d3565b6104bf816104b9845461040e565b84610446565b6020601f8211600181146104f1575f83156104da5750848201515b5f19600385901b1c1916600184901b17845561048a565b5f84815260208120601f198516915b828110156105205787850151825560209485019460019092019101610500565b508482101561053d57868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b80516020808301519190811015610440575f1960209190910360031b1b16919050565b60805160a05160c05160e051610100516101205161014051610160516119706106065f395f81816103d8015261077301525f610ffd01525f610fd001525f610eda01525f610eb201525f610e0d01525f610e3701525f610e6101526119705ff3fe608060405234801561000f575f5ffd5b5060043610610229575f3560e01c8063735328021161012a57806395d89b41116100b4578063d547741f11610079578063d547741f14610493578063d5abeb01146104a6578063dd62ed3e146104af578063e488ede8146104e7578063e6ad10e1146104fa575f5ffd5b806395d89b4114610451578063a217fddf146103b1578063a9059cbb14610459578063d505accf1461046c578063d53913931461047f575f5ffd5b806381fb8b06116100fa57806381fb8b06146103d357806383de3e6a1461041257806384b0196e1461041a5780638e80ff5d1461043557806391d148541461043e575f5ffd5b8063735328021461039e57806375b238fc146103b15780637b61c320146103b85780637ecebe00146103c0575f5ffd5b80633644e515116101b657806355233b481161017b57806355233b481461034957806369e2f0fb146103525780636c02a931146103655780636c8597fc1461036d57806370a0823114610376575f5ffd5b80633644e515146102fb57806336568abe146103035780633dd1eb611461031657806340c10f191461032957806348709a931461033c575f5ffd5b806318160ddd116101fc57806318160ddd1461029257806323b872dd146102a4578063248a9ca3146102b75780632f2ff15d146102d9578063313ce567146102ec575f5ffd5b806301ffc9a71461022d57806306fdde03146102555780630914d4da1461026a578063095ea7b31461027f575b5f5ffd5b61024061023b3660046115ee565b610503565b60405190151581526020015b60405180910390f35b61025d610539565b60405161024c919061164a565b61027d61027836600461165c565b6105c9565b005b61024061028d36600461168e565b610655565b6002545b60405190815260200161024c565b6102406102b23660046116b6565b61066c565b6102966102c536600461165c565b5f9081526008602052604090206001015490565b61027d6102e73660046116f0565b61068f565b6040516012815260200161024c565b6102966106b9565b61027d6103113660046116f0565b6106c7565b61027d61032436600461171a565b6106ff565b61027d61033736600461168e565b610724565b600c546102409060ff1681565b610296600b5481565b61027d61036036600461171a565b6108a3565b61025d6108c4565b6102966101f481565b61029661038436600461171a565b6001600160a01b03165f9081526020819052604090205490565b61027d6103ac36600461165c565b610950565b6102965f81565b61025d6109cd565b6102966103ce36600461171a565b6109da565b6103fa7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200161024c565b61027d6109f7565b610422610a0e565b60405161024c9796959493929190611733565b610296600d5481565b61024061044c3660046116f0565b610a50565b61025d610a7a565b61024061046736600461168e565b610a89565b61027d61047a3660046117c9565b610a96565b6102965f51602061191b5f395f51905f5281565b61027d6104a13660046116f0565b610bcc565b61029660095481565b6102966104bd366004611836565b6001600160a01b039182165f90815260016020908152604080832093909416825291909152205490565b61027d6104f536600461165c565b610bf0565b610296600a5481565b5f6001600160e01b03198216637965db0b60e01b148061053357506301ffc9a760e01b6001600160e01b03198316145b92915050565b6060600380546105489061185e565b80601f01602080910402602001604051908101604052809291908181526020018280546105749061185e565b80156105bf5780601f10610596576101008083540402835291602001916105bf565b820191905f5260205f20905b8154815290600101906020018083116105a257829003601f168201915b5050505050905090565b5f6105d381610c83565b600a54821061064f5760405162461bcd60e51b815260206004820152603f60248201527f4e6577207468726573686f6c6420737570706c79206d757374206265206c657360448201527f73207468616e2063757272656e74207468726573686f6c6420737570706c790060648201526084015b60405180910390fd5b50600a55565b5f33610662818585610c90565b5060019392505050565b5f33610679858285610c9d565b610684858585610d13565b506001949350505050565b5f828152600860205260409020600101546106a981610c83565b6106b38383610d70565b50505050565b5f6106c2610e01565b905090565b6001600160a01b03811633146106f05760405163334bd91960e11b815260040160405180910390fd5b6106fa8282610f2a565b505050565b5f61070981610c83565b6107205f51602061191b5f395f51905f528361068f565b5050565b5f51602061191b5f395f51905f5261073b81610c83565b5f61074560025490565b90505f620186a06107586101f4866118aa565b61076291906118c1565b905061076e8585610f95565b6107987f000000000000000000000000000000000000000000000000000000000000000082610f95565b42600d55600954816107aa86856118e0565b6107b491906118e0565b11156107fb5760405162461bcd60e51b815260206004820152601660248201527545786365656473206d6178696d756d20737570706c7960501b6044820152606401610646565b600a54821061089c575f600d544261081391906118f3565b90505f63bbf81e0082600b548661082a91906118aa565b61083491906118aa565b61083e91906118c1565b90508061084b84886118e0565b11156108995760405162461bcd60e51b815260206004820152601e60248201527f45786365656473206d6178696d756d20657870616e73696f6e207261746500006044820152606401610646565b50505b5050505050565b5f6108ad81610c83565b6107205f51602061191b5f395f51905f5283610bcc565b600e80546108d19061185e565b80601f01602080910402602001604051908101604052809291908181526020018280546108fd9061185e565b80156109485780601f1061091f57610100808354040283529160200191610948565b820191905f5260205f20905b81548152906001019060200180831161092b57829003601f168201915b505050505081565b5f61095a81610c83565b60095482106109c75760405162461bcd60e51b815260206004820152603360248201527f4e6577206d617820737570706c79206d757374206265206c657373207468616e6044820152722063757272656e74206d617820737570706c7960681b6064820152608401610646565b50600955565b600f80546108d19061185e565b6001600160a01b0381165f90815260076020526040812054610533565b5f610a0181610c83565b50600c805460ff19169055565b5f6060805f5f5f6060610a1f610fc9565b610a27610ff6565b604080515f80825260208201909252600f60f81b9b939a50919850469750309650945092509050565b5f9182526008602090815260408084206001600160a01b0393909316845291905290205460ff1690565b6060600480546105489061185e565b5f33610662818585610d13565b83421115610aba5760405163313c898160e11b815260048101859052602401610646565b5f7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9888888610b058c6001600160a01b03165f90815260076020526040902080546001810190915590565b6040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e0016040516020818303038152906040528051906020012090505f610b5f82611023565b90505f610b6e8287878761104f565b9050896001600160a01b0316816001600160a01b031614610bb5576040516325c0072360e11b81526001600160a01b0380831660048301528b166024820152604401610646565b610bc08a8a8a610c90565b50505050505050505050565b5f82815260086020526040902060010154610be681610c83565b6106b38383610f2a565b5f610bfa81610c83565b600b548210610c7d5760405162461bcd60e51b815260206004820152604360248201527f4e6577206d617820657870616e73696f6e2072617465206d757374206265206c60448201527f657373207468616e2063757272656e74206d617820657870616e73696f6e207260648201526261746560e81b608482015260a401610646565b50600b55565b610c8d813361107b565b50565b6106fa83838360016110b4565b6001600160a01b038381165f908152600160209081526040808320938616835292905220545f198110156106b35781811015610d0557604051637dc7a0d960e11b81526001600160a01b03841660048201526024810182905260448101839052606401610646565b6106b384848484035f6110b4565b6001600160a01b038316610d3c57604051634b637e8f60e11b81525f6004820152602401610646565b6001600160a01b038216610d655760405163ec442f0560e01b81525f6004820152602401610646565b6106fa838383611186565b5f610d7b8383610a50565b610dfa575f8381526008602090815260408083206001600160a01b03861684529091529020805460ff19166001179055610db23390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610533565b505f610533565b5f306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148015610e5957507f000000000000000000000000000000000000000000000000000000000000000046145b15610e8357507f000000000000000000000000000000000000000000000000000000000000000090565b6106c2604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f0000000000000000000000000000000000000000000000000000000000000000918101919091527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a08201525f9060c00160405160208183030381529060405280519060200120905090565b5f610f358383610a50565b15610dfa575f8381526008602090815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610533565b6001600160a01b038216610fbe5760405163ec442f0560e01b81525f6004820152602401610646565b6107205f8383611186565b60606106c27f0000000000000000000000000000000000000000000000000000000000000000600561123b565b60606106c27f0000000000000000000000000000000000000000000000000000000000000000600661123b565b5f61053361102f610e01565b8360405161190160f01b8152600281019290925260228201526042902090565b5f5f5f5f61105f888888886112e4565b92509250925061106f82826113ac565b50909695505050505050565b6110858282610a50565b6107205760405163e2517d3f60e01b81526001600160a01b038216600482015260248101839052604401610646565b6001600160a01b0384166110dd5760405163e602df0560e01b81525f6004820152602401610646565b6001600160a01b03831661110657604051634a1406b160e11b81525f6004820152602401610646565b6001600160a01b038085165f90815260016020908152604080832093871683529290522082905580156106b357826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258460405161117891815260200190565b60405180910390a350505050565b600c5460ff1615611230576001600160a01b03831615806111ae57506001600160a01b038216155b806111ce57506001600160a01b0382165f90815260208190526040812054115b6112305760405162461bcd60e51b815260206004820152602d60248201527f5472616e73666572207265737472696374656420746f206578697374696e672060448201526c746f6b656e20686f6c6465727360981b6064820152608401610646565b6106fa838383611464565b606060ff83146112555761124e8361158a565b9050610533565b8180546112619061185e565b80601f016020809104026020016040519081016040528092919081815260200182805461128d9061185e565b80156112d85780601f106112af576101008083540402835291602001916112d8565b820191905f5260205f20905b8154815290600101906020018083116112bb57829003601f168201915b50505050509050610533565b5f80807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a084111561131d57505f915060039050826113a2565b604080515f808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa15801561136e573d5f5f3e3d5ffd5b5050604051601f1901519150506001600160a01b03811661139957505f9250600191508290506113a2565b92505f91508190505b9450945094915050565b5f8260038111156113bf576113bf611906565b036113c8575050565b60018260038111156113dc576113dc611906565b036113fa5760405163f645eedf60e01b815260040160405180910390fd5b600282600381111561140e5761140e611906565b0361142f5760405163fce698f760e01b815260048101829052602401610646565b600382600381111561144357611443611906565b03610720576040516335e2f38360e21b815260048101829052602401610646565b6001600160a01b03831661148e578060025f82825461148391906118e0565b909155506114fe9050565b6001600160a01b0383165f90815260208190526040902054818110156114e05760405163391434e360e21b81526001600160a01b03851660048201526024810182905260448101839052606401610646565b6001600160a01b0384165f9081526020819052604090209082900390555b6001600160a01b03821661151a57600280548290039055611538565b6001600160a01b0382165f9081526020819052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161157d91815260200190565b60405180910390a3505050565b60605f611596836115c7565b6040805160208082528183019092529192505f91906020820181803683375050509182525060208101929092525090565b5f60ff8216601f81111561053357604051632cd44ac360e21b815260040160405180910390fd5b5f602082840312156115fe575f5ffd5b81356001600160e01b031981168114611615575f5ffd5b9392505050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f611615602083018461161c565b5f6020828403121561166c575f5ffd5b5035919050565b80356001600160a01b0381168114611689575f5ffd5b919050565b5f5f6040838503121561169f575f5ffd5b6116a883611673565b946020939093013593505050565b5f5f5f606084860312156116c8575f5ffd5b6116d184611673565b92506116df60208501611673565b929592945050506040919091013590565b5f5f60408385031215611701575f5ffd5b8235915061171160208401611673565b90509250929050565b5f6020828403121561172a575f5ffd5b61161582611673565b60ff60f81b8816815260e060208201525f61175160e083018961161c565b8281036040840152611763818961161c565b606084018890526001600160a01b038716608085015260a0840186905283810360c0850152845180825260208087019350909101905f5b818110156117b857835183526020938401939092019160010161179a565b50909b9a5050505050505050505050565b5f5f5f5f5f5f5f60e0888a0312156117df575f5ffd5b6117e888611673565b96506117f660208901611673565b95506040880135945060608801359350608088013560ff81168114611819575f5ffd5b9699959850939692959460a0840135945060c09093013592915050565b5f5f60408385031215611847575f5ffd5b61185083611673565b915061171160208401611673565b600181811c9082168061187257607f821691505b60208210810361189057634e487b7160e01b5f52602260045260245ffd5b50919050565b634e487b7160e01b5f52601160045260245ffd5b808202811582820484141761053357610533611896565b5f826118db57634e487b7160e01b5f52601260045260245ffd5b500490565b8082018082111561053357610533611896565b8181038181111561053357610533611896565b634e487b7160e01b5f52602160045260245ffdfe9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6a2646970667358221220b48d06dfe162a9b2ed0088f3f19fe7610c0a09b89b526efd5ce65a8f1329fc8064736f6c634300081c0033a264697066735822122029caf5f3cba9971fbe382374d529fff168aaddfc7939a62f336d7d7d6049f59d64736f6c634300081c0033", + "sourceMap": "157:2369:0:-:0;;;535:36;;;;;;;;;-1:-1:-1;557:10:0;;1269:95:4;;1322:31;;-1:-1:-1;;;1322:31:4;;1350:1;1322:31;;;160:51:26;133:18;;1322:31:4;;;;;;;1269:95;1373:32;1392:12;1373:18;:32::i;:::-;1225:187;157:2369:0;;2912:187:4;2985:16;3004:6;;-1:-1:-1;;;;;3020:17:4;;;-1:-1:-1;;;;;;3020:17:4;;;;;;3052:40;;3004:6;;;;;;;3052:40;;2985:16;3052:40;2975:124;2912:187;:::o;14:203:26:-;157:2369:0;;;;;;", + "linkReferences": {} + }, + "deployedBytecode": { + "object": "0x608060405234801561000f575f5ffd5b5060043610610090575f3560e01c8063695ee8de11610063578063695ee8de146100fd578063715018a61461011d5780638da5cb5b14610125578063c76fdf6814610135578063f2fde38b14610148575f5ffd5b8063247db5dd1461009457806325c71938146100aa5780633385ab9c146100bf578063387e8311146100ea575b5f5ffd5b6001546040519081526020015b60405180910390f35b6100bd6100b836600461048c565b61015b565b005b6100d26100cd3660046104bd565b6101f9565b6040516001600160a01b0390911681526020016100a1565b6100d26100f83660046104bd565b61022d565b61011061010b3660046104e5565b610246565b6040516100a19190610505565b6100bd6102b9565b5f546001600160a01b03166100d2565b6100d26101433660046105ef565b6102cc565b6100bd6101563660046104e5565b6103a7565b6101636103e9565b604051633dd1eb6160e01b81526001600160a01b038281166004830152831690633dd1eb61906024015f604051808303815f87803b1580156101a3575f5ffd5b505af11580156101b5573d5f5f3e3d5ffd5b505050506001600160a01b039081165f9081526003602090815260408220805460018101825590835291200180546001600160a01b03191692909116919091179055565b6002602052815f5260405f208181548110610212575f80fd5b5f918252602090912001546001600160a01b03169150829050565b6003602052815f5260405f208181548110610212575f80fd5b6001600160a01b0381165f908152600260209081526040918290208054835181840281018401909452808452606093928301828280156102ad57602002820191905f5260205f20905b81546001600160a01b0316815260019091019060200180831161028f575b50505050509050919050565b6102c16103e9565b6102ca5f610415565b565b5f5f3387878787876040516102e090610464565b6102ef9695949392919061069d565b604051809103905ff080158015610308573d5f5f3e3d5ffd5b50335f8181526002602090815260408083208054600180820183559185529383902090930180546001600160a01b0319166001600160a01b038716908117909155925481519384529183019190915292935083927f054189e2ad79e5c2d10e8da115126520634a6a9b369a130345025ae1ddeafe92910160405180910390a260018054905f610396836106ee565b909155509098975050505050505050565b6103af6103e9565b6001600160a01b0381166103dd57604051631e4fbdf760e01b81525f60048201526024015b60405180910390fd5b6103e681610415565b50565b5f546001600160a01b031633146102ca5760405163118cdaa760e01b81523360048201526024016103d4565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b611f768061071383390190565b80356001600160a01b0381168114610487575f5ffd5b919050565b5f5f6040838503121561049d575f5ffd5b6104a683610471565b91506104b460208401610471565b90509250929050565b5f5f604083850312156104ce575f5ffd5b6104d783610471565b946020939093013593505050565b5f602082840312156104f5575f5ffd5b6104fe82610471565b9392505050565b602080825282518282018190525f918401906040840190835b818110156105455783516001600160a01b031683526020938401939092019160010161051e565b509095945050505050565b634e487b7160e01b5f52604160045260245ffd5b5f82601f830112610573575f5ffd5b813567ffffffffffffffff81111561058d5761058d610550565b604051601f8201601f19908116603f0116810167ffffffffffffffff811182821017156105bc576105bc610550565b6040528181528382016020018510156105d3575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f5f5f5f5f60a08688031215610603575f5ffd5b853594506020860135935060408601359250606086013567ffffffffffffffff81111561062e575f5ffd5b61063a88828901610564565b925050608086013567ffffffffffffffff811115610656575f5ffd5b61066288828901610564565b9150509295509295909350565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b60018060a01b038716815285602082015284604082015283606082015260c060808201525f6106cf60c083018561066f565b82810360a08401526106e1818561066f565b9998505050505050505050565b5f6001820161070b57634e487b7160e01b5f52601160045260245ffd5b506001019056fe610180604052600c805460ff1916600117905573355e559bca86346b82d58be0460d661db481e05e61016052348015610036575f5ffd5b50604051611f76380380611f7683398101604081905261005591610370565b6040805180820190915260018152603160f81b6020820152829081908184600361007f8382610492565b50600461008c8282610492565b5061009c915083905060056101b0565b610120526100ab8160066101b0565b61014052815160208084019190912060e052815190820120610100524660a05261013760e05161010051604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201529081019290925260608201524660808201523060a08201525f9060c00160405160208183030381529060405280519060200120905090565b60805250503060c0525061014b5f876101e2565b506101767f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6876101e2565b506009859055600a849055600b839055600e6101928382610492565b50600f61019f8282610492565b505042600d55506105a49350505050565b5f6020835110156101cb576101c48361028d565b90506101dc565b816101d68482610492565b5060ff90505b92915050565b5f8281526008602090815260408083206001600160a01b038516845290915281205460ff16610286575f8381526008602090815260408083206001600160a01b03861684529091529020805460ff1916600117905561023e3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016101dc565b505f6101dc565b5f5f829050601f815111156102c0578260405163305a27a960e01b81526004016102b7919061054c565b60405180910390fd5b80516102cb82610581565b179392505050565b634e487b7160e01b5f52604160045260245ffd5b5f82601f8301126102f6575f5ffd5b81516001600160401b0381111561030f5761030f6102d3565b604051601f8201601f19908116603f011681016001600160401b038111828210171561033d5761033d6102d3565b604052818152838201602001851015610354575f5ffd5b8160208501602083015e5f918101602001919091529392505050565b5f5f5f5f5f5f60c08789031215610385575f5ffd5b86516001600160a01b038116811461039b575f5ffd5b6020880151604089015160608a015160808b0151939950919750955093506001600160401b038111156103cc575f5ffd5b6103d889828a016102e7565b60a089015190935090506001600160401b038111156103f5575f5ffd5b61040189828a016102e7565b9150509295509295509295565b600181811c9082168061042257607f821691505b60208210810361044057634e487b7160e01b5f52602260045260245ffd5b50919050565b601f82111561048d57805f5260205f20601f840160051c8101602085101561046b5750805b601f840160051c820191505b8181101561048a575f8155600101610477565b50505b505050565b81516001600160401b038111156104ab576104ab6102d3565b6104bf816104b9845461040e565b84610446565b6020601f8211600181146104f1575f83156104da5750848201515b5f19600385901b1c1916600184901b17845561048a565b5f84815260208120601f198516915b828110156105205787850151825560209485019460019092019101610500565b508482101561053d57868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b80516020808301519190811015610440575f1960209190910360031b1b16919050565b60805160a05160c05160e051610100516101205161014051610160516119706106065f395f81816103d8015261077301525f610ffd01525f610fd001525f610eda01525f610eb201525f610e0d01525f610e3701525f610e6101526119705ff3fe608060405234801561000f575f5ffd5b5060043610610229575f3560e01c8063735328021161012a57806395d89b41116100b4578063d547741f11610079578063d547741f14610493578063d5abeb01146104a6578063dd62ed3e146104af578063e488ede8146104e7578063e6ad10e1146104fa575f5ffd5b806395d89b4114610451578063a217fddf146103b1578063a9059cbb14610459578063d505accf1461046c578063d53913931461047f575f5ffd5b806381fb8b06116100fa57806381fb8b06146103d357806383de3e6a1461041257806384b0196e1461041a5780638e80ff5d1461043557806391d148541461043e575f5ffd5b8063735328021461039e57806375b238fc146103b15780637b61c320146103b85780637ecebe00146103c0575f5ffd5b80633644e515116101b657806355233b481161017b57806355233b481461034957806369e2f0fb146103525780636c02a931146103655780636c8597fc1461036d57806370a0823114610376575f5ffd5b80633644e515146102fb57806336568abe146103035780633dd1eb611461031657806340c10f191461032957806348709a931461033c575f5ffd5b806318160ddd116101fc57806318160ddd1461029257806323b872dd146102a4578063248a9ca3146102b75780632f2ff15d146102d9578063313ce567146102ec575f5ffd5b806301ffc9a71461022d57806306fdde03146102555780630914d4da1461026a578063095ea7b31461027f575b5f5ffd5b61024061023b3660046115ee565b610503565b60405190151581526020015b60405180910390f35b61025d610539565b60405161024c919061164a565b61027d61027836600461165c565b6105c9565b005b61024061028d36600461168e565b610655565b6002545b60405190815260200161024c565b6102406102b23660046116b6565b61066c565b6102966102c536600461165c565b5f9081526008602052604090206001015490565b61027d6102e73660046116f0565b61068f565b6040516012815260200161024c565b6102966106b9565b61027d6103113660046116f0565b6106c7565b61027d61032436600461171a565b6106ff565b61027d61033736600461168e565b610724565b600c546102409060ff1681565b610296600b5481565b61027d61036036600461171a565b6108a3565b61025d6108c4565b6102966101f481565b61029661038436600461171a565b6001600160a01b03165f9081526020819052604090205490565b61027d6103ac36600461165c565b610950565b6102965f81565b61025d6109cd565b6102966103ce36600461171a565b6109da565b6103fa7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200161024c565b61027d6109f7565b610422610a0e565b60405161024c9796959493929190611733565b610296600d5481565b61024061044c3660046116f0565b610a50565b61025d610a7a565b61024061046736600461168e565b610a89565b61027d61047a3660046117c9565b610a96565b6102965f51602061191b5f395f51905f5281565b61027d6104a13660046116f0565b610bcc565b61029660095481565b6102966104bd366004611836565b6001600160a01b039182165f90815260016020908152604080832093909416825291909152205490565b61027d6104f536600461165c565b610bf0565b610296600a5481565b5f6001600160e01b03198216637965db0b60e01b148061053357506301ffc9a760e01b6001600160e01b03198316145b92915050565b6060600380546105489061185e565b80601f01602080910402602001604051908101604052809291908181526020018280546105749061185e565b80156105bf5780601f10610596576101008083540402835291602001916105bf565b820191905f5260205f20905b8154815290600101906020018083116105a257829003601f168201915b5050505050905090565b5f6105d381610c83565b600a54821061064f5760405162461bcd60e51b815260206004820152603f60248201527f4e6577207468726573686f6c6420737570706c79206d757374206265206c657360448201527f73207468616e2063757272656e74207468726573686f6c6420737570706c790060648201526084015b60405180910390fd5b50600a55565b5f33610662818585610c90565b5060019392505050565b5f33610679858285610c9d565b610684858585610d13565b506001949350505050565b5f828152600860205260409020600101546106a981610c83565b6106b38383610d70565b50505050565b5f6106c2610e01565b905090565b6001600160a01b03811633146106f05760405163334bd91960e11b815260040160405180910390fd5b6106fa8282610f2a565b505050565b5f61070981610c83565b6107205f51602061191b5f395f51905f528361068f565b5050565b5f51602061191b5f395f51905f5261073b81610c83565b5f61074560025490565b90505f620186a06107586101f4866118aa565b61076291906118c1565b905061076e8585610f95565b6107987f000000000000000000000000000000000000000000000000000000000000000082610f95565b42600d55600954816107aa86856118e0565b6107b491906118e0565b11156107fb5760405162461bcd60e51b815260206004820152601660248201527545786365656473206d6178696d756d20737570706c7960501b6044820152606401610646565b600a54821061089c575f600d544261081391906118f3565b90505f63bbf81e0082600b548661082a91906118aa565b61083491906118aa565b61083e91906118c1565b90508061084b84886118e0565b11156108995760405162461bcd60e51b815260206004820152601e60248201527f45786365656473206d6178696d756d20657870616e73696f6e207261746500006044820152606401610646565b50505b5050505050565b5f6108ad81610c83565b6107205f51602061191b5f395f51905f5283610bcc565b600e80546108d19061185e565b80601f01602080910402602001604051908101604052809291908181526020018280546108fd9061185e565b80156109485780601f1061091f57610100808354040283529160200191610948565b820191905f5260205f20905b81548152906001019060200180831161092b57829003601f168201915b505050505081565b5f61095a81610c83565b60095482106109c75760405162461bcd60e51b815260206004820152603360248201527f4e6577206d617820737570706c79206d757374206265206c657373207468616e6044820152722063757272656e74206d617820737570706c7960681b6064820152608401610646565b50600955565b600f80546108d19061185e565b6001600160a01b0381165f90815260076020526040812054610533565b5f610a0181610c83565b50600c805460ff19169055565b5f6060805f5f5f6060610a1f610fc9565b610a27610ff6565b604080515f80825260208201909252600f60f81b9b939a50919850469750309650945092509050565b5f9182526008602090815260408084206001600160a01b0393909316845291905290205460ff1690565b6060600480546105489061185e565b5f33610662818585610d13565b83421115610aba5760405163313c898160e11b815260048101859052602401610646565b5f7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9888888610b058c6001600160a01b03165f90815260076020526040902080546001810190915590565b6040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e0016040516020818303038152906040528051906020012090505f610b5f82611023565b90505f610b6e8287878761104f565b9050896001600160a01b0316816001600160a01b031614610bb5576040516325c0072360e11b81526001600160a01b0380831660048301528b166024820152604401610646565b610bc08a8a8a610c90565b50505050505050505050565b5f82815260086020526040902060010154610be681610c83565b6106b38383610f2a565b5f610bfa81610c83565b600b548210610c7d5760405162461bcd60e51b815260206004820152604360248201527f4e6577206d617820657870616e73696f6e2072617465206d757374206265206c60448201527f657373207468616e2063757272656e74206d617820657870616e73696f6e207260648201526261746560e81b608482015260a401610646565b50600b55565b610c8d813361107b565b50565b6106fa83838360016110b4565b6001600160a01b038381165f908152600160209081526040808320938616835292905220545f198110156106b35781811015610d0557604051637dc7a0d960e11b81526001600160a01b03841660048201526024810182905260448101839052606401610646565b6106b384848484035f6110b4565b6001600160a01b038316610d3c57604051634b637e8f60e11b81525f6004820152602401610646565b6001600160a01b038216610d655760405163ec442f0560e01b81525f6004820152602401610646565b6106fa838383611186565b5f610d7b8383610a50565b610dfa575f8381526008602090815260408083206001600160a01b03861684529091529020805460ff19166001179055610db23390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610533565b505f610533565b5f306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148015610e5957507f000000000000000000000000000000000000000000000000000000000000000046145b15610e8357507f000000000000000000000000000000000000000000000000000000000000000090565b6106c2604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f0000000000000000000000000000000000000000000000000000000000000000918101919091527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a08201525f9060c00160405160208183030381529060405280519060200120905090565b5f610f358383610a50565b15610dfa575f8381526008602090815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610533565b6001600160a01b038216610fbe5760405163ec442f0560e01b81525f6004820152602401610646565b6107205f8383611186565b60606106c27f0000000000000000000000000000000000000000000000000000000000000000600561123b565b60606106c27f0000000000000000000000000000000000000000000000000000000000000000600661123b565b5f61053361102f610e01565b8360405161190160f01b8152600281019290925260228201526042902090565b5f5f5f5f61105f888888886112e4565b92509250925061106f82826113ac565b50909695505050505050565b6110858282610a50565b6107205760405163e2517d3f60e01b81526001600160a01b038216600482015260248101839052604401610646565b6001600160a01b0384166110dd5760405163e602df0560e01b81525f6004820152602401610646565b6001600160a01b03831661110657604051634a1406b160e11b81525f6004820152602401610646565b6001600160a01b038085165f90815260016020908152604080832093871683529290522082905580156106b357826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258460405161117891815260200190565b60405180910390a350505050565b600c5460ff1615611230576001600160a01b03831615806111ae57506001600160a01b038216155b806111ce57506001600160a01b0382165f90815260208190526040812054115b6112305760405162461bcd60e51b815260206004820152602d60248201527f5472616e73666572207265737472696374656420746f206578697374696e672060448201526c746f6b656e20686f6c6465727360981b6064820152608401610646565b6106fa838383611464565b606060ff83146112555761124e8361158a565b9050610533565b8180546112619061185e565b80601f016020809104026020016040519081016040528092919081815260200182805461128d9061185e565b80156112d85780601f106112af576101008083540402835291602001916112d8565b820191905f5260205f20905b8154815290600101906020018083116112bb57829003601f168201915b50505050509050610533565b5f80807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a084111561131d57505f915060039050826113a2565b604080515f808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa15801561136e573d5f5f3e3d5ffd5b5050604051601f1901519150506001600160a01b03811661139957505f9250600191508290506113a2565b92505f91508190505b9450945094915050565b5f8260038111156113bf576113bf611906565b036113c8575050565b60018260038111156113dc576113dc611906565b036113fa5760405163f645eedf60e01b815260040160405180910390fd5b600282600381111561140e5761140e611906565b0361142f5760405163fce698f760e01b815260048101829052602401610646565b600382600381111561144357611443611906565b03610720576040516335e2f38360e21b815260048101829052602401610646565b6001600160a01b03831661148e578060025f82825461148391906118e0565b909155506114fe9050565b6001600160a01b0383165f90815260208190526040902054818110156114e05760405163391434e360e21b81526001600160a01b03851660048201526024810182905260448101839052606401610646565b6001600160a01b0384165f9081526020819052604090209082900390555b6001600160a01b03821661151a57600280548290039055611538565b6001600160a01b0382165f9081526020819052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161157d91815260200190565b60405180910390a3505050565b60605f611596836115c7565b6040805160208082528183019092529192505f91906020820181803683375050509182525060208101929092525090565b5f60ff8216601f81111561053357604051632cd44ac360e21b815260040160405180910390fd5b5f602082840312156115fe575f5ffd5b81356001600160e01b031981168114611615575f5ffd5b9392505050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f611615602083018461161c565b5f6020828403121561166c575f5ffd5b5035919050565b80356001600160a01b0381168114611689575f5ffd5b919050565b5f5f6040838503121561169f575f5ffd5b6116a883611673565b946020939093013593505050565b5f5f5f606084860312156116c8575f5ffd5b6116d184611673565b92506116df60208501611673565b929592945050506040919091013590565b5f5f60408385031215611701575f5ffd5b8235915061171160208401611673565b90509250929050565b5f6020828403121561172a575f5ffd5b61161582611673565b60ff60f81b8816815260e060208201525f61175160e083018961161c565b8281036040840152611763818961161c565b606084018890526001600160a01b038716608085015260a0840186905283810360c0850152845180825260208087019350909101905f5b818110156117b857835183526020938401939092019160010161179a565b50909b9a5050505050505050505050565b5f5f5f5f5f5f5f60e0888a0312156117df575f5ffd5b6117e888611673565b96506117f660208901611673565b95506040880135945060608801359350608088013560ff81168114611819575f5ffd5b9699959850939692959460a0840135945060c09093013592915050565b5f5f60408385031215611847575f5ffd5b61185083611673565b915061171160208401611673565b600181811c9082168061187257607f821691505b60208210810361189057634e487b7160e01b5f52602260045260245ffd5b50919050565b634e487b7160e01b5f52601160045260245ffd5b808202811582820484141761053357610533611896565b5f826118db57634e487b7160e01b5f52601260045260245ffd5b500490565b8082018082111561053357610533611896565b8181038181111561053357610533611896565b634e487b7160e01b5f52602160045260245ffdfe9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6a2646970667358221220b48d06dfe162a9b2ed0088f3f19fe7610c0a09b89b526efd5ce65a8f1329fc8064736f6c634300081c0033a264697066735822122029caf5f3cba9971fbe382374d529fff168aaddfc7939a62f336d7d7d6049f59d64736f6c634300081c0033", + "sourceMap": "157:2369:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2291:87;2359:12;;2291:87;;160:25:26;;;148:2;133:18;2291:87:0;;;;;;;;1933:241;;;;;;:::i;:::-;;:::i;:::-;;282:57;;;;;;:::i;:::-;;:::i;:::-;;;-1:-1:-1;;;;;1108:32:26;;;1090:51;;1078:2;1063:18;282:57:0;944:203:26;346:51:0;;;;;;:::i;:::-;;:::i;2384:140::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;2293:101:4:-;;;:::i;1638:85::-;1684:7;1710:6;-1:-1:-1;;;;;1710:6:4;1638:85;;1023:705:0;;;;;;:::i;:::-;;:::i;2543:215:4:-;;;;;;:::i;:::-;;:::i;1933:241:0:-;1531:13:4;:11;:13::i;:::-;2021:63:0::1;::::0;-1:-1:-1;;;2021:63:0;;-1:-1:-1;;;;;1108:32:26;;;2021:63:0::1;::::0;::::1;1090:51:26::0;2021:55:0;::::1;::::0;::::1;::::0;1063:18:26;;2021:63:0::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1::0;;;;;;;;;2094:22:0;;::::1;;::::0;;;:14:::1;:22;::::0;;;;;;:39;;::::1;::::0;::::1;::::0;;;;;;;::::1;::::0;;-1:-1:-1;;;;;;2094:39:0::1;::::0;;;::::1;::::0;;;::::1;::::0;;1933:241::o;282:57::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;282:57:0;;-1:-1:-1;282:57:0;;-1:-1:-1;282:57:0:o;346:51::-;;;;;;;;;;;;;;;;;;;;2384:140;-1:-1:-1;;;;;2487:30:0;;;;;;:20;:30;;;;;;;;;2480:37;;;;;;;;;;;;;;;;;2452:16;;2480:37;;;2487:30;2480:37;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;2480:37:0;;;;;;;;;;;;;;;;;;;;;;;2384:140;;;:::o;2293:101:4:-;1531:13;:11;:13::i;:::-;2357:30:::1;2384:1;2357:18;:30::i;:::-;2293:101::o:0;1023:705:0:-;1216:7;1235:34;1317:10;1341:9;1364:15;1393:16;1423:4;1441:6;1272:185;;;;;:::i;:::-;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1535:10:0;1468:18;1514:32;;;:20;:32;;;;;;;;:49;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;1514:49:0;-1:-1:-1;;;;;1514:49:0;;;;;;;;1613:12;;1578:48;;4917:51:26;;;4984:18;;;4977:34;;;;1514:49:0;;-1:-1:-1;1514:49:0;;1578:48;;4890:18:26;1578:48:0;;;;;;;1636:12;:14;;;:12;:14;;;:::i;:::-;;;;-1:-1:-1;1711:10:0;;1023:705;-1:-1:-1;;;;;;;;1023:705:0:o;2543:215:4:-;1531:13;:11;:13::i;:::-;-1:-1:-1;;;;;2627:22:4;::::1;2623:91;;2672:31;::::0;-1:-1:-1;;;2672:31:4;;2700:1:::1;2672:31;::::0;::::1;1090:51:26::0;1063:18;;2672:31:4::1;;;;;;;;2623:91;2723:28;2742:8;2723:18;:28::i;:::-;2543:215:::0;:::o;1796:162::-;1684:7;1710:6;-1:-1:-1;;;;;1710:6:4;735:10:12;1855:23:4;1851:101;;1901:40;;-1:-1:-1;;;1901:40:4;;735:10:12;1901:40:4;;;1090:51:26;1063:18;;1901:40:4;944:203:26;2912:187:4;2985:16;3004:6;;-1:-1:-1;;;;;3020:17:4;;;-1:-1:-1;;;;;;3020:17:4;;;;;;3052:40;;3004:6;;;;;;;3052:40;;2985:16;3052:40;2975:124;2912:187;:::o;-1:-1:-1:-;;;;;;;;:::o;196:173:26:-;264:20;;-1:-1:-1;;;;;313:31:26;;303:42;;293:70;;359:1;356;349:12;293:70;196:173;;;:::o;374:260::-;442:6;450;503:2;491:9;482:7;478:23;474:32;471:52;;;519:1;516;509:12;471:52;542:29;561:9;542:29;:::i;:::-;532:39;;590:38;624:2;613:9;609:18;590:38;:::i;:::-;580:48;;374:260;;;;;:::o;639:300::-;707:6;715;768:2;756:9;747:7;743:23;739:32;736:52;;;784:1;781;774:12;736:52;807:29;826:9;807:29;:::i;:::-;797:39;905:2;890:18;;;;877:32;;-1:-1:-1;;;639:300:26:o;1152:186::-;1211:6;1264:2;1252:9;1243:7;1239:23;1235:32;1232:52;;;1280:1;1277;1270:12;1232:52;1303:29;1322:9;1303:29;:::i;:::-;1293:39;1152:186;-1:-1:-1;;;1152:186:26:o;1343:637::-;1533:2;1545:21;;;1615:13;;1518:18;;;1637:22;;;1485:4;;1716:15;;;1690:2;1675:18;;;1485:4;1759:195;1773:6;1770:1;1767:13;1759:195;;;1838:13;;-1:-1:-1;;;;;1834:39:26;1822:52;;1903:2;1929:15;;;;1894:12;;;;1870:1;1788:9;1759:195;;;-1:-1:-1;1971:3:26;;1343:637;-1:-1:-1;;;;;1343:637:26:o;1985:127::-;2046:10;2041:3;2037:20;2034:1;2027:31;2077:4;2074:1;2067:15;2101:4;2098:1;2091:15;2117:726;2160:5;2213:3;2206:4;2198:6;2194:17;2190:27;2180:55;;2231:1;2228;2221:12;2180:55;2271:6;2258:20;2301:18;2293:6;2290:30;2287:56;;;2323:18;;:::i;:::-;2372:2;2366:9;2464:2;2426:17;;-1:-1:-1;;2422:31:26;;;2455:2;2418:40;2414:54;2402:67;;2499:18;2484:34;;2520:22;;;2481:62;2478:88;;;2546:18;;:::i;:::-;2582:2;2575:22;2606;;;2647:19;;;2668:4;2643:30;2640:39;-1:-1:-1;2637:59:26;;;2692:1;2689;2682:12;2637:59;2756:6;2749:4;2741:6;2737:17;2730:4;2722:6;2718:17;2705:58;2811:1;2783:19;;;2804:4;2779:30;2772:41;;;;2787:6;2117:726;-1:-1:-1;;;2117:726:26:o;2848:894::-;2963:6;2971;2979;2987;2995;3048:3;3036:9;3027:7;3023:23;3019:33;3016:53;;;3065:1;3062;3055:12;3016:53;3110:23;;;-1:-1:-1;3230:2:26;3215:18;;3202:32;;-1:-1:-1;3333:2:26;3318:18;;3305:32;;-1:-1:-1;3414:2:26;3399:18;;3386:32;3441:18;3430:30;;3427:50;;;3473:1;3470;3463:12;3427:50;3496;3538:7;3529:6;3518:9;3514:22;3496:50;:::i;:::-;3486:60;;;3599:3;3588:9;3584:19;3571:33;3629:18;3619:8;3616:32;3613:52;;;3661:1;3658;3651:12;3613:52;3684;3728:7;3717:8;3706:9;3702:24;3684:52;:::i;:::-;3674:62;;;2848:894;;;;;;;;:::o;3747:289::-;3789:3;3827:5;3821:12;3854:6;3849:3;3842:19;3910:6;3903:4;3896:5;3892:16;3885:4;3880:3;3876:14;3870:47;3962:1;3955:4;3946:6;3941:3;3937:16;3933:27;3926:38;4025:4;4018:2;4014:7;4009:2;4001:6;3997:15;3993:29;3988:3;3984:39;3980:50;3973:57;;;3747:289;;;;:::o;4041:697::-;4379:1;4375;4370:3;4366:11;4362:19;4354:6;4350:32;4339:9;4332:51;4419:6;4414:2;4403:9;4399:18;4392:34;4462:6;4457:2;4446:9;4442:18;4435:34;4505:6;4500:2;4489:9;4485:18;4478:34;4549:3;4543;4532:9;4528:19;4521:32;4313:4;4576:46;4617:3;4606:9;4602:19;4594:6;4576:46;:::i;:::-;4671:9;4663:6;4659:22;4653:3;4642:9;4638:19;4631:51;4699:33;4725:6;4717;4699:33;:::i;:::-;4691:41;4041:697;-1:-1:-1;;;;;;;;;4041:697:26:o;5022:232::-;5061:3;5082:17;;;5079:140;;5141:10;5136:3;5132:20;5129:1;5122:31;5176:4;5173:1;5166:15;5204:4;5201:1;5194:15;5079:140;-1:-1:-1;5246:1:26;5235:13;;5022:232::o", + "linkReferences": {} + }, + "methodIdentifiers": { + "administerableTokens(address,uint256)": "3385ab9c", + "createCAT(uint256,uint256,uint256,string,string)": "c76fdf68", + "getVaultAddresses(address)": "695ee8de", + "grantMinterRole(address,address)": "25c71938", + "mintableTokens(address,uint256)": "387e8311", + "owner()": "8da5cb5b", + "renounceOwnership()": "715018a6", + "totalCATs()": "247db5dd", + "transferOwnership(address)": "f2fde38b" + }, + "rawMetadata": "{\"compiler\":{\"version\":\"0.8.28+commit.7893614a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"OwnableInvalidOwner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"OwnableUnauthorizedAccount\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"catAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"CATCreated\",\"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\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"administerableTokens\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"maxSupply\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"thresholdSupply\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxExpansionRate\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"symbol\",\"type\":\"string\"}],\"name\":\"createCAT\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_creator\",\"type\":\"address\"}],\"name\":\"getVaultAddresses\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"catAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"minter\",\"type\":\"address\"}],\"name\":\"grantMinterRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"mintableTokens\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalCATs\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"OwnableInvalidOwner(address)\":[{\"details\":\"The owner is not a valid owner account. (eg. `address(0)`)\"}],\"OwnableUnauthorizedAccount(address)\":[{\"details\":\"The caller account is not authorized to perform an operation.\"}]},\"kind\":\"dev\",\"methods\":{\"createCAT(uint256,uint256,uint256,string,string)\":{\"details\":\"Creates a new CAT contract and assigns it to the caller.\",\"params\":{\"maxExpansionRate\":\"The maximum expansion rate for the new CAT.\",\"maxSupply\":\"The maximum supply for the new CAT.\",\"name\":\"The name of the CAT token.\",\"symbol\":\"The symbol of the CAT token.\",\"thresholdSupply\":\"The threshold supply for the new CAT.\"},\"returns\":{\"_0\":\"The address of the newly created CAT contract.\"}},\"grantMinterRole(address,address)\":{\"details\":\"Grants minter role to an address in the CAT contract.\",\"params\":{\"catAddress\":\"The address of the CAT contract.\",\"minter\":\"The address to grant the minter role.\"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner.\"},\"totalCATs()\":{\"details\":\"Returns the total number of CATs created.\",\"returns\":{\"_0\":\"The total number of CATs.\"}},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/CATFactory.sol\":\"CATFactory\"},\"evmVersion\":\"cancun\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[\":@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/\",\":erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/\",\":forge-std/=lib/openzeppelin-contracts/lib/forge-std/src/\",\":halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/\",\":openzeppelin-contracts/=lib/openzeppelin-contracts/\"]},\"sources\":{\"contracts/CATFactory.sol\":{\"keccak256\":\"0x01c26f10b7428fc9c9f7372ad8988f082853d97ab51687f867c58203deaec88e\",\"license\":\"AEL\",\"urls\":[\"bzz-raw://eefaa94541e645aeab647cff1a59d9b8cc0f66dc8a6f180c6d0b0e8325abda5f\",\"dweb:/ipfs/QmbsURrhXH6XTq83EDoqm1EfnhKYTWBjivu7gHqTaocJp5\"]},\"contracts/ContributionAccountingToken.sol\":{\"keccak256\":\"0xe9a9f746be738f74f5e2958534fdf563bf017304ffa10d2b518a9650638793f6\",\"license\":\"AEL\",\"urls\":[\"bzz-raw://dcec763f8832e8214e89ab67434f92fbca8eda7f5fbfb13eb7516f0bc243cce4\",\"dweb:/ipfs/QmdkGCk94aX64nhzvUNi1Y4yfACK58hjsHL7iBcpyM1uQR\"]},\"lib/openzeppelin-contracts/contracts/access/AccessControl.sol\":{\"keccak256\":\"0xa0e92d42942f4f57c5be50568dac11e9d00c93efcb458026e18d2d9b9b2e7308\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://46326c0bb1e296b67185e81c918e0b40501b8b6386165855df0a3f3c634b6a80\",\"dweb:/ipfs/QmTwyrDYtsxsk6pymJTK94PnEpzsmkpUxFuzEiakDopy4Z\"]},\"lib/openzeppelin-contracts/contracts/access/IAccessControl.sol\":{\"keccak256\":\"0xc1c2a7f1563b77050dc6d507db9f4ada5d042c1f6a9ddbffdc49c77cdc0a1606\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://fd54abb96a6156d9a761f6fdad1d3004bc48d2d4fce47f40a3f91a7ae83fc3a1\",\"dweb:/ipfs/QmUrFSGkTDJ7WaZ6qPVVe3Gn5uN2viPb7x7QQ35UX4DofX\"]},\"lib/openzeppelin-contracts/contracts/access/Ownable.sol\":{\"keccak256\":\"0xff6d0bb2e285473e5311d9d3caacb525ae3538a80758c10649a4d61029b017bb\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://8ed324d3920bb545059d66ab97d43e43ee85fd3bd52e03e401f020afb0b120f6\",\"dweb:/ipfs/QmfEckWLmZkDDcoWrkEvMWhms66xwTLff9DDhegYpvHo1a\"]},\"lib/openzeppelin-contracts/contracts/interfaces/IERC5267.sol\":{\"keccak256\":\"0x92aa1df62dc3d33f1656d63bede0923e0df0b706ad4137c8b10b0a8fe549fd92\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://c5c0f29195ad64cbe556da8e257dac8f05f78c53f90323c0d2accf8e6922d33a\",\"dweb:/ipfs/QmQ61TED8uaCZwcbh8KkgRSsCav7x7HbcGHwHts3U4DmUP\"]},\"lib/openzeppelin-contracts/contracts/interfaces/draft-IERC6093.sol\":{\"keccak256\":\"0x880da465c203cec76b10d72dbd87c80f387df4102274f23eea1f9c9b0918792b\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://399594cd8bb0143bc9e55e0f1d071d0d8c850a394fb7a319d50edd55d9ed822b\",\"dweb:/ipfs/QmbPZzgtT6LEm9CMqWfagQFwETbV1ztpECBB1DtQHrKiRz\"]},\"lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol\":{\"keccak256\":\"0x6ef9389a2c07bc40d8a7ba48914724ab2c108fac391ce12314f01321813e6368\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b7a5cb39b1e6df68f4dd9a5e76e853d745a74ffb3dfd7df4ae4d2ace6992a171\",\"dweb:/ipfs/QmPbzKR19rdM8X3PLQjsmHRepUKhvoZnedSR63XyGtXZib\"]},\"lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol\":{\"keccak256\":\"0xe06a3f08a987af6ad2e1c1e774405d4fe08f1694b67517438b467cecf0da0ef7\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://df6f0c459663c9858b6cba2cda1d14a7d05a985bed6d2de72bd8e78c25ee79db\",\"dweb:/ipfs/QmeTTxZ7qVk9rjEv2R4CpCwdf8UMCcRqDNMvzNxHc3Fnn9\"]},\"lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Permit.sol\":{\"keccak256\":\"0xaa7f0646f49ebe2606eeca169f85c56451bbaeeeb06265fa076a03369a25d1d3\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://ee931d4e832385765967efe6366dcc6d00d6a2d794f9c66ee38283c03882de9c\",\"dweb:/ipfs/QmR6SkuJGYxpQeLz38rBdghqaWqEPfzUsL9kBoXgEXKtbD\"]},\"lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"keccak256\":\"0x70f2f713b13b7ce4610bcd0ac9fec0f3cc43693b043abcb8dc40a42a726eb330\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://c13d13304ac79a83ab1c30168967d19e2203342ebbd6a9bbce4db7550522dcbf\",\"dweb:/ipfs/QmeN5jKMN2vw5bhacr6tkg78afbTTZUeaacNHqjWt4Ew1r\"]},\"lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Permit.sol\":{\"keccak256\":\"0x27dbc90e5136ffe46c04f7596fc2dbcc3acebd8d504da3d93fdb8496e6de04f6\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://0ea8b92e4245d75a5579c10f22f118f7b4ba07c57341f181f0b2a85ff8663de3\",\"dweb:/ipfs/Qme3Ss5ByjmkxxkMdLpyu7fQ1PCtjNFH1wEFszt2BZePiG\"]},\"lib/openzeppelin-contracts/contracts/utils/Context.sol\":{\"keccak256\":\"0x493033a8d1b176a037b2cc6a04dad01a5c157722049bbecf632ca876224dd4b2\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://6a708e8a5bdb1011c2c381c9a5cfd8a9a956d7d0a9dc1bd8bcdaf52f76ef2f12\",\"dweb:/ipfs/Qmax9WHBnVsZP46ZxEMNRQpLQnrdE4dK8LehML1Py8FowF\"]},\"lib/openzeppelin-contracts/contracts/utils/Nonces.sol\":{\"keccak256\":\"0x0082767004fca261c332e9ad100868327a863a88ef724e844857128845ab350f\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://132dce9686a54e025eb5ba5d2e48208f847a1ec3e60a3e527766d7bf53fb7f9e\",\"dweb:/ipfs/QmXn1a2nUZMpu2z6S88UoTfMVtY2YNh86iGrzJDYmMkKeZ\"]},\"lib/openzeppelin-contracts/contracts/utils/Panic.sol\":{\"keccak256\":\"0xf7fe324703a64fc51702311dc51562d5cb1497734f074e4f483bfb6717572d7a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://c6a5ff4f9fd8649b7ee20800b7fa387d3465bd77cf20c2d1068cd5c98e1ed57a\",\"dweb:/ipfs/QmVSaVJf9FXFhdYEYeCEfjMVHrxDh5qL4CGkxdMWpQCrqG\"]},\"lib/openzeppelin-contracts/contracts/utils/ShortStrings.sol\":{\"keccak256\":\"0x7d94fa0af099a2172eb01f9c8a8a443cbe7e0e43654841563e4e09968efdb549\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://65e38fb76b6add407d4557753ae83dd1268e8261195dbe5c19a580d5ba6e4e9a\",\"dweb:/ipfs/QmTkGSJtaQrqjcyWM4AgemeEmKgtDydKPPVRajsUJRQSrK\"]},\"lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol\":{\"keccak256\":\"0xcf74f855663ce2ae00ed8352666b7935f6cddea2932fdf2c3ecd30a9b1cd0e97\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://9f660b1f351b757dfe01438e59888f31f33ded3afcf5cb5b0d9bf9aa6f320a8b\",\"dweb:/ipfs/QmarDJ5hZEgBtCmmrVzEZWjub9769eD686jmzb2XpSU1cM\"]},\"lib/openzeppelin-contracts/contracts/utils/Strings.sol\":{\"keccak256\":\"0x44f87e91783e88415bde66f1a63f6c7f0076f2d511548820407d5c95643ac56c\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://13a51bc2b23827744dcf5bad10c69e72528cf015a6fe48c93632cdb2c0eb1251\",\"dweb:/ipfs/QmZwPA47Yqgje1qtkdEFEja8ntTahMStYzKf5q3JRnaR7d\"]},\"lib/openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol\":{\"keccak256\":\"0x69f54c02b7d81d505910ec198c11ed4c6a728418a868b906b4a0cf29946fda84\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://8e25e4bdb7ae1f21d23bfee996e22736fc0ab44cfabedac82a757b1edc5623b9\",\"dweb:/ipfs/QmQdWQvB6JCP9ZMbzi8EvQ1PTETqkcTWrbcVurS7DKpa5n\"]},\"lib/openzeppelin-contracts/contracts/utils/cryptography/EIP712.sol\":{\"keccak256\":\"0x10eb97d047f8d84fe263a02bb4a656ac6674f6679d74532cc37546289e073a9d\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://3e41287d40b0c46982f1083d40d32de2761f009c5c51627fe79a7feb0ab1cf5c\",\"dweb:/ipfs/Qme7dbh6HX3ZvUJdbQAcVqXkmyXyfcLiUZRhhon3cU6K8p\"]},\"lib/openzeppelin-contracts/contracts/utils/cryptography/MessageHashUtils.sol\":{\"keccak256\":\"0x4515543bc4c78561f6bea83ecfdfc3dead55bd59858287d682045b11de1ae575\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://60601f91440125727244fffd2ba84da7caafecaae0fd887c7ccfec678e02b61e\",\"dweb:/ipfs/QmZnKPBtVDiQS9Dp8gZ4sa3ZeTrWVfqF7yuUd6Y8hwm1Rs\"]},\"lib/openzeppelin-contracts/contracts/utils/introspection/ERC165.sol\":{\"keccak256\":\"0xddce8e17e3d3f9ed818b4f4c4478a8262aab8b11ed322f1bf5ed705bb4bd97fa\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://8084aa71a4cc7d2980972412a88fe4f114869faea3fefa5436431644eb5c0287\",\"dweb:/ipfs/Qmbqfs5dRdPvHVKY8kTaeyc65NdqXRQwRK7h9s5UJEhD1p\"]},\"lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol\":{\"keccak256\":\"0x79796192ec90263f21b464d5bc90b777a525971d3de8232be80d9c4f9fb353b8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://f6fda447a62815e8064f47eff0dd1cf58d9207ad69b5d32280f8d7ed1d1e4621\",\"dweb:/ipfs/QmfDRc7pxfaXB2Dh9np5Uf29Na3pQ7tafRS684wd3GLjVL\"]},\"lib/openzeppelin-contracts/contracts/utils/math/Math.sol\":{\"keccak256\":\"0xa00be322d7db5786750ce0ac7e2f5b633ac30a5ed5fa1ced1e74acfc19acecea\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://6c84e822f87cbdc4082533b626667b6928715bb2b1e8e7eb96954cebb9e38c8d\",\"dweb:/ipfs/QmZmy9dgxLTerBAQDuuHqbL6EpgRxddqgv5KmwpXYVbKz1\"]},\"lib/openzeppelin-contracts/contracts/utils/math/SafeCast.sol\":{\"keccak256\":\"0x195533c86d0ef72bcc06456a4f66a9b941f38eb403739b00f21fd7c1abd1ae54\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://b1d578337048cad08c1c03041cca5978eff5428aa130c781b271ad9e5566e1f8\",\"dweb:/ipfs/QmPFKL2r9CBsMwmUqqdcFPfHZB2qcs9g1HDrPxzWSxomvy\"]},\"lib/openzeppelin-contracts/contracts/utils/math/SignedMath.sol\":{\"keccak256\":\"0xb1970fac7b64e6c09611e6691791e848d5e3fe410fa5899e7df2e0afd77a99e3\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://db5fbb3dddd8b7047465b62575d96231ba8a2774d37fb4737fbf23340fabbb03\",\"dweb:/ipfs/QmVUSvooZKEdEdap619tcJjTLcAuH6QBdZqAzWwnAXZAWJ\"]}},\"version\":1}", + "metadata": { + "compiler": { "version": "0.8.28+commit.7893614a" }, + "language": "Solidity", + "output": { + "abi": [ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { "internalType": "address", "name": "owner", "type": "address" } + ], + "type": "error", + "name": "OwnableInvalidOwner" + }, + { + "inputs": [ + { "internalType": "address", "name": "account", "type": "address" } + ], + "type": "error", + "name": "OwnableUnauthorizedAccount" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address", + "indexed": true + }, + { + "internalType": "address", + "name": "catAddress", + "type": "address", + "indexed": false + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256", + "indexed": false + } + ], + "type": "event", + "name": "CATCreated", + "anonymous": false + }, + { + "inputs": [ + { + "internalType": "address", + "name": "previousOwner", + "type": "address", + "indexed": true + }, + { + "internalType": "address", + "name": "newOwner", + "type": "address", + "indexed": true + } + ], + "type": "event", + "name": "OwnershipTransferred", + "anonymous": false + }, + { + "inputs": [ + { "internalType": "address", "name": "", "type": "address" }, + { "internalType": "uint256", "name": "", "type": "uint256" } + ], + "stateMutability": "view", + "type": "function", + "name": "administerableTokens", + "outputs": [ + { "internalType": "address", "name": "", "type": "address" } + ] + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "maxSupply", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "thresholdSupply", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxExpansionRate", + "type": "uint256" + }, + { "internalType": "string", "name": "name", "type": "string" }, + { "internalType": "string", "name": "symbol", "type": "string" } + ], + "stateMutability": "nonpayable", + "type": "function", + "name": "createCAT", + "outputs": [ + { "internalType": "address", "name": "", "type": "address" } + ] + }, + { + "inputs": [ + { "internalType": "address", "name": "_creator", "type": "address" } + ], + "stateMutability": "view", + "type": "function", + "name": "getVaultAddresses", + "outputs": [ + { "internalType": "address[]", "name": "", "type": "address[]" } + ] + }, + { + "inputs": [ + { + "internalType": "address", + "name": "catAddress", + "type": "address" + }, + { "internalType": "address", "name": "minter", "type": "address" } + ], + "stateMutability": "nonpayable", + "type": "function", + "name": "grantMinterRole" + }, + { + "inputs": [ + { "internalType": "address", "name": "", "type": "address" }, + { "internalType": "uint256", "name": "", "type": "uint256" } + ], + "stateMutability": "view", + "type": "function", + "name": "mintableTokens", + "outputs": [ + { "internalType": "address", "name": "", "type": "address" } + ] + }, + { + "inputs": [], + "stateMutability": "view", + "type": "function", + "name": "owner", + "outputs": [ + { "internalType": "address", "name": "", "type": "address" } + ] + }, + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "function", + "name": "renounceOwnership" + }, + { + "inputs": [], + "stateMutability": "view", + "type": "function", + "name": "totalCATs", + "outputs": [ + { "internalType": "uint256", "name": "", "type": "uint256" } + ] + }, + { + "inputs": [ + { "internalType": "address", "name": "newOwner", "type": "address" } + ], + "stateMutability": "nonpayable", + "type": "function", + "name": "transferOwnership" + } + ], + "devdoc": { + "kind": "dev", + "methods": { + "createCAT(uint256,uint256,uint256,string,string)": { + "details": "Creates a new CAT contract and assigns it to the caller.", + "params": { + "maxExpansionRate": "The maximum expansion rate for the new CAT.", + "maxSupply": "The maximum supply for the new CAT.", + "name": "The name of the CAT token.", + "symbol": "The symbol of the CAT token.", + "thresholdSupply": "The threshold supply for the new CAT." + }, + "returns": { + "_0": "The address of the newly created CAT contract." + } + }, + "grantMinterRole(address,address)": { + "details": "Grants minter role to an address in the CAT contract.", + "params": { + "catAddress": "The address of the CAT contract.", + "minter": "The address to grant the minter role." + } + }, + "owner()": { "details": "Returns the address of the current owner." }, + "renounceOwnership()": { + "details": "Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner." + }, + "totalCATs()": { + "details": "Returns the total number of CATs created.", + "returns": { "_0": "The total number of CATs." } + }, + "transferOwnership(address)": { + "details": "Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner." + } + }, + "version": 1 + }, + "userdoc": { "kind": "user", "methods": {}, "version": 1 } + }, + "settings": { + "remappings": [ + "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/", + "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/", + "forge-std/=lib/openzeppelin-contracts/lib/forge-std/src/", + "halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/", + "openzeppelin-contracts/=lib/openzeppelin-contracts/" + ], + "optimizer": { "enabled": true, "runs": 200 }, + "metadata": { "bytecodeHash": "ipfs" }, + "compilationTarget": { "contracts/CATFactory.sol": "CATFactory" }, + "evmVersion": "cancun", + "libraries": {} + }, + "sources": { + "contracts/CATFactory.sol": { + "keccak256": "0x01c26f10b7428fc9c9f7372ad8988f082853d97ab51687f867c58203deaec88e", + "urls": [ + "bzz-raw://eefaa94541e645aeab647cff1a59d9b8cc0f66dc8a6f180c6d0b0e8325abda5f", + "dweb:/ipfs/QmbsURrhXH6XTq83EDoqm1EfnhKYTWBjivu7gHqTaocJp5" + ], + "license": "AEL" + }, + "contracts/ContributionAccountingToken.sol": { + "keccak256": "0xe9a9f746be738f74f5e2958534fdf563bf017304ffa10d2b518a9650638793f6", + "urls": [ + "bzz-raw://dcec763f8832e8214e89ab67434f92fbca8eda7f5fbfb13eb7516f0bc243cce4", + "dweb:/ipfs/QmdkGCk94aX64nhzvUNi1Y4yfACK58hjsHL7iBcpyM1uQR" + ], + "license": "AEL" + }, + "lib/openzeppelin-contracts/contracts/access/AccessControl.sol": { + "keccak256": "0xa0e92d42942f4f57c5be50568dac11e9d00c93efcb458026e18d2d9b9b2e7308", + "urls": [ + "bzz-raw://46326c0bb1e296b67185e81c918e0b40501b8b6386165855df0a3f3c634b6a80", + "dweb:/ipfs/QmTwyrDYtsxsk6pymJTK94PnEpzsmkpUxFuzEiakDopy4Z" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts/contracts/access/IAccessControl.sol": { + "keccak256": "0xc1c2a7f1563b77050dc6d507db9f4ada5d042c1f6a9ddbffdc49c77cdc0a1606", + "urls": [ + "bzz-raw://fd54abb96a6156d9a761f6fdad1d3004bc48d2d4fce47f40a3f91a7ae83fc3a1", + "dweb:/ipfs/QmUrFSGkTDJ7WaZ6qPVVe3Gn5uN2viPb7x7QQ35UX4DofX" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts/contracts/access/Ownable.sol": { + "keccak256": "0xff6d0bb2e285473e5311d9d3caacb525ae3538a80758c10649a4d61029b017bb", + "urls": [ + "bzz-raw://8ed324d3920bb545059d66ab97d43e43ee85fd3bd52e03e401f020afb0b120f6", + "dweb:/ipfs/QmfEckWLmZkDDcoWrkEvMWhms66xwTLff9DDhegYpvHo1a" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts/contracts/interfaces/IERC5267.sol": { + "keccak256": "0x92aa1df62dc3d33f1656d63bede0923e0df0b706ad4137c8b10b0a8fe549fd92", + "urls": [ + "bzz-raw://c5c0f29195ad64cbe556da8e257dac8f05f78c53f90323c0d2accf8e6922d33a", + "dweb:/ipfs/QmQ61TED8uaCZwcbh8KkgRSsCav7x7HbcGHwHts3U4DmUP" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts/contracts/interfaces/draft-IERC6093.sol": { + "keccak256": "0x880da465c203cec76b10d72dbd87c80f387df4102274f23eea1f9c9b0918792b", + "urls": [ + "bzz-raw://399594cd8bb0143bc9e55e0f1d071d0d8c850a394fb7a319d50edd55d9ed822b", + "dweb:/ipfs/QmbPZzgtT6LEm9CMqWfagQFwETbV1ztpECBB1DtQHrKiRz" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol": { + "keccak256": "0x6ef9389a2c07bc40d8a7ba48914724ab2c108fac391ce12314f01321813e6368", + "urls": [ + "bzz-raw://b7a5cb39b1e6df68f4dd9a5e76e853d745a74ffb3dfd7df4ae4d2ace6992a171", + "dweb:/ipfs/QmPbzKR19rdM8X3PLQjsmHRepUKhvoZnedSR63XyGtXZib" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol": { + "keccak256": "0xe06a3f08a987af6ad2e1c1e774405d4fe08f1694b67517438b467cecf0da0ef7", + "urls": [ + "bzz-raw://df6f0c459663c9858b6cba2cda1d14a7d05a985bed6d2de72bd8e78c25ee79db", + "dweb:/ipfs/QmeTTxZ7qVk9rjEv2R4CpCwdf8UMCcRqDNMvzNxHc3Fnn9" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Permit.sol": { + "keccak256": "0xaa7f0646f49ebe2606eeca169f85c56451bbaeeeb06265fa076a03369a25d1d3", + "urls": [ + "bzz-raw://ee931d4e832385765967efe6366dcc6d00d6a2d794f9c66ee38283c03882de9c", + "dweb:/ipfs/QmR6SkuJGYxpQeLz38rBdghqaWqEPfzUsL9kBoXgEXKtbD" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol": { + "keccak256": "0x70f2f713b13b7ce4610bcd0ac9fec0f3cc43693b043abcb8dc40a42a726eb330", + "urls": [ + "bzz-raw://c13d13304ac79a83ab1c30168967d19e2203342ebbd6a9bbce4db7550522dcbf", + "dweb:/ipfs/QmeN5jKMN2vw5bhacr6tkg78afbTTZUeaacNHqjWt4Ew1r" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Permit.sol": { + "keccak256": "0x27dbc90e5136ffe46c04f7596fc2dbcc3acebd8d504da3d93fdb8496e6de04f6", + "urls": [ + "bzz-raw://0ea8b92e4245d75a5579c10f22f118f7b4ba07c57341f181f0b2a85ff8663de3", + "dweb:/ipfs/Qme3Ss5ByjmkxxkMdLpyu7fQ1PCtjNFH1wEFszt2BZePiG" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts/contracts/utils/Context.sol": { + "keccak256": "0x493033a8d1b176a037b2cc6a04dad01a5c157722049bbecf632ca876224dd4b2", + "urls": [ + "bzz-raw://6a708e8a5bdb1011c2c381c9a5cfd8a9a956d7d0a9dc1bd8bcdaf52f76ef2f12", + "dweb:/ipfs/Qmax9WHBnVsZP46ZxEMNRQpLQnrdE4dK8LehML1Py8FowF" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts/contracts/utils/Nonces.sol": { + "keccak256": "0x0082767004fca261c332e9ad100868327a863a88ef724e844857128845ab350f", + "urls": [ + "bzz-raw://132dce9686a54e025eb5ba5d2e48208f847a1ec3e60a3e527766d7bf53fb7f9e", + "dweb:/ipfs/QmXn1a2nUZMpu2z6S88UoTfMVtY2YNh86iGrzJDYmMkKeZ" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts/contracts/utils/Panic.sol": { + "keccak256": "0xf7fe324703a64fc51702311dc51562d5cb1497734f074e4f483bfb6717572d7a", + "urls": [ + "bzz-raw://c6a5ff4f9fd8649b7ee20800b7fa387d3465bd77cf20c2d1068cd5c98e1ed57a", + "dweb:/ipfs/QmVSaVJf9FXFhdYEYeCEfjMVHrxDh5qL4CGkxdMWpQCrqG" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts/contracts/utils/ShortStrings.sol": { + "keccak256": "0x7d94fa0af099a2172eb01f9c8a8a443cbe7e0e43654841563e4e09968efdb549", + "urls": [ + "bzz-raw://65e38fb76b6add407d4557753ae83dd1268e8261195dbe5c19a580d5ba6e4e9a", + "dweb:/ipfs/QmTkGSJtaQrqjcyWM4AgemeEmKgtDydKPPVRajsUJRQSrK" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol": { + "keccak256": "0xcf74f855663ce2ae00ed8352666b7935f6cddea2932fdf2c3ecd30a9b1cd0e97", + "urls": [ + "bzz-raw://9f660b1f351b757dfe01438e59888f31f33ded3afcf5cb5b0d9bf9aa6f320a8b", + "dweb:/ipfs/QmarDJ5hZEgBtCmmrVzEZWjub9769eD686jmzb2XpSU1cM" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts/contracts/utils/Strings.sol": { + "keccak256": "0x44f87e91783e88415bde66f1a63f6c7f0076f2d511548820407d5c95643ac56c", + "urls": [ + "bzz-raw://13a51bc2b23827744dcf5bad10c69e72528cf015a6fe48c93632cdb2c0eb1251", + "dweb:/ipfs/QmZwPA47Yqgje1qtkdEFEja8ntTahMStYzKf5q3JRnaR7d" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol": { + "keccak256": "0x69f54c02b7d81d505910ec198c11ed4c6a728418a868b906b4a0cf29946fda84", + "urls": [ + "bzz-raw://8e25e4bdb7ae1f21d23bfee996e22736fc0ab44cfabedac82a757b1edc5623b9", + "dweb:/ipfs/QmQdWQvB6JCP9ZMbzi8EvQ1PTETqkcTWrbcVurS7DKpa5n" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts/contracts/utils/cryptography/EIP712.sol": { + "keccak256": "0x10eb97d047f8d84fe263a02bb4a656ac6674f6679d74532cc37546289e073a9d", + "urls": [ + "bzz-raw://3e41287d40b0c46982f1083d40d32de2761f009c5c51627fe79a7feb0ab1cf5c", + "dweb:/ipfs/Qme7dbh6HX3ZvUJdbQAcVqXkmyXyfcLiUZRhhon3cU6K8p" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts/contracts/utils/cryptography/MessageHashUtils.sol": { + "keccak256": "0x4515543bc4c78561f6bea83ecfdfc3dead55bd59858287d682045b11de1ae575", + "urls": [ + "bzz-raw://60601f91440125727244fffd2ba84da7caafecaae0fd887c7ccfec678e02b61e", + "dweb:/ipfs/QmZnKPBtVDiQS9Dp8gZ4sa3ZeTrWVfqF7yuUd6Y8hwm1Rs" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts/contracts/utils/introspection/ERC165.sol": { + "keccak256": "0xddce8e17e3d3f9ed818b4f4c4478a8262aab8b11ed322f1bf5ed705bb4bd97fa", + "urls": [ + "bzz-raw://8084aa71a4cc7d2980972412a88fe4f114869faea3fefa5436431644eb5c0287", + "dweb:/ipfs/Qmbqfs5dRdPvHVKY8kTaeyc65NdqXRQwRK7h9s5UJEhD1p" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol": { + "keccak256": "0x79796192ec90263f21b464d5bc90b777a525971d3de8232be80d9c4f9fb353b8", + "urls": [ + "bzz-raw://f6fda447a62815e8064f47eff0dd1cf58d9207ad69b5d32280f8d7ed1d1e4621", + "dweb:/ipfs/QmfDRc7pxfaXB2Dh9np5Uf29Na3pQ7tafRS684wd3GLjVL" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts/contracts/utils/math/Math.sol": { + "keccak256": "0xa00be322d7db5786750ce0ac7e2f5b633ac30a5ed5fa1ced1e74acfc19acecea", + "urls": [ + "bzz-raw://6c84e822f87cbdc4082533b626667b6928715bb2b1e8e7eb96954cebb9e38c8d", + "dweb:/ipfs/QmZmy9dgxLTerBAQDuuHqbL6EpgRxddqgv5KmwpXYVbKz1" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts/contracts/utils/math/SafeCast.sol": { + "keccak256": "0x195533c86d0ef72bcc06456a4f66a9b941f38eb403739b00f21fd7c1abd1ae54", + "urls": [ + "bzz-raw://b1d578337048cad08c1c03041cca5978eff5428aa130c781b271ad9e5566e1f8", + "dweb:/ipfs/QmPFKL2r9CBsMwmUqqdcFPfHZB2qcs9g1HDrPxzWSxomvy" + ], + "license": "MIT" + }, + "lib/openzeppelin-contracts/contracts/utils/math/SignedMath.sol": { + "keccak256": "0xb1970fac7b64e6c09611e6691791e848d5e3fe410fa5899e7df2e0afd77a99e3", + "urls": [ + "bzz-raw://db5fbb3dddd8b7047465b62575d96231ba8a2774d37fb4737fbf23340fabbb03", + "dweb:/ipfs/QmVUSvooZKEdEdap619tcJjTLcAuH6QBdZqAzWwnAXZAWJ" + ], + "license": "MIT" + } + }, + "version": 1 + }, + "id": 0 +} + +export const CAT_FACTORY_ABI = CAT_FACTORY.abi; diff --git a/web/src/components/theme-provider.tsx b/web/src/hooks/ThemeProvider.tsx similarity index 85% rename from web/src/components/theme-provider.tsx rename to web/src/hooks/ThemeProvider.tsx index 5f919284..0947bf51 100644 --- a/web/src/components/theme-provider.tsx +++ b/web/src/hooks/ThemeProvider.tsx @@ -17,11 +17,7 @@ export function ThemeProvider({ children, ...props }: ThemeProviderProps) { } return ( - + {children} ); diff --git a/web/src/hooks/WalletConnectProvider.tsx b/web/src/hooks/WalletConnectProvider.tsx deleted file mode 100644 index 2c5848f7..00000000 --- a/web/src/hooks/WalletConnectProvider.tsx +++ /dev/null @@ -1,141 +0,0 @@ -"use client"; - -import { WalletContextProps } from "@/types/walletContext"; -import detectEthereumProvider from "@metamask/detect-provider"; -import React, { createContext, useState, useEffect } from "react"; -import CAT_FACTORY_ABI from "../contractsABI/CatFactoryABI.js"; -import { CATS_FACTORY_ADDRESS } from "../constants.js"; -import Web3 from "web3"; - -const WalletContext = createContext({ - address: "", - isLoading: false, - balance: "", - connect: () => { }, - disconnect: () => { }, - catsContractInstance: null, - catsContractFactoryInstance: null, -}); - -export function WalletConnectProvider({ - children, -}: React.PropsWithChildren) { - const [address, setAddress] = useState(""); - const [isLoading, setIsLoading] = useState(false); - const [balance, setBalance] = useState(""); - const [web3, setWeb3] = useState(null); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const [catsContractInstance] = useState(null); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const [catsContractFactoryInstance, setCatsContractFactoryInstance] = useState(null); - - const initContracts = async () => { - if (!web3) return; - const catsContractFactoryInstance = new web3.eth.Contract( - // eslint-disable-next-line @typescript-eslint/no-explicit-any - CAT_FACTORY_ABI as any, - CATS_FACTORY_ADDRESS - ); - setCatsContractFactoryInstance(catsContractFactoryInstance); - localStorage.setItem("contract", "catsContractFactoryInstance"); - }; - - useEffect(() => { - if (!web3) return; - initContracts(); - }, [isLoading]); - - useEffect(() => { - const init = async () => { - const provider = await detectEthereumProvider(); - if (provider) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const web3Instance = new Web3(provider as any); - setWeb3(web3Instance); - - // Try to load address from localStorage on page load - const savedAddress = localStorage.getItem("walletAddress"); - if (savedAddress) { - setAddress(savedAddress); - const savedBalance = localStorage.getItem("walletBalance"); - if (savedBalance) setBalance(savedBalance); - } - - // Listen for account changes - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (provider as any).on("accountsChanged", async (accounts: string[]) => { - if (accounts.length > 0) { - setAddress(accounts[0]); - const balance = await web3Instance.eth.getBalance(accounts[0]); - const balanceInEther = web3Instance.utils.fromWei(balance, "ether"); - setBalance(balanceInEther); - localStorage.setItem("walletAddress", accounts[0]); - localStorage.setItem("walletBalance", balanceInEther); - } else { - setAddress(""); - setBalance(""); - localStorage.removeItem("walletAddress"); - localStorage.removeItem("walletBalance"); - } - }); - } else { - console.error("Please install MetaMask!"); - } - }; - init(); - }, []); - - const connect = async () => { - if (!web3) return; - setIsLoading(true); - try { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const accounts = await (web3.currentProvider as any).request({ - method: "eth_requestAccounts", - }); - setAddress(accounts[0]); - const balance = await web3.eth.getBalance(accounts[0]); - const balanceInEther = web3.utils.fromWei(balance, "ether"); - setBalance(balanceInEther); - - // Save to localStorage - localStorage.setItem("walletAddress", accounts[0]); - localStorage.setItem("walletBalance", balanceInEther); - } catch (error) { - console.error("Error connecting to MetaMask:", error); - } finally { - setIsLoading(false); - } - }; - - const disconnect = () => { - setAddress(""); - setBalance(""); - localStorage.removeItem("walletAddress"); - localStorage.removeItem("walletBalance"); - }; - - return ( - - {children} - - ); -} - -export function useWallet() { - try { - return React.useContext(WalletContext); - } catch (e) { - throw new Error("useWallet must be used within a WalletConnectProvider"); - } -} diff --git a/web/src/hooks/WalletProvider.tsx b/web/src/hooks/WalletProvider.tsx new file mode 100644 index 00000000..93fe591a --- /dev/null +++ b/web/src/hooks/WalletProvider.tsx @@ -0,0 +1,31 @@ +"use client"; + +import React, { ReactNode } from "react"; +import { config } from "@/utils/config"; +import { RainbowKitProvider, darkTheme } from "@rainbow-me/rainbowkit"; +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; +import { WagmiProvider } from "wagmi"; +import { scrollSepolia } from "wagmi/chains"; + +// Create a client +const queryClient = new QueryClient(); + +export function WalletProvider({ children }: { children: ReactNode }) { + return ( + + + + {children} + + + + ); +} diff --git a/web/src/images/logo.png b/web/src/images/logo.png new file mode 100644 index 00000000..affadf5f Binary files /dev/null and b/web/src/images/logo.png differ diff --git a/web/src/types/address.ts b/web/src/types/address.ts deleted file mode 100644 index 1283c5a9..00000000 --- a/web/src/types/address.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface AddressProps { - address: string; -} \ No newline at end of file diff --git a/web/src/types/walletContext.ts b/web/src/types/walletContext.ts index ff1377fa..0c782d98 100644 --- a/web/src/types/walletContext.ts +++ b/web/src/types/walletContext.ts @@ -8,4 +8,4 @@ export interface WalletContextProps { catsContractInstance?: any; // eslint-disable-next-line @typescript-eslint/no-explicit-any catsContractFactoryInstance?: any; -} \ No newline at end of file +} diff --git a/web/src/utils/address.ts b/web/src/utils/address.ts new file mode 100644 index 00000000..c35416da --- /dev/null +++ b/web/src/utils/address.ts @@ -0,0 +1,6 @@ +export const ClowderVaultFactories = { + 534351: "0xff1be271440b76d3064556422f4458bed5bbb4b5", + 5115: "0xf899F1b8c710bC4Bc2462cE1B65265760921b2ca", +} as { + [key: number]: `0x${string}`; +}; diff --git a/web/src/utils/config.tsx b/web/src/utils/config.tsx new file mode 100644 index 00000000..c115b5a3 --- /dev/null +++ b/web/src/utils/config.tsx @@ -0,0 +1,29 @@ +import { + arbitrum, + base, + mainnet, + optimism, + polygon, + scrollSepolia, + sepolia, +} from "wagmi/chains"; +import { + getDefaultConfig, + RainbowKitProvider, + darkTheme, + Chain, +} from "@rainbow-me/rainbowkit"; +import * as chains from "wagmi/chains"; +import { citreaTestnet } from "@/components/CitreaTestnet"; + +// const AllChains: readonly [Chain, ...Chain[]] = [ +// ...(Object.values(chains) as Chain[]), +// // citreaTestnet, +// ] as unknown as readonly [Chain, ...Chain[]]; + +export const config = getDefaultConfig({ + appName: "clowder", + projectId: process.env.NEXT_PUBLIC_PROJECT_ID ?? "", + chains: [scrollSepolia, polygon, mainnet, citreaTestnet], + ssr: true, +});