# On-Chain Methods

## Overview

On-chain methods send transactions or read directly from the Gensyn blockchain via the Gateway contract, which is the single entry point for all on-chain interactions.

### 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.&#x20;

### Trading

#### Pricing Mechanism (DPM)

Delphi uses *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 USDC/share means \~65% implied probability

### Quoting Trades

These are read-only and therefore do not consume any *gas.*&#x20;

#### 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;
```

### 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 USDC 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`            | Max USDC to 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`            | Min USDC to receive — slippage floor (6 decimals) |

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

### 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.&#x20;

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

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

// Approve exact amount (e.g. 100 USDC)
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="success" %}
The SDK resolves the collateral token address from `Gateway.token(marketProxy)` automatically so there is no need to hardcode it.
{% endhint %}

### Gateway Contract Reference

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

#### viem Client Setup

Set up your viem client like this:

```typescript
import { createPublicClient, http, defineChain, type Abi } from "viem";
import { 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 = process.env.DELPHI_GATEWAY_CONTRACT as `0x${string}`;
```

#### Gateway Functions

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

#### 1. *Read* Functions

| Function                   | Args                                      | Returns              | Notes                       |
| -------------------------- | ----------------------------------------- | -------------------- | --------------------------- |
| `quoteBuyExactOut`         | marketProxy, outcomeIdx, sharesOut        | `tokensIn: uint256`  | USDC cost (6 dec)           |
| `quoteSellExactIn`         | marketProxy, outcomeIdx, sharesIn         | `tokensOut: uint256` | USDC payout (6 dec)         |
| `spotImpliedProbability`   | marketProxy, outcomeIdx                   | `uint256`            | 1e18 = 100%                 |
| `spotImpliedProbabilities` | marketProxy, outcomeIndices\[]            | `uint256[]`          | Batch                       |
| `spotPrice`                | marketProxy, outcomeIdx                   | `uint256`            | 1e18 = 1.0 USDC/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=Closed, 2=Settled |
| `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()` |

### 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 = USDC 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: Querying This Documentation

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

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.gensyn.ai/tech/delphi-sdk/methods.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
