diff --git a/examples/injective/components/SendMsg.tsx b/examples/injective/components/SendMsg.tsx index 7c83df9e2..a23a85f39 100644 --- a/examples/injective/components/SendMsg.tsx +++ b/examples/injective/components/SendMsg.tsx @@ -1,48 +1,80 @@ -import { Box, Text, Button, Link } from "@interchain-ui/react"; -import { useEffect, useState } from "react"; -import { useChain, useOfflineSigner } from "@interchain-kit/react"; -import { defaultAssetList, defaultChain, defaultChainName, defaultRpcEndpoint } from "@/config"; -import useBalance from "@/hooks/useBalance"; -import { InjSigningClient } from "@interchainjs/injective/signing-client"; -import { toEncoders, toConverters } from '@interchainjs/cosmos/utils'; -import { MsgSend } from 'interchain-react/cosmos/bank/v1beta1/tx'; +import { Box, Text, Button, Link } from '@interchain-ui/react'; +import { InjSigningClient } from '@interchainjs/injective/signing-client'; +import { useEffect, useState } from 'react'; +import { useChain, useOfflineSigner } from '@interchain-kit/react'; +import { + defaultAssetList, + defaultChain, + defaultChainName, + defaultRpcEndpoint, +} from '@/config'; +import useBalance from '@/hooks/useBalance'; +import { useSend } from 'interchain-react/cosmos/bank/v1beta1/tx.rpc.func'; +import { defaultContext } from '@tanstack/react-query'; export default function SendMsg() { const coin = defaultAssetList?.assets[0]; - const denom = coin!.base! + + const denom = coin!.base!; + const COIN_DISPLAY_EXPONENT = coin!.denomUnits.find( (unit) => unit.denom === coin!.display )?.exponent as number; - const chain = defaultChain - const txPage = chain?.explorers?.[0].txPage - const { address, isLoading, wallet } = useChain(defaultChainName); + const chain = defaultChain; + const txPage = chain?.explorers?.[0].txPage; - const { offlineSigner } = useOfflineSigner(defaultChainName, wallet.info!.name) + const { address, isLoading, wallet } = useChain(defaultChainName); + const { offlineSigner } = useOfflineSigner( + defaultChainName, + wallet.info!.name + ); - const [sending, setSending] = useState(false); - const [txHash, setTxHash] = useState(null); - const [error, setError] = useState(null); - const [signingClient, setSigningClient] = useState(null); + const [signingClient, setSigningClient] = useState( + null + ); useEffect(() => { if (!offlineSigner) return; (async () => { - console.log('offlineSigner', offlineSigner) - setSigningClient(await InjSigningClient.connectWithSigner(defaultRpcEndpoint, offlineSigner)) - })() - }, [offlineSigner]) + console.log('offlineSigner', offlineSigner); + setSigningClient( + await InjSigningClient.connectWithSigner( + defaultRpcEndpoint, + offlineSigner + ) + ); + })(); + }, [offlineSigner]); - useEffect(() => { - signingClient?.addEncoders(toEncoders(MsgSend)); - signingClient?.addConverters(toConverters(MsgSend)); - }, [signingClient]) + const [sending, setSending] = useState(false); + const [txHash, setTxHash] = useState(null); + const [error, setError] = useState(null); - const { - balance, refetchBalance, isFetchingBalance - } = useBalance({ + const { mutate: send, isSuccess: isSendSuccess } = useSend({ + clientResolver: signingClient ?? undefined, + options: { + context: defaultContext, + onSuccess: (data) => { + console.log('signAndBroadcast', data); + if (data.code === 0) { + setTxHash((data as any).hash); + } else { + setError(data.rawLog || JSON.stringify(data || {})); + } + setSending(false); + }, + onError: (error) => { + console.error('signAndBroadcast', error); + setError(error.message); + setSending(false); + }, + }, + }); + + const { balance } = useBalance({ address, - }) + }); const handleSend = async () => { if (sending || isLoading) return; @@ -52,66 +84,66 @@ export default function SendMsg() { setSending(true); const fee = { - amount: [{ - denom, - amount: '2500', - }], - gas: "1000000", + amount: [ + { + denom, + amount: '2500', + }, + ], + gas: '1000000', }; - const msgs = [{ - typeUrl: MsgSend.typeUrl, - value: { + send({ + signerAddress: address, + message: { fromAddress: address, toAddress: address, - amount: [{ denom, amount: '1' }] - } - }] - - try { - const data = await signingClient!.signAndBroadcast( - address, msgs, fee, 'using interchainjs' - ) as any - console.log('onSuccess', data) - if (data.code === 0) { - setTimeout(() => { - refetchBalance() - setTxHash(data.hash); - setSending(false); - }, 4000) - } else { - setError(data.rawLog || JSON.stringify(data || {})); - setSending(false); - } - } catch (error: any) { - console.log('onError', error) - setError(error?.message || 'Unknown error'); - setSending(false); - } - } + amount: [ + { + denom, + amount: '1', + }, + ], + }, + fee, + memo: 'Send from interchain-react', + }); + }; return ( - - Balance: {isFetchingBalance ? '--' : (balance?.toFixed(COIN_DISPLAY_EXPONENT))} {coin?.symbol} + + + Balance:{' '} + {balance === null ? '--' : balance?.toFixed(COIN_DISPLAY_EXPONENT)}{' '} + {coin?.symbol} + + > + {isLoading ? 'Initializing...' : 'Send Token'} + - {txHash && - Details: - - {txPage?.replace('${txHash}', txHash)!} - - } - {error && - Error: - {error} - } + {txHash && ( + + Details: + + {txPage?.replace('${txHash}', txHash)!} + + + )} + {error && ( + + + Error: + + {error} + + )} ); -} \ No newline at end of file +} diff --git a/examples/injective/package.json b/examples/injective/package.json index a5fc3bbdc..124106969 100644 --- a/examples/injective/package.json +++ b/examples/injective/package.json @@ -41,9 +41,9 @@ "bignumber.js": "9.1.1", "chain-registry": "^1.69.32", "decimal.js": "^10.4.3", - "injective-react": "^1.6.3", - "interchain-react": "1.6.3", - "interchainjs": "1.6.3", + "injective-react": "^1.6.4", + "interchain-react": "1.6.4", + "interchainjs": "1.6.4", "mobx": "^6.13.5", "next": "^13", "react": "18.2.0", diff --git a/examples/injective/yarn.lock b/examples/injective/yarn.lock index 8e481e53f..13b929825 100644 --- a/examples/injective/yarn.lock +++ b/examples/injective/yarn.lock @@ -3063,9 +3063,9 @@ __metadata: eslint: "npm:8.28.0" eslint-config-next: "npm:13.0.5" generate-lockfile: "npm:0.0.12" - injective-react: "npm:^1.6.3" - interchain-react: "npm:1.6.3" - interchainjs: "npm:1.6.3" + injective-react: "npm:^1.6.4" + interchain-react: "npm:1.6.4" + interchainjs: "npm:1.6.4" mobx: "npm:^6.13.5" next: "npm:^13" react: "npm:18.2.0" @@ -9990,9 +9990,9 @@ __metadata: languageName: node linkType: hard -"injective-react@npm:^1.6.3": - version: 1.6.3 - resolution: "injective-react@npm:1.6.3" +"injective-react@npm:^1.6.4": + version: 1.6.4 + resolution: "injective-react@npm:1.6.4" dependencies: "@interchainjs/cosmos": "npm:1.6.3" "@interchainjs/cosmos-types": "npm:1.6.3" @@ -10002,7 +10002,7 @@ __metadata: decimal.js: "npm:^10.4.3" peerDependencies: "@tanstack/react-query": 4.29.1 - checksum: 10c0/e46f1cbf4622b03c572472ec9c3a8c1e65a41f090e216869bcce429e432dde26bdb0a0382c5d7c14781e2da42f9d55371313ecd8a5a78a64e985fb8fef37a7aa + checksum: 10c0/73ede404cd05856314c28ab297a50ca66a7918cd5d36ba92085dcde0bb40e8f52f45105c035b665da618e71d1dd094194bad754b888d45a3eece2b2c4b2906b1 languageName: node linkType: hard @@ -10075,9 +10075,9 @@ __metadata: languageName: node linkType: hard -"interchain-react@npm:1.6.3": - version: 1.6.3 - resolution: "interchain-react@npm:1.6.3" +"interchain-react@npm:1.6.4": + version: 1.6.4 + resolution: "interchain-react@npm:1.6.4" dependencies: "@interchainjs/cosmos": "npm:1.6.3" "@interchainjs/cosmos-types": "npm:1.6.3" @@ -10087,7 +10087,7 @@ __metadata: decimal.js: "npm:^10.4.3" peerDependencies: "@tanstack/react-query": 4.29.1 - checksum: 10c0/4a437e4a40a746159f313c22c767650e396958f30dd246bb214443ab56275a73eb5ab341b3a139081bfeb2ea730cf64bd9e2d55629b41f24a2c3180f4aff83ba + checksum: 10c0/3b166295b38e7ff6a5b9905524be162f67a84989f57d48ab68247a718f123e2fcf148d2bc9292ad5cc410d737153ca68fc3e9e0941677f0b2b8a431451e17412 languageName: node linkType: hard @@ -10107,6 +10107,22 @@ __metadata: languageName: node linkType: hard +"interchainjs@npm:1.6.4": + version: 1.6.4 + resolution: "interchainjs@npm:1.6.4" + dependencies: + "@interchainjs/cosmos": "npm:1.6.3" + "@interchainjs/cosmos-types": "npm:1.6.3" + "@interchainjs/types": "npm:1.6.3" + "@interchainjs/utils": "npm:1.6.3" + "@noble/hashes": "npm:^1.3.1" + decimal.js: "npm:^10.4.3" + peerDependencies: + "@tanstack/react-query": 4.29.1 + checksum: 10c0/aca1d8f21c9b3768d0694d67cc8c3434d986f99b9926ca2d63bb6661f2380d4d54255b2fea752e3944123731fd931c989d809e5ca979811d000fcc1964d7ce0a + languageName: node + linkType: hard + "internal-slot@npm:^1.0.7": version: 1.0.7 resolution: "internal-slot@npm:1.0.7" diff --git a/examples/interchainjs-demo/.gitignore b/examples/interchainjs-demo/.gitignore new file mode 100644 index 000000000..ae45b5ee5 --- /dev/null +++ b/examples/interchainjs-demo/.gitignore @@ -0,0 +1,39 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# local env files +.env*.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts + +*.next/* +*.yarn/* \ No newline at end of file diff --git a/examples/interchainjs-demo/CHANGELOG.md b/examples/interchainjs-demo/CHANGELOG.md new file mode 100644 index 000000000..e69de29bb diff --git a/examples/interchainjs-demo/README.md b/examples/interchainjs-demo/README.md new file mode 100644 index 000000000..c8b801a98 --- /dev/null +++ b/examples/interchainjs-demo/README.md @@ -0,0 +1,86 @@ +## Getting Started + +First, install the packages and run the development server: + +```bash +yarn && yarn dev +``` + +Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. + +You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file. + +## Learn More + +### Chain Registry + +The npm package for the Official Cosmos chain registry. Get chain and token data for you application. + +* https://github.com/cosmology-tech/chain-registry + +### Cosmology Videos + +Checkout more videos for how to use various frontend tooling in the Cosmos! + +* https://cosmology.zone/learn + +### Interchain Kit + +A wallet connector for the Cosmos ⚛️ + +* https://github.com/cosmology-tech/interchain-kit + +### Telescope + +A "babel for the Cosmos", Telescope is a TypeScript Transpiler for Cosmos Protobufs. Telescope is used to generate libraries for Cosmos blockchains. Simply point to your protobuffer files and create developer-friendly Typescript libraries for teams to build on your blockchain. + +* https://github.com/cosmology-tech/telescope + +🎥 [Checkout the Telescope video playlist](https://www.youtube.com/watch?v=n82MsLe82mk&list=PL-lMkVv7GZwyQaK6bp6kMdOS5mzosxytC) to learn how to use `telescope`! + +### CosmWasm TS Codegen + +The quickest and easiest way to interact with CosmWasm Contracts. @cosmwasm/ts-codegen converts your CosmWasm smart contracts into dev-friendly TypeScript classes so you can focus on shipping code. + +* https://github.com/CosmWasm/ts-codegen + +🎥 [Checkout the CosmWasm/ts-codegen video playlist](https://www.youtube.com/watch?v=D_A5V2PfNLA&list=PL-lMkVv7GZwz1KO3jANwr5W4MoziruXwK) to learn how to use `ts-codegen`! + + +## Learn More about Next.js + +To learn more about Next.js, take a look at the following resources: + +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. +- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. + +You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! + +## Deploy on Vercel + +The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. + +Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. + +## Related + +Checkout these related projects: + +* [@cosmology/telescope](https://github.com/cosmology-tech/telescope) Your Frontend Companion for Building with TypeScript with Cosmos SDK Modules. +* [@cosmwasm/ts-codegen](https://github.com/CosmWasm/ts-codegen) Convert your CosmWasm smart contracts into dev-friendly TypeScript classes. +* [chain-registry](https://github.com/cosmology-tech/chain-registry) Everything from token symbols, logos, and IBC denominations for all assets you want to support in your application. +* [interchain-kit](https://github.com/cosmology-tech/interchain-kit) Experience the convenience of connecting with a variety of web3 wallets through a single, streamlined interface. +* [create-cosmos-app](https://github.com/cosmology-tech/create-cosmos-app) Set up a modern Cosmos app by running one command. +* [interchain-ui](https://github.com/cosmology-tech/interchain-ui) The Interchain Design System, empowering developers with a flexible, easy-to-use UI kit. +* [starship](https://github.com/cosmology-tech/starship) Unified Testing and Development for the Interchain. + +## Credits + +🛠 Built by Cosmology — if you like our tools, please consider delegating to [our validator ⚛️](https://cosmology.zone/validator) + + +## Disclaimer + +AS DESCRIBED IN THE LICENSES, THE SOFTWARE IS PROVIDED “AS IS”, AT YOUR OWN RISK, AND WITHOUT WARRANTIES OF ANY KIND. + +No developer or entity involved in creating this software will be liable for any claims or damages whatsoever associated with your use, inability to use, or your interaction with other users of the code, including any direct, indirect, incidental, special, exemplary, punitive or consequential damages, or loss of profits, cryptocurrencies, tokens, or anything else of value. diff --git a/examples/interchainjs-demo/components/Main.tsx b/examples/interchainjs-demo/components/Main.tsx new file mode 100644 index 000000000..56803830a --- /dev/null +++ b/examples/interchainjs-demo/components/Main.tsx @@ -0,0 +1,23 @@ +import { Box, Text } from '@interchain-ui/react'; +import { useChain } from "@interchain-kit/react"; +import { defaultChainName } from "@/config"; +import { WalletState } from '@interchain-kit/core' +import dynamic from 'next/dynamic'; + +const SendMsg = dynamic(() => import('./SendMsg'), { + ssr: false, +}); + +export function Main() { + const { status } = useChain(defaultChainName); + + return ( + status === WalletState.Connected ? + : + + + Please connect to your wallet. + + + ); +} \ No newline at end of file diff --git a/examples/interchainjs-demo/components/SendMsg.tsx b/examples/interchainjs-demo/components/SendMsg.tsx new file mode 100644 index 000000000..9fc22c151 --- /dev/null +++ b/examples/interchainjs-demo/components/SendMsg.tsx @@ -0,0 +1,122 @@ +import { Box, Text, Button, Link } from '@interchain-ui/react'; +import { useState } from 'react'; +import { useChain } from '@interchain-kit/react'; +import { defaultAssetList, defaultChain, defaultChainName } from '@/config'; +import useBalance from '@/hooks/useBalance'; +import { useSend } from 'interchain-react/cosmos/bank/v1beta1/tx.rpc.func'; +import { defaultContext } from '@tanstack/react-query'; + +export default function SendMsg() { + const coin = defaultAssetList?.assets[0]; + + const denom = coin!.base!; + + const COIN_DISPLAY_EXPONENT = coin!.denomUnits.find( + (unit) => unit.denom === coin!.display + )?.exponent as number; + + const chain = defaultChain; + const txPage = chain?.explorers?.[0].txPage; + + const { address, signingClient, isLoading } = useChain(defaultChainName); + + const [sending, setSending] = useState(false); + const [txHash, setTxHash] = useState(null); + const [error, setError] = useState(null); + + const { mutate: send, isSuccess: isSendSuccess } = useSend({ + clientResolver: signingClient, + options: { + context: defaultContext, + onSuccess: (data) => { + console.log('signAndBroadcast', data); + if (data.code === 0) { + setTxHash((data as any).hash); + } else { + setError(data.rawLog || JSON.stringify(data || {})); + } + setSending(false); + }, + onError: (error) => { + console.error('signAndBroadcast', error); + setError(error.message); + setSending(false); + }, + }, + }); + + const { balance } = useBalance({ + address, + }); + + const handleSend = async () => { + if (sending || isLoading) return; + + setError(null); + setTxHash(null); + setSending(true); + + const fee = { + amount: [ + { + denom, + amount: '2500', + }, + ], + gas: '1000000', + }; + + send({ + signerAddress: address, + message: { + fromAddress: address, + toAddress: address, + amount: [ + { + denom, + amount: '1', + }, + ], + }, + fee, + memo: 'Send from interchain-react', + }); + }; + + return ( + + + + Balance:{' '} + {balance === null ? '--' : balance?.toFixed(COIN_DISPLAY_EXPONENT)}{' '} + {coin?.symbol} + + + + + + {txHash && ( + + Details: + + {txPage?.replace('${txHash}', txHash)!} + + + )} + {error && ( + + + Error: + + {error} + + )} + + ); +} diff --git a/examples/interchainjs-demo/components/common/Footer.tsx b/examples/interchainjs-demo/components/common/Footer.tsx new file mode 100644 index 000000000..abdb60da5 --- /dev/null +++ b/examples/interchainjs-demo/components/common/Footer.tsx @@ -0,0 +1,141 @@ +import { Box, Link, Text, Icon, Stack, Divider, useColorModeValue } from '@interchain-ui/react'; +import { dependencies, products, Project } from '@/config'; + +function Product({ name, desc, link }: Project) { + return ( + + + + {name} → + + + {desc} + + + + ); +} + +function Dependency({ name, desc, link }: Project) { + return ( + + + + + + + + + {name} + + + {desc} + + + + + ); +} + +export function Footer() { + return ( + <> + + {products.map((product) => ( + + ))} + + + {dependencies.map((dependency) => ( + + ))} + + + + + + Built with + + Cosmology + + + + ); +} \ No newline at end of file diff --git a/examples/interchainjs-demo/components/common/Header.tsx b/examples/interchainjs-demo/components/common/Header.tsx new file mode 100644 index 000000000..b036a25e1 --- /dev/null +++ b/examples/interchainjs-demo/components/common/Header.tsx @@ -0,0 +1,72 @@ +import { Link, Box, Button, Icon, Text, useTheme, useColorModeValue } from '@interchain-ui/react'; +import { dependencies } from '@/config'; + +const stacks = ['Interchain Kit', 'Next.js']; + +const dependency = dependencies[0]; + +export function Header() { + const { theme, setTheme } = useTheme(); + + const toggleColorMode = () => { + setTheme(theme === 'light' ? 'dark' : 'light'); + }; + + return ( + <> + + + + + + + Interchain + + + + Welcome to  + + + {stacks.join(' + ')} + {' + '} + + + {dependency.name} + + + + + + ); +} \ No newline at end of file diff --git a/examples/interchainjs-demo/components/common/Layout.tsx b/examples/interchainjs-demo/components/common/Layout.tsx new file mode 100644 index 000000000..af6777c01 --- /dev/null +++ b/examples/interchainjs-demo/components/common/Layout.tsx @@ -0,0 +1,20 @@ +import Head from 'next/head'; +import { Toaster, Container } from '@interchain-ui/react'; +import { Header } from './Header'; +import { Footer } from './Footer'; + +export function Layout({ children }: { children: React.ReactNode }) { + return ( + + + Interchain-Kit Demo + + + +
+ {children} + +