## Summary
The Guild SDK library is a Typescript library for interacting with the Guild API. This document explains how to authenticate, manage your Guilds easily and automate token-gated access in any application with this SDK.
Guild.xyz is the membership layer protocol for web3 communities, making community management easy and interoperable between platforms.
## Migration Guide to V2
⚠️ `1.x.x versions` of the SDK are **_deprecated_**, these versions won't work after **_2024-01-31_**. Please migrate to the latest version. You can find the migration guide [HERE](https://github.com/guildxyz/guild-sdk/blob/main/v2-migration-guide.md#guild-sdk-v2-migration-guide).
## Demo app
A demo app is available [here](https://github.com/guildxyz/guild-sdk/tree/main/examples/next-js), it shows how to:
- Connect wallet (with wagmi)
- Sign a message
- Get user profile with signature
- Fetch data (with SWR)
- Guild roles
- User memberships
- Leaderboard
## Contents
- [Installation](#installation)
- [Importing the package and creating a Guild client](#importing-the-package-and-creating-a-guild-client)
- [SignerFunctions and Authentication](#signerfunctions-and-authentication)
- [ethers.js](#creating-a-signer-from-an-ethers-wallet)
- [web3-react](#creating-a-custom-signer-for-usage-with-web3-react)
- [wagmi](#creating-a-custom-signer-for-usage-with-wagmi)
- [EIP-1271](#support-for-eip-1271-smart-contract-wallets)
- [Clients](#clients)
- [Guild client](#guild-client)
- [Points](#points)
- [Guild admin client](#guild-admin-client)
- [Guild reward client](#guild-reward-client)
- [Role client](#role-client)
- [Requirement client](#requirement-client)
- [Role reward client](#role-reward-client)
- [User client](#user-client)
- [User address client](#user-address-client)
- [User platform client](#user-platform-client)
- [Modular / multi-platform architecture](#modular--multi-platform-architecture)
- [Examples](#examples)
- [Example flow from Create Guild to Join](#example-flow-from-create-guild-to-join)
- [Multiple telegram groups guild](#multiple-telegram-groups-guild)
### Installation
To install our SDK, open your terminal and run:
```
npm i @guildxyz/sdk
```
### Importing the package and creating a Guild client
```typescript
import { createGuildClient, createSigner } from "@guildxyz/sdk";
// The only parameter is the name of your project
const guildClient = createGuildClient("My project");
```
### SignerFunctions and Authentication
#### `Creating a signer from an ethers wallet`
```ts
import { ethers } from "ethers";
const ethersWallet = new ethers.Wallet(...);
const signerFunction = createSigner.fromEthersWallet(ethersWallet);
```
#### `Creating a custom signer for usage with web3-react`
```ts
import { useWeb3React } from "@web3-react/core";
const { account: walletAddress, library } = useWeb3React();
const signerFunction = createSigner.custom(
(message) => library.getSigner(account).signMessage(signableMessage),
address
);
```
#### `Creating a custom signer for usage with wagmi`
```ts
import { useAccount, useSignMessage } from "wagmi";
const { signMessageAsync } = useSignMessage();
const { address } = useAccount();
const signerFunction = createSigner.custom(
(message) => signMessageAsync({ message }),
address
);
```
#### `Support for EIP-1271 smart contract wallets`
For signatures produced by EIP-1272 wallets, pass `{ chainIdOfSmartContractWallet: chainId }` as the third parameter of `createSigner.custom`, where `chainId` is the chain where the wallet operates. The Guild backend will try to call `isValidSignature` on the specified chain.
We have an example app under [`examples`](https://github.com/guildxyz/guild-sdk/tree/main/examples), which covers this parameter
### Clients
We have multiple clients for different entities. These clients are created from the `guildClient` that we created above.
#### `Guild client`
```ts
const { guild: client } = guildClient;
// Get Guild by its numeric ID
const guild = await client.get(guildId);
// Get Guild by its urlName (slug)
const guild = await client.get(urlName);
// Get multiple guilds by their IDs
const guilds = await client.getMany([guildId1, guildId2]);
// Search guilds with pagination
const guilds = await client.search({ limit: 10, offset: 0, search: "our" });
// Get the members of a guild
const members = await client.getMembers(
guildId,
signerFunction // Optional, if a valid signer is provided, the result will contain private data
);
// Join into a guild
const joinResult = await client.join(guildId, signerFunction);
// Check access to a guild, signerFuncion is required
await client.accessCheck(guildId, signerFunction);
// Create a new guild, check the possible creation parameters according to the typing
await client.create(
{
// In this example we are creating a guild with one FREE role
name: "My Guild",
urlName: "my-guild",
roles: [{ name: "My Role", requirements: [{ type: "FREE" }] }],
},
signerFunction
);
// Update an existing guild, check the possible update parameters according to the typing
await client.update(guildId, { description: "Edited" }, signerFunction);
// Delete a guild
await client.delete(guildId, signerFunction);
```
##### `Points`
```ts
// For a given role, create a new point system, and assign some points as reward
const created = await guild.role.reward.create(
guildId,
roleId, // This role will have the 5 points reward
{
guildPlatform: {
platformGuildId: "my-points", // Some unique name for your point system
platformName: "POINTS",
platformGuildData: { name: "coins" }, // Assign a custom name for the points
},
platformRoleData: { score: 5 }, // Members will get this many points
},
signerFunction
);
// Use an existing point system for a role
const created = await guild.role.reward.create(
guildId,
roleId, // This role will have the 10 points reward
{
guildPlatformId, // The ID of the existing guildPlatform (reward) object
platformRoleData: { score: 10 },
},
signerFunction
);
// Get leaderboard for a specific point guild reward
const { leaderboard, aroundUser } = await guild.getLeaderboard(
guildId,
guildPlatformId,
signerFunction // Optional. If provided, the response will include an "aroundUser" field, which contains leaderboard items from around the user's position, otherwise it will be undefined
);
// Get user's rank in a specific reward
const response = await user.getRankInGuild(userId, guildId, guildPlatformId); // Returns the leaderboard position of a user for the given reward
// Get all the points of a user across all relevant rewards
const response = await user.getPoints(userId, signerFunction);
```
#### `Guild admin client`
```ts
const {
guild: { admin: adminClient },
} = guildClient;
// Get all admins of a guild
const admins = await adminClient.getAll(guildIdOrUrlName);
// Get a specific admin of a guild
const admin = await adminClient.get(guildIdOrUrlName, userIdOfAdmin);
```
#### `Guild reward client`
```ts
const {
guild: { reward: guildRewardClient },
} = guildClient;
// Get a guild reward (like a Discord server)
const guildReward = await guildRewardClient.get(
guildIdOrUrlName,
guildPlatformId,
signerFunction // Optional, if a valid signer is provided, the result will contain private data
);
// Get all rewards of a guild
const guildRewards = await guildRewardClient.getAll(
guildIdOrUrlName,
signerFunction // Optional, if a valid signer is provided, the result will contain private data
);
// Add a new reward to a guild
const createdGuildReward = await guildRewardClient.create(guildIdOrUrlName, {
platformName: "DISCORD", // In this example we are adding a Discord server
platformGuildId: "",
});
// Delete a reward from a guild
await guildRewardClient.delete(
guildIdOrUrlName,
guildPlatformId,
signerFunction
);
```
#### `Role client`
```ts
const {
guild: { role: roleClient },
} = guildClient;
// Get a role
await roleClient.get(
guildIdOrUrlName,
roleId,
signerFunction // Optional, if a valid signer is provided, the result will contain private data
);
// Get all roles of a guild
await roleClient.getAll(
guildIdOrUrlName,
signerFunction // Optional, if a valid signer is provided, the result will contain private data
);
// Create a new role. Refer to the typing for other possible input parameters, like description, logic, or visibility
const createdRole = await roleClient.create(
guildIdOrUrlName,
{
name: "My new role",
requirements: [{ type: "FREE" }],
},
signerFunction
);
// Update an existing role
const updatedRole = await roleClient.update(
guildIdOrUrlName,
roleId,
{ description: "Edited" },
signerFunction
);
// Delete a role
await roleClient.delete(guildIdOrUrlName, roleId, signerFunction);
```
#### `Requirement client`
```ts
const {
guild: {
role: { requirement: requirementClient },
},
} = guildClient;
// Get a requirement
const requirement = await requirementClient.get(
guildIdOrUrlName,
roleId,
requirementId,
signerFunction // Optional, if a valid signer is provided, the result will contain private data
);
// Get all requirements of a role
const requirements = await requirementClient.getAll(
guildIdOrUrlName,
roleId,
signerFunction // Optional, if a valid signer is provided, the result will contain private data
);
// Create a new requirement
const createdRequirement = await requirementClient.create(
guildIdOrUrlName,
roleId,
{ type: "FREE" },
signerFunction
);
// Update an existing requirement (for example addresses in an ALLOWLIST requirement)
const updatedRequirement = await requirementClient.update(
guildIdOrUrlName,
roleId,
requirementId,
{ data: { addresses: ["0x..."] } }, // Lowercased addresses
signerFunction
);
// Delete a requirement
await requirementClient.delete(
guildIdOrUrlName,
roleId,
requirementId,
signerFunction
);
```
#### `Role reward client`
```ts
const {
guild: {
role: { reward: rewardClient },
},
} = guildClient;
// Get a role reward
const reward = rewardClient.get(
guildIdOrUrlName,
roleId,
rolePlatformId,
signerFunction // Optional, if a valid signer is provided, the result will contain private data
);
// Get all rewards of a role
const roleReward = rewardClient.getAll(
guildIdOrUrlName,
roleId,
signerFunction // Optional, if a valid signer is provided, the result will contain private data
);
// Create a role reward (for example a Discord role) with a guild reward (Discord server)
const createdReward = rewardClient.create(
guildIdOrUrlName,
roleId,
{
guildPlatform: {
// Here we are also creating a guild reward (the Discord server)
platformName: "DISCORD",
platformGuildId: "",
},
platformRoleId: "",
},
signerFunction
);
// Or create a role reward using an existing guild reward
const createdReward = rewardClient.create(
guildIdOrUrlName,
roleId,
{
guildPlatformId, // Here we are passing the id of an existing guild role (in this case a Discord server)
platformRoleId: "",
},
signerFunction
);
// Update an existing role reward
const updatedRoleReward = rewardClient.update(
guildIdOrUrlName,
roleId,
rolePlatformId,
{ visibility: "HIDDEN" }, // In this example we update a reward's visibility to HIDDEN
signerFunction
);
// Delete a role reward
rewardClient.delete(guildIdOrUrlName, roleId, rolePlatformId, signerFunction);
```
#### `User client`
```ts
const { user: userClient } = guildClient;
// Get a user by numeric ID, or an address
const user = await userClient.get(userIdOrAddress);
// Get current memberships of a user
const userMemberships = await userClient.getMemberships(
userIdOrAddress,
signerFunction // Optional, if a valid signer is provided, the result will contain private data
);
// Get a user's profile
const profile = await userClient.getProfile(
userIdOrAddress,
signerFunction // Optional, if a valid signer is provided, the result will contain private data
);
// Delete a user
await userClient.delete(userIdOrAddress, signerFunction);
```
#### `User address client`
```ts
const {
user: { address: userAddressClient },
} = guildClient;
// Get a user address
const userAddress = await userAddressClient.get(
userIdOrAddress, // Used for identifying the guild user
address, // The userAddress with this address will be returned
signerFunction
);
// Get all addresses of a user
const userAddresses = await userAddressClient.getAll(
userIdOrAddress,
signerFunction
);
// Create (connect / link) a new user address
const linkedAddress = await userAddressClient.create(
userIdOrAddress,
signerFunctionOfAddressToLink, // Should be a SignerFunction that is derived from the wallet that is being linked to the user. Can be obtained as described above
signerFunction
);
// Update a user address
const updatedUserAddress = await userAddressClient.update(
userIdOrAddress,
addressToUpdate,
{ isPrimary: true }, // In this example we update an address to be primary
signerFunction
);
// Delete (disconnect / unlink) a user address
await userAddressClient.delete(
userIdOrAddress,
addressToUpdate,
signerFunction
);
```
#### `User platform client`
```ts
const {
user: { platform: userPlatformClient },
} = guildClient;
// Get a user platform connection
const userPlatform = await userPlatformClient.get(
userIdOrAddress,
platformId,
signerFunction
);
// Get all platform connections of a user
const userPlatforms = await userPlatformClient.getAll(
userIdOrAddress,
signerFunction
);
// Delete (disconnect / unlink) a platform connection
await userPlatformClient.delete(userIdOrAddress, platformId, signerFunction);
```
### Modular / multi-platform architecture
Guild.xyz no longer limits its platform gating functionalities to a single gateable Discord server or Telegram group. In the new multi-platform architecture you can gate more platforms in a single guild/role.
The `guildPlatform` entity refers to a platform gated by the guild. It contains information about the gate platform, e.g.: a Discord server's id (`platformGuildId` which is a uniqu identifier of this platform) and optionally some additional data like the `inviteChannel` in the `platformRoleData` property in this case.
The `rolePlatform` entity connects a `guildPlatform` to a role indicating that this role gives access to that platform. It can also contain some additional information about the platform (`platformRoleId` and `platformRoleData`), in Discord's case it's the Discord-role's id.
Note that for example in Telegram's case `platformRoleId` is not required; only `platformGuild` (which refers to a telegram group's id) needs to be provided in `guildPlatform`.
### Examples
#### `Example flow from Create Guild to Join`
```ts
import { createGuildClient, createSigner } from "@guildxyz/sdk";
import { Wallet } from "ethers";
import { randomBytes } from "crypto";
// Creating a guild client
const guildClient = createGuildClient("sdk-readme-example");
// Creating a random wallet for the example
const wallet = new Wallet(randomBytes(32).toString("hex"));
// Creating a signer function
const signerFunction = createSigner.fromEthersWallet(wallet);
// Creating a Guild
await guildClient.guild.create(
{
name: "My New Guild",
urlName: "my-new-guild-123", // Optinal
description: "Cool stuff", // Optional
admins: ["0x916b1aBC3C38852B338a22B08aF19DEe14113627"], // Optional
showMembers: true, // Optional
hideFromExplorer: false, // Optional
theme: [{ color: "#000000" }], // Optional
guildPlatforms: [
// Optional (declaring the gated platforms)
{
platformName: "DISCORD",
platformGuildId: "717317894983225012",
platformGuildData: { inviteChannel: "832195274127999019" },
},
],
roles: [
{
name: "My First Role",
logic: "AND",
requirements: [
{
type: "ALLOWLIST",
data: {
addresses: [
"0xedd9C1954c77beDD8A2a524981e1ea08C7E484Be",
"0x1b64230Ad5092A4ABeecE1a50Dc7e9e0F0280304",
],
},
},
],
rolePlatforms: [
// Optional (connecting gated platforms to the role)
{
guildPlatformIndex: 0,
platformRoleId: "947846353822178118",
},
],
},
{
name: "My Second Role",
logic: "OR",
requirements: [
{
type: "ERC20",
chain: "ETHEREUM",
address: "0xf76d80200226ac250665139b9e435617e4ba55f9",
data: {
amount: 1,
},
},
{
type: "ERC721",
chain: "ETHEREUM",
address: "0x734AA2dac868218D2A5F9757f16f6f881265441C",
data: {
amount: 1,
},
},
],
rolePlatforms: [
// Optional (connecting gated platforms to the role)
{
guildPlatformIndex: 0,
platformRoleId: "283446353822178118",
},
],
},
],
},
signerFunction
);
// Joining to a Guild if any role is accessible by the given address
await guildClient.guild.join(myGuild.id, signerFunction);
```
#### `Multiple telegram groups guild`
```typescript
const myGuild = await guildClient.guild.create(
{
name: "My Telegram Guild",
guildPlatforms: [
{
platformName: "TELEGRAM", // Telegram group 0
platformGuildId: "-1001190870894",
},
{
platformName: "TELEGRAM", // Telegram group 1
platformGuildId: "-1003847238493",
},
{
platformName: "TELEGRAM", // Telegram group 2
platformGuildId: "-1008347384212",
},
],
roles: [
{
name: "My First Role",
logic: "AND",
requirements: [
{
type: "ALLOWLIST",
data: {
addresses: [
"0xedd9C1954c77beDD8A2a524981e1ea08C7E484Be",
"0x1b64230Ad5092A4ABeecE1a50Dc7e9e0F0280304",
],
},
},
],
rolePlatforms: [
{
guildPlatformIndex: 0, // Telegram group 0
},
{
guildPlatformIndex: 2, // Telegram group 2
},
],
},
{
name: "My Second Role",
logic: "OR",
requirements: [
{
type: "ERC20",
chain: "ETHEREUM",
address: "0xf76d80200226ac250665139b9e435617e4ba55f9",
data: {
amount: 1,
},
},
],
rolePlatforms: [
{
guildPlatformIndex: 1, // Telegram group 1
},
],
},
],
},
signerFunction
);
```