Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update readme #89

Merged
merged 6 commits into from
Mar 6, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -131,3 +131,6 @@ dist

# Other build output
compiled

# Vscode Settings
.vscode/
82 changes: 64 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# UI Kit

Components and tools for building graphical UIs for Agoric dapps

## Setup
Expand All @@ -7,6 +8,11 @@ These packages require SES ([learn more](https://github.com/endojs/endo/tree/mas
See this [example](https://github.com/Agoric/dapp-inter/blob/main/src/main.tsx#L1) for enabling SES in your application.
Setup may vary by environment.

## React Apps

See [packages/react-components](https://github.com/Agoric/ui-kit) for convenient hooks and utilities that make setting up
a React app as quick and painless as possible.

## Reading Contract Data (vstorage)

`makeAgoricChainStorageWatcher` can be used to subscribe to updates to vstorage.
Expand All @@ -17,18 +23,18 @@ See https://github.com/p2p-org/p2p-agoric-vstorage-viewer to explore vstorage mo
```ts
import {
makeAgoricChainStorageWatcher,
AgoricChainStoragePathKind as Kind
AgoricChainStoragePathKind as Kind,
} from '@agoric/rpc';

const watcher = makeAgoricChainStorageWatcher(rpc, chainName);
const watcher = makeAgoricChainStorageWatcher(restApi, chainName);

// Watch vstorage children at a given node.
const stopWatching = watcher.watchLatest<string[]>(
[Kind.Children, 'published.vaultFactory.managers'],
managerIds => {
console.log('Got vault manager IDs:', managerIds);
}
)
},
);

// Stop watching.
stopWatching();
Expand All @@ -38,8 +44,8 @@ watcher.watchLatest<Brands>(
[Kind.Data, 'published.agoricNames.brand'],
brands => {
console.log('Do something with the brands');
}
)
},
);
```

## Connecting to User's Account (Keplr)
Expand All @@ -49,35 +55,78 @@ import { subscribeLatest } from '@agoric/notifier';
import { makeAgoricChainStorageWatcher } from '@agoric/rpc';
import { makeAgoricWalletConnection } from '@agoric/web-components';

const watcher = makeAgoricChainStorageWatcher(rpc, chainName);
const connection = await makeAgoricWalletConnection(watcher);
const {pursesNotifier, publicSubscribersNotifier} = chainConnection;
const watcher = makeAgoricChainStorageWatcher(apiAddr, chainName);
const connection = await makeAgoricWalletConnection(watcher, rpcAddr);
const { pursesNotifier, publicSubscribersNotifier } = chainConnection;

for await (const purses of subscribeLatest(pursesNotifier)) {
console.log('Got purses:', purses);
}
```

## Using a Custom Signer

While `makeAgoricChainStorageWatcher` connects to Keplr by default, clients
that use a custom signer can provide their own:

```ts
import {
agoricRegistryTypes,
agoricConverters,
makeAgoricWalletConnection,
} from '@agoric/web-components';
import { Registry } from '@cosmjs/proto-signing';
import {
AminoTypes,
defaultRegistryTypes,
createBankAminoConverters,
createAuthzAminoConverters,
} from '@cosmjs/stargate';

...

const signingStargateClient = await SigningStargateClient.connectWithSigner(
rpcEndpoint, // RPC endpoint to use
customAminoSigner, // E.g. window.getOfflineSignerOnlyAmino(chainId)
{
aminoTypes: new AminoTypes({
...agoricConverters,
...createBankAminoConverters(),
...createAuthzAminoConverters(),
}),
registry: new Registry([...defaultRegistryTypes, ...agoricRegistryTypes]),
},
);
const agoricWalletConnection = await makeAgoricWalletConnection(
chainStorageWatcher,
rpcEndpoint,
(e: unknown) => {
console.error('wallet connection error', e);
},
{ address: myAddress, client: signingStargateClient },
);
```

## Executing Offers

```ts
import { makeAgoricChainStorageWatcher } from '@agoric/rpc';
import { makeAgoricWalletConnection } from '@agoric/web-components';

const watcher = makeAgoricChainStorageWatcher(rpc, chainName);
const connection = await makeAgoricWalletConnection(watcher);
const watcher = makeAgoricChainStorageWatcher(apiAddr, chainName);
const connection = await makeAgoricWalletConnection(watcher, rpcAddr);

const amountToGive = {brand: someBrand, value: 123n};
const amountToWant = {brand: someOtherBrand, value: 456n};
const amountToGive = { brand: someBrand, value: 123n };
const amountToWant = { brand: someOtherBrand, value: 456n };

connection.makeOffer(
{
source: 'agoricContract',
instancePath: ['SimpleSwapExampleInstance'],
callPipe: [
['getSwapManagerForBrand', [amountToGive.brand]],
['makeSwapOffer']
]
['makeSwapOffer'],
],
},
{
give: { In: amountToGive },
Expand All @@ -101,6 +150,3 @@ connection.makeOffer(
},
);
```



101 changes: 101 additions & 0 deletions configure-vscode.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#!/bin/sh
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question

Just curious, why is this file needed here if it's already in Agoric/agoric-sdk?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The .vscode/settings.json file that this script produces only applies when it's at the root of the currently opened workspace, so running it from agoric-sdk wouldn't apply the settings to this repo unless they were opened together in the same workspace.

We could point to the agoric-sdk repo and ask people to copy that .vscode/settings.json into this workspace when working with this repo, but it's more convenient to just have it here and allows us to tweak things specific to this repo.

Copy link
Contributor Author

@samsiegart samsiegart Mar 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


# Configures the .vscode directory (which is .gitignored so that everyone can tailor it)

die() {
echo "$*" >&2
exit 1
}

# Run at the top level of the repository
cd "$(git rev-parse --show-toplevel)" ||
die "Could not cd to top-level directory"

mkdir -p .vscode ||
die "Could not create .vscode/"

# General settings

cat >.vscode/settings.json.new <<\EOF ||
{
// Automatically format with Prettier on save
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",

"typescript.preferences.importModuleSpecifierEnding": "js",
"typescript.tsdk": "node_modules/typescript/lib",

// ESLint config
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"eslint.rules.customizations": [
// Leave this to Prettier itself
{ "rule": "prettier/*", "severity": "off" },
// Error in CI but a common state while coding in IDE
{ "rule": "no-unused-vars", "severity": "warn" },
// Imports are auto-fixed on save
{ "rule": "import/newline-after-import", "severity": "off" },
{ "rule": "import/order", "severity": "off" },
],
"eslint.useESLintClass": true,
"eslint.packageManager": "yarn"
}
EOF
die "Could not write settings.json"

cat > .vscode/launch.json.new <<\EOF ||
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "pwa-node",
"request": "launch",
"name": "Debug AVA file",
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/ava",
"runtimeArgs": [
"${file}"
],
"outputCapture": "std",
"skipFiles": [
"<node_internals>/**"
],
},
{
"type": "pwa-node",
"request": "launch",
"name": "Debug AVA matches",
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/ava",
"runtimeArgs": [
"${file}",
"-m",
"${selectedText}"
],
"outputCapture": "std",
"skipFiles": [
"<node_internals>/**"
],
}
]
}
EOF
die "Could not write launch.json"

for file in .vscode/launch.json .vscode/settings.json; do
printf "\nComparing %s\n" $file
if test -f $file; then
if git diff --no-index --quiet --exit-code $file $file.new; then
echo "Your existing configuration matches the recommendations."
rm $file.new
else
printf "The file %s.new has these changes:\n\n" $file
git --no-pager diff --no-index $file $file.new
printf "\n\nTo overwrite yours:\n\n mv %s.new %s\n\n" $file $file
fi
else
mv $file.new $file
fi
done
85 changes: 84 additions & 1 deletion packages/react-components/README.md
Original file line number Diff line number Diff line change
@@ -1 +1,84 @@
# Agoric React Components
# Agoric React Components

React hooks and utilities that make writing an Agoric dapp as quick and painless as possible.

## Prequisites

See [Agoric/ui-kit#setup](https://github.com/Agoric/ui-kit?tab=readme-ov-file#setup) for setup instructions, as well as more pointers for using the `chainStorageWatcher` and `walletConnection`.

## Integrating

Getting set up is as easy as using the `AgoricProvider`. Under the hood, it uses [`cosmos-kit/react`](https://docs.cosmology.zone/cosmos-kit) to connect to your wallet provider of choice.

```tsx
import { AgoricProvider, ConnectWalletButton } from '@agoric/react-components';
import { wallets } from 'cosmos-kit';
import '@agoric/react-components/dist/style.css';

const App = () => {
return (
<AgoricProvider
wallets={wallets.extension}
defaultNetworkConfig={{
// testChain is optional, defaulting to Agoric mainnet otherwise.
testChain: {
chainId: 'agoriclocal',
chainName: 'agoric-local',
},
apis: {
rest: ['http://localhost:1317'],
rpc: ['http://localhost:26657'],
},
}}
>
<ConnectWalletButton />
</AgoricProvider>
);
};
```

## Connecting without `ConnectWalletButton`

```tsx
import { useAgoric } from '@agoric/react-components';

const MyCustomConnectButton = () => {
const agoric = useAgoric();

return <button onClick={agoric.connect}>Connect</button>;
};
```

## Node Selector

To let a user choose their own API endpoints, separate from those provided in `defaultNetworkConfig`, the `NodeSelectorModal` can be provided:

```tsx
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 in `defaultNetworkConfig`.

## Agoric Context

All Agoric-related state is accessible through the `useAgoric` hook. See [`AgoricContext`](https://github.com/Agoric/ui-kit/blob/585b47d158a983643659a2cfccd76f772933db7e/packages/react-components/src/lib/context/AgoricContext.ts#L28-L39) for the full interface.

For more details on making offers and reading chain data with `AgoricWalletConnection` and `ChainStorageWatcher`, see [Agoric/ui-kit](https://github.com/Agoric/ui-kit).

## Using a Custom `ChainProvider`

If you need to configure `ChainProvider` more, or have an existing `cosmos-kit` dapp that you want to add Agoric functionality to, the [`AgoricProviderLite`](https://github.com/Agoric/ui-kit/blob/585b47d158a983643659a2cfccd76f772933db7e/packages/react-components/src/lib/context/AgoricProviderLite.tsx) component can be used directly inside your own `ChainProvider`. [Under the hood](https://github.com/Agoric/ui-kit/blob/585b47d158a983643659a2cfccd76f772933db7e/packages/react-components/src/lib/context/AgoricProvider.tsx#L27-L61), `AgoricProvider` provides a default `ChainProvider` implementation and wraps `AgoricProviderLite`.
Loading