2️Quick Start

Glacier SDK supports Node.js and Browser simultaneously, which means that developers can not only create Dateset and Collection on the server side through the private key controlled by themselves but also support users to control all their data through the Ethereum wallet in the browser. This chapter will introduce how to get started with the Glacier SDK quickly

Using Glacier SDK in Node.js is very easy and only requires a few steps:

Install the SDK

Execute commands in your Node.js project

pnpm add @glacier-network/client

Import SDK

To use SDK, you only need to import the GlacierClient class in @glacier-network/client and then create an instance, for example:

src/index.ts

import { GlacierClient } from '@glacier-network/client';

const client = new GlacierClient('https://p0.onebitdev.com/glacier-gateway');

The first parameter of the instantiation is the address of the Glacier node to be connected.

After the instantiation is completed, the read-only query of the Glacier data can be executed through the client. If you want to write or modify the data, you need to specify your own Ethereum wallet private key when creating the instance:

src/index.ts

import { GlacierClient } from '@glacier-network/client';

const privateKey = `0xf7311f908890f7aeaf46d0185cf4234ae926cf896b2c50590d6735a37c827045`;
const client = new GlacierClient('https://p0.onebitdev.com/glacier-gateway', {
  privateKey,
});

Now you can read and write data, a complete sample project as below:

https://github.com/Glacier-Labs/js-glacier/tree/main/apps/sdk-example

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:

src/useMetaMask.ts

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.

src/useGlacier.ts

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:

src/App.tsx

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!

Last updated