🔹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: