🔹Use in Browser
Use in browser
For Web3 applications, users usually operate their data through the Ethereum wallet in the browser. However, unlike Node.js, the browser cannot access the user's private key, so signature authorization can only be performed through the Ethereum wallet, such as MetaMask, WalletConnect. After completing this step, the subsequent usage is consistent with Node.js.
Create project
We can create a react-ts template project based on Vite. If it is integrated with an existing project, you can skip this step
pnpm create vite glacier-quickstart --template react-ts
The complete sample https://github.com/Glacier-Labs/glacier-quickstart
More complex project can refer to https://github.com/Glacier-Labs/js-glacier/tree/main/apps/playground
Install SDK
Enter glacier-quickstart directory and execute the command
pnpm add @glacier-network/client
Connect wallet
Next, we create a React Hook to connect to the browser wallet MetaMask. The code is as follows:
import { useState, useEffect, useCallback } from 'react';
import { MetaMaskInpageProvider } from '@metamask/providers';
export default function useMetaMask() {
const [account, setAccount] = useState<string>();
const [provider, setProvider] = useState<MetaMaskInpageProvider>();
const connect = useCallback(async () => {
const accounts = await window.ethereum.request<string[]>({
method: 'eth_requestAccounts',
params: [],
});
if (accounts) setAccount(accounts[0]);
}, []);
const eagerConnect = useCallback(async () => {
if (!window.ethereum) return;
const accounts = await window.ethereum?.request<string[]>({
method: 'eth_accounts',
params: [],
});
if (accounts) setAccount(accounts[0]);
setProvider(window.ethereum);
}, []);
useEffect(() => {
window.ethereum?.on('accountsChanged', (args) => {
const accounts = args as string[];
if (accounts) setAccount(accounts[0]);
setProvider(window.ethereum);
});
}, []);
return {
account,
provider,
connect,
eagerConnect,
};
}
Connect Glacier
To operate the data of Glacier, you need to sign in through the Ethereum wallet. So now we create another Hook to encapsulate the relevant operations, which includs:
- Instantiate
GlacierClient - Create
Namespace - Enum
Namespace
The creation of Namespace will call the wallet for signature confirmation.
import { useState, useCallback, useMemo, useEffect } from 'react';
import { GlacierClient, NamespaceRecord } from '@glacier-network/client';
import useMetaMask from './useMetaMask';
export default function useGlacier() {
const [spaces, setSpaces] = useState<NamespaceRecord[]>([]);
const { provider, account, connect, eagerConnect } = useMetaMask();
const client = useMemo(() => {
return new GlacierClient('https://p0.onebitdev.com/glacier-gateway', {
provider,
});
}, [provider]);
const listNamespace = useCallback(async () => {
if (!account) return setSpaces([]);
const result = await client.namespaces(account);
setSpaces(result);
}, [client, account]);
const createNamespace = useCallback(
async (name: string) => {
const result = await client.createNamespace(name);
return result;
},
[client]
);
useEffect(() => {
listNamespace();
}, [listNamespace]);
return {
client,
spaces,
account,
connect,
eagerConnect,
listNamespace,
createNamespace,
};
}
Pay attention to this part from the above codes:
const client = useMemo(() => {
return new GlacierClient('https://p0.onebitdev.com/glacier-gateway', {
provider,
});
}, [provider]);
When instantiating GlacierClient, provider, that is, window.ethereum is passed in instead of privateKey, which is also the main difference between Browser and Node.js. If you use other popular wallet connection libraries in your project, such as web3-react, you can refer to the following usage:
import { useWeb3React } from '@web3-react/core';
import { Web3Provider } from '@ethersproject/providers';
export default function App() {
const { account, library } = useWeb3React<Web3Provider>();
const client = new GlacierClient('https://p0.onebitdev.com/glacier-gateway', {
provider: library?.provider,
});
}
Write component
Finally, let's write a React component to connect the previous Hook. The code is as follows:
import { useEffect, useState } from 'react';
import { Button, Form, ListGroup } from 'react-bootstrap';
import useGlacier from './useGlacier';
export default function App() {
const [name, setName] = useState('');
const [loading, setLoading] = useState(false);
const {
account,
spaces,
connect,
eagerConnect,
createNamespace,
listNamespace,
} = useGlacier();
useEffect(() => {
eagerConnect();
}, [eagerConnect]);
const onCreate = async () => {
try {
setLoading(true);
const result = await createNamespace(name);
await listNamespace();
alert(result.insertedId);
} catch (error) {
console.trace(error);
} finally {
setLoading(false);
}
};
if (!window.ethereum) {
return (
<div className="container my-3">
<a href="https://metamask.io/" target="_blank" rel="noreferrer">
<Button>Install MetaMask</Button>
</a>
</div>
);
}
if (!account) {
return (
<div className="container my-3">
<Button variant="success" onClick={connect}>
Connect Wallet
</Button>
</div>
);
}
return (
<div className="container">
<div className="my-3">Connected: {account}</div>
<Form>
<Form.Group className="mb-3">
<Form.Control
type="text"
placeholder="Namespace"
value={name}
onChange={(e) => {
setName(e.target.value.trim());
}}
/>
</Form.Group>
<Button
variant="primary"
disabled={loading || !name}
onClick={onCreate}
>
Create Namespace
</Button>
</Form>
<div className="my-3">My Namespaces:</div>
<ListGroup>
{spaces.map((item) => (
<ListGroup.Item key={item.namespace}>{item.namespace}</ListGroup.Item>
))}
</ListGroup>
</div>
);
}
Well done! Check the following result: