React hooks and utilities that make writing an Agoric dapp as quick and painless as possible.
See Agoric/ui-kit#setup for setup instructions, as well as more pointers for using the chainStorageWatcher and walletConnection.
Getting set up is as easy as using the AgoricProvider. Under the hood, it uses cosmos-kit/react to connect to your wallet provider of choice.
import { AgoricProvider, ConnectWalletButton } from '@agoric/react-components';
import { wallets } from 'cosmos-kit';
import { ThemeProvider, useTheme } from '@interchain-ui/react';
import '@agoric/react-components/dist/style.css';
const localnet = {
testChain: {
chainId: 'agoriclocal',
chainName: 'agoric-local',
},
apis: {
rest: ['http://localhost:1317'],
rpc: ['http://localhost:26657'],
iconUrl: '/agoriclocal.svg', // Optional icon for Network Dropdown component
},
};
// Omit "testChain" to specify the apis for Agoric Mainnet.
const mainnet = {
apis: {
rest: ['https://main.api.agoric.net'],
rpc: ['https://main.rpc.agoric.net'],
},
};
const App = () => {
const { themeClass } = useTheme();
return (
<ThemeProvider>
<div className={themeClass}>
<AgoricProvider
wallets={wallets.extension}
agoricNetworkConfigs={[localnet, mainnet]}
/**
* If unspecified, connects to Agoric Mainnet by default.
* See "Network Dropdown" below to see how to switch between Agoric testnets.
*/
defaultChainName="agoric-local"
>
<ConnectWalletButton />
</AgoricProvider>
</div>
</ThemeProvider>
);
};
ConnectWalletButtonWhile the example above uses the premade ConnectWalletButton, the useAgoric
hook can also be used instead.
import { useAgoric } from '@agoric/react-components';
const MyCustomConnectButton = () => {
const agoric = useAgoric();
return <button onClick={agoric.connect}>Connect</button>;
};
The AmountInput provides a configurable component for handling different assets and denoms.
import { useState } from 'React';
import { AmountInput, useAgoric } from '@agoric/react-components';
const MyIstInput = () => {
const [value, setValue] = useState(0n);
const { purses } = useAgoric();
const istPurse = purses?.find(p => p.brandPetname === 'IST');
return (
<AmountInput
className="my-input-class"
value={value}
onChange={setValue}
decimalPlaces={istPurse?.displayInfo.decimalPlaces ?? 0}
disabled={!istPurse}
/>
);
};
If you wish to use your own custom component, the useAmountInput hook can be utilized
which helps convert between input strings and denominated BigInt values.
To let a user choose their own API endpoints, separate from those provided in agoricNetworkConfigs, the NodeSelectorModal can be provided:
import { useState } from 'react';
import { NodeSelectorModal } from '@agoric/react-components';
const NodeSelector = () => {
const [isOpen, setIsOpen] = useState(false);
return (
<>
<button onClick={() => setIsOpen(true)}>
Configure Endpoints
</button>
<NodeSelectorModal isOpen={isOpen} onClose={() => setIsOpen(false)}>
</>
);
};
The modal will persist the user's chosen API endpoints in local storage, and override whichever endpoints are specified for the current network in agoricNetworkConfigs.
To support multiple Agoric test networks, the NetworkDropdown component can
be used. It will let the user choose between the networks provided in agoricNetworkConfigs, save their choice to local storage, and override defaultChainName when choosing the network to connect to. It uses the interchain-ui
ChangeChainCombobox
and requires the ThemeProvider (see Integrating above):
import { NetworkDropdown } from '@agoric/react-components';
const MyNetworkSelect = () => {
return (
<NetworkDropdown
appearance="minimal"
size="sm"
label="Switch Agoric Networks"
/>
);
};
The OnboardIstModal component provides an easy way for users to acquire IST through interchain swaps, bridging, IBC, and more with Leap Elements.
If you wish to use Leap Elements in another context, the useElementsWalletClient hook provides a wallet client to plug into your own instance of Elements.
import { useElementsWalletClient, useAgoric } from '@agoric/react-components';
import { LiquidityModal } from '@leapwallet/elements';
import '@leapwallet/elements/styles.css';
const MyElementModal = () => {
const { address } = useAgoric();
const elementsWalletClient = useElementsWalletClient();
return (
<LiquidityModal
walletClientConfig={{
userAddress: address,
walletClient: elementsWalletClient,
connectWallet: (chainId?: string) => {
return elementsWalletClient.enable(chainId ?? []);
}
}}
...
>
...
)
}
All Agoric-related state is accessible through the useAgoric hook. See AgoricContext for the full interface.
For more details on making offers and reading chain data with AgoricWalletConnection and ChainStorageWatcher, see Agoric/ui-kit.
For users that don't have a smart wallet provisioned, the makeOffer function from the
useAgoric hook will automatically show a modal informing them of the provisioning fee, showing their IST balance, and providing
a Leap Elements button to acquire IST if necessary before signing the transaction. The text content of this modal is configurable through the provisionNoticeContent prop in AgoricProvider. If this modal
is not desired, the makeOfferWithoutModal function can be used instead, and the provision status and fee can be accessed with isSmartWalletProvisioned and smartWalletProvisionFee from the useAgoric hook.
ChainProviderIf you need to configure ChainProvider more, or have an existing cosmos-kit dapp that you want to add Agoric functionality to, the AgoricProviderLite component can be used directly inside your own ChainProvider. Under the hood, AgoricProvider provides a default ChainProvider implementation and wraps AgoricProviderLite.