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:
Execute commands in your Node.js project
Copy pnpm add @glacier-network/client
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
Copy 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
Copy 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
.
We can create a react-ts
template project based on Vite
. If it is integrated with an existing project, you can skip this step
Copy 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
Enter glacier-quickstart
directory and execute the command
Copy pnpm add @glacier-network/client
Next, we create a React Hook
to connect to the browser wallet MetaMask
. The code is as follows:
src/useMetaMask.ts
Copy 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 ,
};
}
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
The creation of Namespace
will call the wallet for signature confirmation.
src/useGlacier.ts
Copy 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👇
Copy 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:
Copy 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 ,
});
}
Finally, let's write a React component to connect the previous Hook. The code is as follows:
src/App.tsx
Copy 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!