npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@guildxyz/sdk

v2.6.9

Published

SDK for Guild.xyz Public API

Downloads

14,814

Readme

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.

Demo app

A demo app is available here, 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

To install our SDK, open your terminal and run:

npm i @guildxyz/sdk

Importing the package and creating a Guild client

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

import { ethers } from "ethers";

const ethersWallet = new ethers.Wallet(...);

const signerFunction = createSigner.fromEthersWallet(ethersWallet);

Creating a custom signer for usage with web3-react

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

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, 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

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
// 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

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

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: "<SERVER_ID>",
});

// Delete a reward from a guild
await guildRewardClient.delete(
  guildIdOrUrlName,
  guildPlatformId,
  signerFunction
);

Role client

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

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

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: "<DC_SERVER_ID>",
    },
    platformRoleId: "<DC_ROLE_ID>",
  },
  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: "<DC_ROLE_ID>",
  },
  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

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

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

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

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

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
);