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

@predictdotfun/sdk

v1.2.0

Published

A TypeScript SDK to help developers interface with the Predict's protocol.

Downloads

494

Readme

A TypeScript SDK to help developers interface with the Predict's protocol.

Install

This package has ethers v6 as a peer dependency.

yarn add @predictdotfun/sdk ethers
npm install @predictdotfun/sdk ethers

See the OrderBuilder class for more in-depth details on each function.

Set Approvals

Before trading, you need to set approvals for ERC-1155 (ConditionalTokens) and ERC-20 (USDB). This can be achieved by sending a transaction to the respective contracts (see the Contracts section) and approving both the CTF_EXCHANGE and the NEG_RISK_CTF_EXCHANGE or via the SDK utils.

Contracts: The current deployed contracts can be found either in the Constants.ts file or in the Deployed Contracts documentation.

The following example demonstrates how to set the necessary approvals using the SDK utils.

import { Wallet, MaxInt256 } from "ethers";
import { OrderBuilder, ChainId, Side } from "@predictdotfun/sdk";

// Create a wallet to sent the approvals transactions (must be the orders' `maker`)
const signer = new Wallet(process.env.WALLET_PRIVATE_KEY);

// The main function which initiates the OrderBuilder (only once per signer) and then provides it as dependency to other util functions
async function main() {
  // Create a new instance of the OrderBuilder class. Note: This should only be done once per signer
  const builder = await OrderBuilder.make(ChainId.BlastMainnet, signer);

  /**
   * NOTE: To use your predict account, export the Privy wallet from the account settings at https://predict.fun/account/settings
   *
   * You will need to deposit ETH on that address (the Privy wallet) to set approvals and cancel orders.
   *
   * Then initiate the `OrderBuilder` as such:
   *
   * const builder = await OrderBuilder.make(ChainId.BlastMainnet, privyWallet, { predictAccount: "PREDICT_ACCOUNT_ADDRESS" });
   *
   * Replacing `PREDICT_ACCOUNT_ADDRESS` with your Predict account address/deposit address.
   */

  // Call an helper function to set the approvals and provide the OrderBuilder instance.
  await setApprovals(builder);
}

async function setApprovals(builder: OrderBuilder) {
  // Set all the approval needed within the protocol
  const result = await builder.setApprovals();

  // Check if the approvals were set successfully
  if (!result.success) {
    throw new Error("Failed to set approvals.");
  }
}

How to use a Predict account

Here's an example of how to use a Predict account to create/cancel orders and set approvals.

  1. Initiate the Privy Wallet: The wallet is needed to sign orders. Can be found in the account settings.
  2. Ensure the Privy Wallet has funds: You will need to add some ETH to be able to set approvals and cancel orders, if needed.
  3. Initialize OrderBuilder: Instantiate the OrderBuilder class by calling OrderBuilder.make.
    • NOTE: Include the predictAccount address, which is also known as the deposit address.
  4. Set Approvals: Ensure the necessary approvals are set (refer to Set Approvals).
  5. Determine Order Amounts: Use getLimitOrderAmounts to calculate order amounts.
  6. Build Order: Use buildOrder to generate a LIMIT strategy order.
    • NOTE: Fetch the feeRateBps via the GET /markets endpoint on the REST API
    • NOTE: Set the signer and maker to the predictAccount address, NOT the signer/privy wallet address.
  7. Generate Typed Data: Call buildTypedData to generate typed data for the order.
  8. Sign Order: Obtain a SignedOrder object by calling signTypedDataOrder.
  9. Compute Order Hash: Compute the order hash using buildTypedDataHash.
import { Wallet } from "ethers";
import { OrderBuilder, ChainId, Side } from "@predictdotfun/sdk";

// Export and fund with ETH the Privy wallet from the account settings at https://predict.fun/account/settings
const privyWallet = new Wallet(process.env.PRIVY_WALLET_PRIVATE_KEY);

// The main function which initiates the OrderBuilder (only once per signer) and then provides it as dependency to other util functions
async function main() {
  /**
   * NOTE: Replace `PREDICT_ACCOUNT_ADDRESS` with your Predict account address/deposit address.
   */

  // Create a new instance of the OrderBuilder class. Note: This should only be done once per signer
  const builder = await OrderBuilder.make(ChainId.BlastMainnet, privyWallet, {
    predictAccount: "PREDICT_ACCOUNT_ADDRESS",
  });

  // Call an helper function to create the order and provide the OrderBuilder instance
  await createOrder(builder);
}

async function createOrder(builder: OrderBuilder) {
  // Step 1. Set approvals and define the order params as usual

  // Step 2. Create the order by using the Predict account address as both the `signer` and `maker`
  const order = builder.buildOrder("LIMIT", {
    maker: "PREDICT_ACCOUNT_ADDRESS",
    signer: "PREDICT_ACCOUNT_ADDRESS",
    side: Side.BUY, // Equivalent to 0
    tokenId: "OUTCOME_ON_CHAIN_ID", // This can be fetched via the API or on-chain
    makerAmount, // 0.4 USDB * 10 shares (in wei)
    takerAmount, // 10 shares (in wei)
    nonce: 0n,
    feeRateBps: 0, // Should be fetched via the `GET /markets` endpoint
  });

  // Step 3. Sign and submit the order as usual
}

Limit Orders

Here's an example of how to use the OrderBuilder to create and sign a LIMIT strategy buy order:

  1. Create Wallet: The wallet is needed to sign orders.
  2. Initialize OrderBuilder: Instantiate the OrderBuilder class by calling OrderBuilder.make.
  3. Set Approvals: Ensure the necessary approvals are set (refer to Set Approvals).
  4. Determine Order Amounts: Use getLimitOrderAmounts to calculate order amounts.
  5. Build Order: Use buildOrder to generate a LIMIT strategy order.
    • NOTE: Fetch the feeRateBps via the GET /markets endpoint on the REST API
  6. Generate Typed Data: Call buildTypedData to generate typed data for the order.
  7. Sign Order: Obtain a SignedOrder object by calling signTypedDataOrder.
  8. Compute Order Hash: Compute the order hash using buildTypedDataHash.
import { Wallet } from "ethers";
import { OrderBuilder, ChainId, Side } from "@predictdotfun/sdk";

// Create a wallet for signing orders
const signer = new Wallet(process.env.WALLET_PRIVATE_KEY);

// The main function which initiates the OrderBuilder (only once per signer) and then provides it as dependency to other util functions
async function main() {
  // Create a new instance of the OrderBuilder class. Note: This should only be done once per signer
  const builder = await OrderBuilder.make(ChainId.BlastMainnet, signer);

  /**
   * NOTE: To use your predict account, export the Privy wallet from the account settings at https://predict.fun/account/settings
   *
   * You will need to deposit ETH on that address (the Privy wallet) to set approvals and cancel orders.
   *
   * Then initiate the `OrderBuilder` as such:
   *
   * const builder = await OrderBuilder.make(ChainId.BlastMainnet, privyWallet, { predictAccount: "PREDICT_ACCOUNT_ADDRESS" });
   *
   * Replacing `PREDICT_ACCOUNT_ADDRESS` with your Predict account address/deposit address.
   */

  // Call an helper function to create the order and provide the OrderBuilder instance
  await createOrder(builder);
}

async function createOrder(builder: OrderBuilder) {
  /**
   * NOTE: You can also call `setApprovals` once per wallet.
   */

  // Set all the approval needed within the protocol (if needed)
  const result = await builder.setApprovals();

  // Check if the approvals were set successfully
  if (!result.success) {
    throw new Error("Failed to set approvals.");
  }

  // Simple helper function to calculate the amounts for a `LIMIT` order
  const { pricePerShare, makerAmount, takerAmount } = builder.getLimitOrderAmounts({
    side: Side.BUY,
    pricePerShareWei: 400000000000000000n, // 0.4 USDB (in wei)
    quantityWei: 10000000000000000000n, // 10 shares (in wei)
  });

  // TODO: If you are using your Predict account (deposit address) use that address, otherwise use the signer address
  const predictAccountOrSigner = "PREDICT_ACCOUNT_ADDRESS" || signer.address;

  // Build a limit order
  const order = builder.buildOrder("LIMIT", {
    maker: predictAccountOrSigner,
    signer: predictAccountOrSigner,
    side: Side.BUY, // Equivalent to 0
    tokenId: "OUTCOME_ON_CHAIN_ID", // This can be fetched via the API or on-chain
    makerAmount, // 0.4 USDB * 10 shares (in wei)
    takerAmount, // 10 shares (in wei)
    nonce: 0n,
    feeRateBps: 0, // Should be fetched via the `GET /markets` endpoint
  });

  // Build typed data for the order (isNegRisk can be fetched via the API)
  const typedData = builder.buildTypedData(order, { isNegRisk: true });

  // Sign the order by providing the typedData of the order
  const signedOrder = await builder.signTypedDataOrder(typedData);

  // Compute the order's hash
  const hash = builder.buildTypedDataHash(typedData);

  // Example structure required to create an order via Predict's API
  const createOrderBody = {
    data: {
      order: { ...signedOrder, hash },
      pricePerShare,
      strategy: "LIMIT",
    },
  };
}

Market Orders

Similarly to the above, here's the flow to create a MARKET sell order:

  1. Create Wallet: The wallet is needed to sign orders.
  2. Initialize OrderBuilder: Instantiate the OrderBuilder class by calling OrderBuilder.make.
  3. Set Approvals: Ensure the necessary approvals are set (refer to Set Approvals).
  4. Fetch Orderbook: Query the Predict API for the latest orderbook for the market.
  5. Determine Order Amounts: Use getMarketOrderAmounts to calculate order amounts.
  6. Build Order: Call buildOrder to generate a MARKET strategy order.
    • NOTE: Fetch the feeRateBps via the GET /markets endpoint on the REST API
  7. Generate Typed Data: Use buildTypedData to create typed data for the order.
  8. Sign Order: Obtain a SignedOrder object by calling signTypedDataOrder.
  9. Compute Order Hash: Compute the order hash using buildTypedDataHash.
import { Wallet } from "ethers";
import { OrderBuilder, ChainId, Side } from "@predictdotfun/sdk";

// Create a wallet for signing orders
const signer = new Wallet(process.env.WALLET_PRIVATE_KEY);

// The main function which initiates the OrderBuilder (only once per signer) and then provides it as dependency to other util functions
async function main() {
  // Create a new instance of the OrderBuilder class. Note: This should only be done once per signer
  const builder = await OrderBuilder.make(ChainId.BlastMainnet, signer);

  /**
   * NOTE: To use your predict account, export the Privy wallet from the account settings at https://predict.fun/account/settings
   *
   * You will need to deposit ETH on that address (the Privy wallet) to set approvals and cancel orders.
   *
   * Then initiate the `OrderBuilder` as such:
   *
   * const builder = await OrderBuilder.make(ChainId.BlastMainnet, privyWallet, { predictAccount: "PREDICT_ACCOUNT_ADDRESS" });
   *
   * Replacing `PREDICT_ACCOUNT_ADDRESS` with your Predict account address/deposit address.
   */

  // Call an helper function to create the order and provide the OrderBuilder instance
  await createOrder(builder);
}

async function createOrder(builder: OrderBuilder) {
  // Fetch the orderbook for the specific market via `GET orderbook/{marketId}`
  const book = {};

  /**
   * NOTE: You can also call `setApprovals` once per wallet.
   */

  // Set all the approval needed within the protocol (if needed)
  const result = await builder.setApprovals();

  // Check if the approvals were set successfully
  if (!result.success) {
    throw new Error("Failed to set approvals.");
  }

  // Helper function to calculate the amounts for a `MARKET` order
  const { pricePerShare, makerAmount, takerAmount } = builder.getMarketOrderAmounts(
    {
      side: Side.SELL,
      quantityWei: 10000000000000000000n, // 10 shares (in wei) e.g. parseEther("10")
    },
    book, // It's recommended to re-fetch the orderbook regularly to avoid issues
  );

  // TODO: If you are using your Predict account (deposit address) use that address, otherwise use the signer address.
  const predictAccountOrSigner = "PREDICT_ACCOUNT_ADDRESS" || signer.address;

  // Build a limit order
  const order = builder.buildOrder("MARKET", {
    maker: predictAccountOrSigner,
    signer: predictAccountOrSigner,
    side: Side.SELL, // Equivalent to 1
    tokenId: "OUTCOME_ON_CHAIN_ID", // This can be fetched via the API or on-chain
    makerAmount, // 10 shares (in wei)
    takerAmount, // 0.4 USDB * 10 shares (in wei)
    nonce: 0n,
    feeRateBps: 0, // Should be fetched via the `GET /markets` endpoint
  });

  // Build typed data for the order (isNegRisk can be fetched via the API)
  const typedData = builder.buildTypedData(order, { isNegRisk: false });

  // Sign the order by providing the typedData of the order
  const signedOrder = await builder.signTypedDataOrder(typedData);

  // Compute the order's hash
  const hash = builder.buildTypedDataHash(typedData);

  // Example structure required to create an order via Predict's API
  const createOrderBody = {
    data: {
      order: { ...signedOrder, hash },
      pricePerShare,
      strategy: "MARKET",
      slippageBps: "2000", // Only used for `MARKET` orders, in this example it's 0.2%
    },
  };
}

Redeem Positions

The OrderBuilder class provides methods to redeem your positions on the Predict protocol. Depending on the type of market you're interacting with, you can use either redeemPositions for standard markets or redeemNegRiskPositions for NegRisk markets.

  1. Create a Wallet: Initialize a wallet that will be used to sign the redemption transaction.
  2. Initialize OrderBuilder: Instantiate the OrderBuilder class by calling the static make method.
  3. Redeem Positions: Call the redeemPositions method with the appropriate conditionId and indexSet.

The conditionId and indexSet can be fetched from the GET /positions endpoint.

import { Wallet } from "ethers";
import { OrderBuilder, ChainId } from "@predictdotfun/sdk";

// Initialize the wallet with your private key
const signer = new Wallet(process.env.WALLET_PRIVATE_KEY);

// The main function initiates the OrderBuilder (only once per signer)
// Then provides it as dependency to other functions
async function main() {
  // Create a new instance of the OrderBuilder class. Note: This should only be done once per signer
  const builder = await OrderBuilder.make(ChainId.BlastMainnet, signer);

  await redeemPositions(builder);
  await redeemNegRiskPositions(builder);
}

async function redeemPositions(orderBuilder: OrderBuilder) {
  const conditionId = "CONDITION_ID_FROM_API"; // A hash string
  const indexSet = "INDEX_SET_FROM_API"; // 1 or 2 based on the position you want to redeem

  const result = await builder.redeemPositions(conditionId, indexSet);

  if (result.success) {
    console.log("Positions redeemed successfully:", result.receipt);
  } else {
    console.error("Failed to redeem positions:", result.cause);
  }
}

async function redeemNegRiskPositions(orderBuilder: OrderBuilder) {
  const conditionId = "CONDITION_ID_FROM_API"; // A hash string
  const indexSet = "INDEX_SET_FROM_API"; // 1 or 2 based on the position you want to redeem
  const amount = "POSITION_AMOUNT_FROM_API"; // The amount to redeem, usually the max

  const result = await builder.redeemNegRiskPositions(conditionId, indexSet, amount);

  if (result.success) {
    console.log("Positions redeemed successfully:", result.receipt);
  } else {
    console.error("Failed to redeem positions:", result.cause);
  }
}

Check USDB balance

The method balanceOf allows to easily check the current USDB balance of the connected signer.

import { Wallet } from "ethers";
import { OrderBuilder, ChainId } from "@predictdotfun/sdk";

// Initialize the wallet with your private key
const signer = new Wallet(process.env.WALLET_PRIVATE_KEY);

// The main function initiates the OrderBuilder (only once per signer)
// Then provides it as dependency to other functions
async function main() {
  // Create a new instance of the OrderBuilder class. Note: This should only be done once per signer
  const builder = await OrderBuilder.make(ChainId.BlastMainnet, signer);

  await checkBalance(builder);
}

async function checkBalance(orderBuilder: OrderBuilder) {
  // Fetch the current account/wallet balance in wei
  const balanceWei = await builder.balanceOf();

  // Example check
  if (balanceWei >= orderAmountWei) {
    console.log("Enough balance to create the order");
  } else {
    console.error("Not enough balance to create the order");
  }
}

Contracts

To facilitate interactions with Predict's contracts we expose the necessary instances of each contract, including ABIs and types.

import { OrderBuilder } from "@predictdotfun/sdk";
import { Wallet } from "ethers";

// Create a wallet to interact with on-chain contracts
const signer = new Wallet(process.env.WALLET_PRIVATE_KEY);

// The main function initiates the OrderBuilder (only once per signer)
// Then provides it as dependency to other functions
async function main() {
  // Create a new instance of the OrderBuilder class. Note: This should only be done once per signer
  const builder = await OrderBuilder.make(ChainId.BlastMainnet, signer);

  await callContracts(builder);
}

async function callContracts(orderBuilder: OrderBuilder) {
  // If the signer is not provided within `OrderBuilder.make` the contracts won't be initiated
  if (!orderBuilder.contracts) {
    throw new Error("The signer was not provided during the OrderBuilder init.");
  }

  // You can now call contract functions (the actual contract instance is within `contract`)
  // The `codec` property contains the ethers Interface, useful to encode and decode data
  const balance = await orderBuilder.contracts["USDB"].contract.balanceOf(signer.address);
}

Other utils

Some other useful utils, ABIs and types exposed by the SDK.

import {
  // Supported Chains
  ChainId,

  // Addresses
  AddressesByChainId,

  // Contract Interfaces
  BlastCTFExchange,
  BlastConditionalTokens,
  BlastNegRiskAdapter,
  BlastNegRiskCtfExchange,
  ERC20,

  // ABIs
  BlastCTFExchangeAbi,
  BlastNegRiskCtfExchangeAbi,
  BlastNegRiskAdapterAbi,
  BlastConditionalTokensAbi,
  ERC20Abi,

  // Order builder
  OrderBuilder,
} from "@predictdotfun/sdk";

Cancel Orders

Here's an example on how to cancel orders via the SDK

  1. Fetch Orders: Retrieve your open orders using GET /orders.
  2. Cancel Orders off chain: Call POST /orders/cancel with orderIds and cancel orders from the orderbook
  3. Group by isNegRisk: Separate orders based on the isNegRisk property.
  4. Cancel Orders: Call the specific cancel function based on the order(s) type (isNegRisk).
  5. Check Transaction Success: Check to confirm the transaction was successful.
import { Wallet } from "ethers";
import { OrderBuilder, ChainId, Side } from "@predictdotfun/sdk";

// Create a new JsonRpcProvider instance
const provider = new JsonRpcProvider(process.env.RPC_PROVIDER_URL);

// Create a wallet to send the cancel transactions on-chain
const signer = new Wallet(process.env.WALLET_PRIVATE_KEY).connect(provider);

// The main function which initiates the OrderBuilder (only once per signer) and then provides it as dependency to other util functions
async function main() {
  // Create a new instance of the OrderBuilder class. Note: This should only be done once per signer
  const builder = await OrderBuilder.make(ChainId.BlastMainnet, signer);

  /**
   * NOTE: To use your predict account, export the Privy wallet from the account settings at https://predict.fun/account/settings
   *
   * You will need to deposit ETH on that address (the Privy wallet) to set approvals and cancel orders.
   *
   * Then initiate the `OrderBuilder` as such:
   *
   * const builder = await OrderBuilder.make(ChainId.BlastMainnet, privyWallet, { predictAccount: "PREDICT_ACCOUNT_ADDRESS" });
   *
   * Replacing `PREDICT_ACCOUNT_ADDRESS` with your Predict account address/deposit address.
   */

  // Call an helper function to cancel orders and provide the OrderBuilder instance
  await createOrder(builder);
}

async function cancelOrders(builder: OrderBuilder) {
  // Fetch your open orders from the `GET /orders` endpoint
  const apiResponse = [
    // There are more fields, but for cancellations we only care about `order` and `isNegRisk`
    { order: {}, isNegRisk: true },
    { order: {}, isNegRisk: false },
    { order: {}, isNegRisk: false },
  ];

  // Determine which orders you want to cancel
  const ordersToCancel = [
    { order: {}, isNegRisk: true },
    { order: {}, isNegRisk: false },
  ];

  const regularOrders: Order[] = [];
  const negRiskOrders: Order[] = [];

  // Group the orders by `isNegRisk`
  for (const { order, isNegRisk } of ordersToCancel) {
    if (isNegRisk) {
      negRiskOrders.push(order);
    } else {
      regularOrders.push(order);
    }
  }

  // Call the respective cancel functions
  const regResult = await builder.cancelOrders(regularOrders);
  const negRiskResult = await builder.cancelNegRiskOrders(regularOrders);

  // Check for the transactions success
  const success = regResult.success && negRiskResult.success;
}

License

By contributing to this project, you agree that your contributions will be licensed under the project's MIT License.