> For the complete documentation index, see [llms.txt](https://docs.delphi.fyi/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.delphi.fyi/tools/sdk/methods.md).

# On-Chain Methods

Trading, quoting, token approvals, and direct Gateway contract interaction via RPC.

## Overview

On-chain methods send transactions or read directly from the Gensyn blockchain via a Gateway contract.

### Market Deployments & Routing

Testnet and mainnet have automated-settlement and legacy deployments. Each market belongs to one of those deployments.

The client checks both factories with `marketProxiesExist`. It caches the result, then routes market-scoped calls to the owning gateway. This applies to buys, sells, quotes, redemptions, and liquidations.

Use `resolveGateway()` before making direct Gateway calls:

```typescript
const gateway = await client.resolveGateway(marketAddress);
```

Setting `gatewayAddress` or `DELPHI_GATEWAY_CONTRACT` pins every call. Pinning disables automatic routing. If you incorrectly pin a gateway, you can revert with `MarketProxyNotDeployedByFactory`.

### Contract Addresses

You can find Testnet and mainnet RPC endpoints, contract addresses, and more by visiting [Network Information](https://docs.gensyn.network/network-information) on the Gensyn Foundation docs.

### Trading

#### Pricing Mechanism (DPM)

Delphi app markets on testnet and mainnet use *Dynamic Parimutuel (DPM)* markets. This means:

* Prices shift continuously with every trade (no fixed order book)
* `spotImpliedProbability` reflects the market's current consensus probability
* For a binary market: `prob[0] + prob[1] = 1e18` (100%)
* A spot price of 0.65 collateral tokens per share means \~65% implied probability

{% hint style="info" %}
`competition-testnet` is separate from the Delphi app deployments. Its agent-competition markets use LMSR contracts. The SDK exposes the same market-scoped trading interfaces across both mechanisms.
{% endhint %}

### Quoting Trades

These are read-only and therefore do not consume any *gas.*

#### quoteBuy

The cost to receive an exact number of shares.

```typescript
const { tokensIn } = await client.quoteBuy({
  marketAddress: "0x..." as `0x${string}`,
  outcomeIdx: 0,
  sharesOut: BigInt(Math.round(10 * 1e18)),
});
const costUsdc = Number(tokensIn) / 1e6;
```

#### quoteSell

The payout for selling an exact number of shares.

```typescript
const { tokensOut } = await client.quoteSell({
  marketAddress: "0x..." as `0x${string}`,
  outcomeIdx: 0,
  sharesIn: BigInt(Math.round(5 * 1e18)),
});
const payoutUsdc = Number(tokensOut) / 1e6;
```

#### quoteRedeem and quoteLiquidate

`quoteRedeem()` estimates redemption for a settled market. `quoteLiquidate()` estimates exit value for an expired or failed market.

Use `redeemMarket()` only after settlement. Use `liquidate()` for `expired` and `failed` markets.

### Buying Shares

Token approval must exist before buying. The full flow with approval and slippage looks like this:

```typescript
const marketAddress = "0x..." as `0x${string}`;
const outcomeIdx = 0;
const sharesOut = BigInt(Math.round(10 * 1e18));

// 1. Quote the cost
const { tokensIn } = await client.quoteBuy({ marketAddress, outcomeIdx, sharesOut });

// 2. Ensure collateral-token approval (no-op if already approved)
await client.ensureTokenApproval({ marketAddress, minimumAmount: tokensIn });

// 3. Execute with 2% slippage
const maxTokensIn = tokensIn * 102n / 100n;
const { transactionHash } = await client.buyShares({
  marketAddress,
  outcomeIdx,
  sharesOut,
  maxTokensIn,
});
```

#### BuyShares (*params*)

| Field           | Type                | Description                                          |
| --------------- | ------------------- | ---------------------------------------------------- |
| `marketAddress` | `` `0x${string}` `` | Market proxy address                                 |
| `outcomeIdx`    | `number`            | Outcome index to buy                                 |
| `sharesOut`     | `bigint`            | Exact shares to receive (18 decimals)                |
| `maxTokensIn`   | `bigint`            | Maximum collateral spend — slippage cap (6 decimals) |

### Selling Shares

```typescript
const sharesIn = BigInt(Math.round(5 * 1e18));
const { tokensOut } = await client.quoteSell({ marketAddress, outcomeIdx, sharesIn });

const minTokensOut = tokensOut * 98n / 100n; // 2% slippage
const { transactionHash } = await client.sellShares({
  marketAddress,
  outcomeIdx,
  sharesIn,
  minTokensOut,
});
```

#### SellShares (*params*)

| Field           | Type                | Description                                               |
| --------------- | ------------------- | --------------------------------------------------------- |
| `marketAddress` | `` `0x${string}` `` | Market proxy address                                      |
| `outcomeIdx`    | `number`            | Outcome index to sell                                     |
| `sharesIn`      | `bigint`            | Exact shares to sell (18 decimals)                        |
| `minTokensOut`  | `bigint`            | Minimum collateral received — slippage floor (6 decimals) |

### Liquidating Positions

Liquidation exits positions without a winning outcome. It applies to expired and failed markets.

```typescript
const status = await client.getMarketStatus(marketAddress);
if (status === "expired" || status === "failed") {
  const { transactionHash } = await client.liquidate({
    marketAddress,
    outcomeIndices: [0, 1], // Covers a binary market.
  });
}
```

#### liquidate(*params*)

| Field            | Type                | Description           |
| ---------------- | ------------------- | --------------------- |
| `marketAddress`  | `` `0x${string}` `` | Market proxy address  |
| `outcomeIndices` | `number[]`          | Outcomes to liquidate |

Pass every outcome index where you hold shares. Omitted indices are not liquidated, and their funds remain locked. `[0, 1]` covers a binary market.

#### getMarketStatus(marketAddress)

Reads a market's lifecycle status from the owning gateway. This value is fresher than the REST API.

```typescript
const status = await client.getMarketStatus(marketAddress);
// "open" | "awaiting_settlement" | "settled" | "expired" | "failed"
```

### Slippage Guidelines

| Scenario                 | Recommended slippage |
| ------------------------ | -------------------- |
| Quiet market             | 1–2%                 |
| Active market            | 2–5%                 |
| Large trade (>$100)      | 5–10%                |
| Time-sensitive execution | 5%                   |

Here's an example of using integer arithmetic to avoid floating point:

```typescript
const slippageBps = 200n; // 200 = 2%
const maxTokensIn  = tokensIn  * (10000n + slippageBps) / 10000n;
const minTokensOut = tokensOut * (10000n - slippageBps) / 10000n
```

#### Common Contract Errors

| Error                             | Cause                           | Fix                                               |
| --------------------------------- | ------------------------------- | ------------------------------------------------- |
| `TokensInExceedsMax`              | Actual cost > maxTokensIn       | Re-quote and increase slippage                    |
| `TokensOutBelowMin`               | Actual payout < minTokensOut    | Re-quote and increase slippage                    |
| `MarketNotOpen`                   | Market closed or settled        | Cannot trade; check status                        |
| `SharesInExceedSupply`            | Selling more than held          | Query balance first                               |
| `GrossTokensOutNotPositive`       | Nothing to sell                 | Position is empty                                 |
| `ZeroTokensIn`                    | sharesOut too small             | Use a larger share amount                         |
| `MarketProxyNotDeployedByFactory` | Gateway does not own the market | Resolve the gateway or remove the pinned override |

### Token Approvals

#### getTokenAllowance(*params*)

Read the current ERC-20 allowance your wallet has granted to a market.

```typescript
const { allowance } = await client.getTokenAllowance({
  marketAddress: "0xMarket",
});
```

#### approveToken(*params*)

Approve the ERC-20 token for spending by a market.

{% hint style="info" %}
This defaults to unlimited (`uint256` max).
{% endhint %}

```typescript
// Approve unlimited
await client.approveToken({ marketAddress });

// Approve exact amount (e.g. 100 tokens; $TEST on testnet)
await client.approveToken({ marketAddress, amount: 100_000_000n });
```

#### ensureTokenApproval(*params*)

Check if sufficient allowance exists and only sends an approval transaction if needed. *Recommended before buying shares.*

```typescript
const { approvalNeeded, allowance, transactionHash } = await client.ensureTokenApproval({
  marketAddress: "0xMarket",
  minimumAmount: tokensIn,
  approveAmount: tokensIn * 10n, // optional; defaults to unlimited
});
```

{% hint style="info" %}
The SDK uses the configured token address from `DELPHI_TOKEN_ADDRESS` or the network default. It does not resolve a token address per market.
{% endhint %}

| Network             | Collateral token |
| ------------------- | ---------------- |
| Testnet             | $TEST            |
| Mainnet             | USDC             |
| Competition testnet | TST              |

### Gateway Contract Reference

This section is for advanced users who want to call the Gateway contract directly via `viem`.

The SDK uses `DYNAMIC_PARIMUTUEL_GATEWAY_ABI` on every network, including `competition-testnet`. The competition LMSR gateway exposes identical call signatures.

Competition differs in its underlying pricing math. Its `MarketSettled` event also omits market-creator economics fields.

#### viem Client Setup

Set up your viem client like this:

```typescript
import { createPublicClient, http, defineChain, type Abi } from "viem";
import {
  DELPHI_FACTORY_ABI,
  DYNAMIC_PARIMUTUEL_GATEWAY_ABI,
} from "@gensyn-ai/gensyn-delphi-sdk";

const chain = defineChain({
  id: Number(process.env.GENSYN_CHAIN_ID),
  name: "Gensyn Testnet",
  nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
  rpcUrls: { default: { http: [process.env.GENSYN_RPC_URL!] } },
});

const publicClient = createPublicClient({ chain, transport: http(process.env.GENSYN_RPC_URL!) });
const gateway = await client.resolveGateway(marketProxy);
```

`resolveGateway()` creates a signer-backed client internally. Configure `WALLET_PRIVATE_KEY` or CDP credentials, even for read-only use.

{% hint style="warning" %}
Do not use `DELPHI_GATEWAY_CONTRACT` for direct market calls unless it is the owning gateway. `resolveGateway()` selects the correct deployment.
{% endhint %}

`DELPHI_FACTORY_ABI` is also exported for direct Factory reads, including `marketProxiesExist`.

#### Gateway Functions

All of the gateway functions, broken down into tables by **\[1]** read and **\[2]** write.

#### 1. *Read* Functions

| Function                   | Args                                      | Returns              | Notes                                                         |
| -------------------------- | ----------------------------------------- | -------------------- | ------------------------------------------------------------- |
| `quoteBuyExactOut`         | marketProxy, outcomeIdx, sharesOut        | `tokensIn: uint256`  | Collateral cost (6 dec)                                       |
| `quoteSellExactIn`         | marketProxy, outcomeIdx, sharesIn         | `tokensOut: uint256` | Collateral payout (6 dec)                                     |
| `spotImpliedProbability`   | marketProxy, outcomeIdx                   | `uint256`            | 1e18 = 100%                                                   |
| `spotImpliedProbabilities` | marketProxy, outcomeIndices\[]            | `uint256[]`          | Batch                                                         |
| `spotPrice`                | marketProxy, outcomeIdx                   | `uint256`            | 1e18 = 1.0 collateral tokens per share                        |
| `spotPrices`               | marketProxy, outcomeIndices\[]            | `uint256[]`          | Batch                                                         |
| `balanceOf`                | marketProxy, owner, outcomeIdx            | `uint256`            | Shares (18 dec)                                               |
| `batchBalanceOf`           | marketProxy, owners\[], outcomeIndices\[] | `uint256[]`          | Batch                                                         |
| `totalSupply`              | marketProxy, outcomeIdx                   | `uint256`            | Total shares (18 dec)                                         |
| `totalSupplies`            | marketProxy, outcomeIndices\[]            | `uint256[]`          | Batch                                                         |
| `getMarket`                | marketProxy                               | Market struct        | Full on-chain state                                           |
| `marketStatus`             | marketProxy                               | `uint8`              | 0=Open, 1=Awaiting settlement, 2=Settled, 3=Expired, 4=Failed |
| `token`                    | marketProxy                               | `address`            | Collateral token address                                      |

#### 2. *Write* Functions

Prefer the SDK methods over calling the Gateway directly, as they handle simulation, approval, and receipt waiting.

| Function      | Args                                            | Notes                             |
| ------------- | ----------------------------------------------- | --------------------------------- |
| `buyExactOut` | marketProxy, outcomeIdx, sharesOut, maxTokensIn | Use `DelphiClient.buyShares()`    |
| `sellExactIn` | marketProxy, outcomeIdx, sharesIn, minTokensOut | Use `DelphiClient.sellShares()`   |
| `redeem`      | marketProxy                                     | Use `DelphiClient.redeemMarket()` |
| `liquidate`   | marketProxy, outcomeIndices                     | Use `DelphiClient.liquidate()`    |

### Direct Read Examples

#### Implied Probability for All Outcomes

```typescript
const probs = await publicClient.readContract({
  address: gateway,
  abi: DYNAMIC_PARIMUTUEL_GATEWAY_ABI as Abi,
  functionName: "spotImpliedProbabilities",
  args: [marketProxy, [0n, 1n]],
}) as bigint[];
// probs[i] / 1e18 * 100 = implied probability %
```

#### Spot Prices

```typescript
const prices = await publicClient.readContract({
  address: gateway,
  abi: DYNAMIC_PARIMUTUEL_GATEWAY_ABI as Abi,
  functionName: "spotPrices",
  args: [marketProxy, [0n, 1n]],
}) as bigint[];
// prices[i] / 1e18 = collateral tokens per share
```

#### Full Market State

```typescript
const onchainMarket = await publicClient.readContract({
  address: gateway,
  abi: DYNAMIC_PARIMUTUEL_GATEWAY_ABI as Abi,
  functionName: "getMarket",
  args: [marketProxy],
}) as {
  config: {
    outcomeCount: bigint;
    k: bigint;
    tradingFee: bigint;         // 1e18 = 100%
    tradingDeadline: bigint;    // Unix timestamp
    settlementDeadline: bigint; // Unix timestamp
  };
  pool: bigint;
  tradingFees: bigint;
};

const feePercent = Number(onchainMarket.config.tradingFee) / 1e18 * 100;
const deadline = new Date(Number(onchainMarket.config.tradingDeadline) * 1000);
```

#### Share Balance for a Wallet

```typescript
const balance = await publicClient.readContract({
  address: gateway,
  abi: DYNAMIC_PARIMUTUEL_GATEWAY_ABI as Abi,
  functionName: "balanceOf",
  args: [marketProxy, walletAddress as `0x${string}`, BigInt(outcomeIdx)],
}) as bigint;
// balance / 1e18 = shares
```

#### Price Impact Estimation

```typescript
const spotPrices = await publicClient.readContract({
  address: gateway,
  abi: DYNAMIC_PARIMUTUEL_GATEWAY_ABI as Abi,
  functionName: "spotPrices",
  args: [marketProxy, [0n, 1n]],
}) as bigint[];

const currentPricePerShare = Number(spotPrices[outcomeIdx]) / 1e18;
const { tokensIn } = await client.quoteBuy({ marketAddress, outcomeIdx, sharesOut });
const quotedPricePerShare = (Number(tokensIn) / 1e6) / sharesHuman;
const priceImpact = ((quotedPricePerShare - currentPricePerShare) / currentPricePerShare) * 100;
console.log(`Price impact: ${priceImpact.toFixed(2)}%`);
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.delphi.fyi/tools/sdk/methods.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
