Co Marketing
When the user wants to find co-marketing partners, plan joint campaigns, or brainstorm partnership opportunities.
5,506,136 AI resources indexedWorking toward the world’s largest AI resource index.
Limit buy, limit sell, update/delete, and list limit orders via managed-custody encrypted payloads
---
name: gdex-limit-orders-67b9ae9b4386
description: Limit buy, limit sell, update/delete, and list limit orders via managed-custody encrypted payloads
---
# GDEX: Limit Orders
Create limit buy/sell orders that trigger when a token reaches your target price. Uses the same managed-custody encryption flow as spot trades (ABI-encoded → signed → AES-encrypted `computedData`).
## Critical: Endpoint Structure
Limit orders use **separate endpoints for buy vs sell** (NOT a single create endpoint):
| Action | Endpoint | SDK Method |
|--------|----------|------------|
| List orders | `GET /v1/orders` | `getLimitOrders()` |
| Buy when price drops | `POST /v1/limit_buy` | `limitBuy()` |
| Sell when price rises/drops | `POST /v1/limit_sell` | `limitSell()` |
| Update or delete order | `POST /v1/update_order` | `updateOrder()` |
> There is NO `/v1/orders/create` or `/v1/orders/cancel` endpoint.
## When to Use
- Buy a token when its price drops to a target → `limitBuy()`
- Sell a token when its price rises (take-profit) or drops (stop-loss) → `limitSell()`
- Cancel an existing order → `updateOrder({ isDelete: true })`
- Update an order's price/amount → `updateOrder()`
- List all active orders → `getLimitOrders()`
## Prerequisites
- `@gemachdao/gdex-skill` installed
- Authenticated via `loginWithApiKey()` — see **gdex-authentication**
- Minimum order: `config.chains[chainId].minLimitOrder` (typically 0.01 native token)
## Limit Buy — Buy Token When Price Drops
```typescript
import { GdexSkill, GDEX_API_KEY_PRIMARY } from '@gemachdao/gdex-skill';
const skill = new GdexSkill();
skill.loginWithApiKey(GDEX_API_KEY_PRIMARY);
const result = await skill.limitBuy({
apiKey: GDEX_API_KEY_PRIMARY,
userId: '0x53D029a671bd1CF61a2fB1F4F6e4bD830BFBb2eD', // control wallet
sessionPrivateKey: '<session-private-key-hex>',
chainId: 622112261, // Solana
tokenAddress: 'EKpQGSJtjMFqKZ9KQanSqYXRcF8fBopzLHYxdM65zcjm', // WIF
amount: '10000000', // 0.01 SOL in lamports
triggerPrice: '0.50', // trigger when WIF price ≤ $0.50
profitPercent: '50', // take profit at 50% gain (optional)
lossPercent: '25', // stop loss at 25% loss (optional)
});
```
### LimitBuyParams
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `apiKey` | `string` | Yes | API key for AES encryption |
| `userId` | `string` | Yes | Control wallet address (NOT managed) |
| `sessionPrivateKey` | `string` | Yes | Session key from sign-in |
| `chainId` | `number` | Yes | Numeric chain ID (e.g. 622112261 for Solana) |
| `tokenAddress` | `string` | Yes | Token to buy |
| `amount` | `string` | Yes | Native token to spend (raw units: wei/lamports, positive integer string) |
| `triggerPrice` | `string` | Yes | USD price to trigger the buy |
| `profitPercent` | `string` | No | Take-profit % above trigger, whole number ("0" to skip) |
| `lossPercent` | `string` | No | Stop-loss % below trigger, whole number below 100 ("0" to skip) |
**ABI schema:** `['string','string','string','uint64','uint64','string']` = `[tokenAddress, amount, triggerPrice, profitPercent, lossPercent, nonce]`
**Signature:** `limit_buy-{userId}-{data}`
> **CRITICAL (Live-Tested):** `profitPercent` and `lossPercent` MUST be ABI-encoded as integers (`uint64`), NOT `string`. The backend decodes them as uint256 and validates `0-100` range. Using `string` type produces ABI byte-offsets (e.g. 192) that fail the range check with `"lossPercent must be between 0 and 100"`. The SDK handles this correctly — only matters if encoding manually.
## Limit Sell — Sell Token at Target Price
```typescript
// Sell WIF when price reaches $999.99 (take-profit)
const result = await skill.limitSell({
apiKey: GDEX_API_KEY_PRIMARY,
userId: '0x53D029a671bd1CF61a2fB1F4F6e4bD830BFBb2eD',
sessionPrivateKey: '<session-private-key-hex>',
chainId: 622112261,
tokenAddress: 'EKpQGSJtjMFqKZ9KQanSqYXRcF8fBopzLHYxdM65zcjm', // WIF
amount: '100000', // token amount in raw units
triggerPrice: '999.99', // trigger when WIF price reaches $999.99
});
```
### LimitSellParams
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `apiKey` | `string` | Yes | API key for AES encryption |
| `userId` | `string` | Yes | Control wallet address |
| `sessionPrivateKey` | `string` | Yes | Session key from sign-in |
| `chainId` | `number` | Yes | Numeric chain ID |
| `tokenAddress` | `string` | Yes | Token to sell |
| `amount` | `string` | Yes | Token amount to sell (raw units) |
| `triggerPrice` | `string` | Yes | USD price to trigger the sell |
**ABI schema:** `['string','string','string','string']` = `[tokenAddress, amount, triggerPrice, nonce]`
**Signature:** `limit_sell-{userId}-{data}`
> The backend auto-classifies as take-profit (trigger > current price) or stop-loss (trigger < current price).
## Update or Delete an Order
```typescript
// Delete an order
await skill.updateOrder({
apiKey: GDEX_API_KEY_PRIMARY,
userId: '0x53D029a671bd1CF61a2fB1F4F6e4bD830BFBb2eD',
sessionPrivateKey: '<session-private-key-hex>',
chainId: 622112261,
orderId: '64-char-hex-order-id',
isDelete: true,
});
// Update an order: the backend replaces amount, price and TP/SL together,
// so pass the full new state ('0' = no TP / SL; sell orders ignore both)
await skill.updateOrder({
apiKey: GDEX_API_KEY_PRIMARY,
userId: '0x53D029a671bd1CF61a2fB1F4F6e4bD830BFBb2eD',
sessionPrivateKey: '<session-private-key-hex>',
chainId: 622112261,
orderId: '64-char-hex-order-id',
triggerPrice: '1.50',
amount: '10000000',
profitPercent: '50',
lossPercent: '25',
});
```
### UpdateOrderParams
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `apiKey` | `string` | Yes | API key for AES encryption |
| `userId` | `string` | Yes | Control wallet address |
| `sessionPrivateKey` | `string` | Yes | Session key from sign-in |
| `chainId` | `number` | Yes | Numeric chain ID |
| `orderId` | `string` | Yes | Order ID from getLimitOrders() |
| `amount` | `string` | Unless `isDelete` | New amount, raw units as a positive integer string |
| `triggerPrice` | `string` | Unless `isDelete` | New trigger price (USD, plain decimal) |
| `profitPercent` | `string` | Unless `isDelete` | New take-profit %, whole number, `'0'` = none (buy orders) |
| `lossPercent` | `string` | Unless `isDelete` | New stop-loss %, whole number below 100, `'0'` = none (buy orders) |
| `isDelete` | `boolean` | No | Set true to cancel/delete the order |
**ABI schema:** `['string','string','string','uint64','uint64','string','bool']` = `[orderId, amount, triggerPrice, profitPercent, lossPercent, nonce, isDelete]`
**Signature:** `update_order-{userId}-{data}`
> **CRITICAL:** `profitPercent` / `lossPercent` are `uint64` and `isDelete` is an ABI `bool`, as the backend decodes them. An `isDelete` encoded as a string decodes as `true`, so every update would delete the order. The SDK encodes these correctly and rejects a malformed amount, price or percentage before signing.
## List Orders
```typescript
const { count, orders } = await skill.getLimitOrders({
userId: '0x53D029a671bd1CF61a2fB1F4F6e4bD830BFBb2eD',
data: encryptedSessionKey, // from buildGdexUserSessionData()
chainId: 622112261,
});
```
### GetLimitOrdersParams
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `userId` | `string` | Yes | Control wallet address |
| `data` | `string` | Yes | Encrypted session key (from `buildGdexUserSessionData`) |
| `chainId` | `number` | Yes | Numeric chain ID |
### LimitOrder Object (response)
```typescript
interface LimitOrder {
orderId: string; // unique 64-char hex ID
fromToken: string; // token being sold
toToken: string; // token being bought
isBuyLimit: boolean; // true = buy limit, false = sell limit
price: number; // trigger price in USD
takeProfitPrice: number; // TP price (0 = disabled)
stopLossPrice: number; // SL price (0 = disabled)
fromTokenAmount: string; // amount in raw units
toTokenAmount: string; // computed output amount
walletAddress: string; // managed wallet address
userId: string; // control wallet address
chainId: number; // numeric chain ID
pairAddress: string; // DEX pair address
isActive: boolean; // still pending?
isCancelled?: boolean; // was cancelled?
expiredAt: number; // expiry Unix timestamp
profitPercent?: string; // TP % (buy orders)
lossPercent?: string; // SL % (buy orders)
}
```
## Order Fill Logic
Orders are filled by background processes that monitor prices via NATS:
- **Buy limit:** triggers when `tokenPrice <= order.price`
- **Sell take-profit:** triggers when `tokenPrice >= takeProfitPrice`
- **Sell stop-loss:** triggers when `tokenPrice <= stopLossPrice`
## Error Codes
| Code | Meaning |
|------|---------|
| 101 | Missing required parameters |
| 102 | Invalid nonce or params |
| 103 | Unauthorized (wrong userId or session key) |
| 1011 | Invalid/expired order |
| 1012 | Order expired |
| 1031 | Unsupported token |
| 400 | Insufficient balance (need ≥ minLimitOrder in native token) |
## Legacy Aliases
For backward compatibility, older method names still work:
- `createLimitOrder()` → calls `limitBuy()`
- `cancelLimitOrder()` → calls `updateOrder({ isDelete: true })`
## Autonomous Agent Notes (Live-Tested)
### Verified Working Flow (Solana/WIF Example)
This exact sequence was tested end-to-end and succeeded:
```typescript
// 1. List existing orders
const orders = await skill.getLimitOrders({ userId, data, chainId: 622112261 });
// 2. Create a limit buy order
const result = await skill.limitBuy({
apiKey: GDEX_API_KEY_PRIMARY,
userId: controlAddress, // MUST be control address, lowercase
sessionPrivateKey,
chainId: 622112261, // Solana
tokenAddress: 'EKpQGSJtjMFqKZ9KQanSqYXRcF8fBopzLHYxdM65zcjm', // WIF
amount: '1000000', // ~0.001 SOL in lamports (raw units)
triggerPrice: '0.0001', // trigger when price drops to $0.0001
profitPercent: '50', // 50% take-profit
lossPercent: '30', // 30% stop-loss
});
// → { isSuccess: true, message: "Order created successfully", order: {...} }
// 3. Verify order appears in list
const updated = await skill.getLimitOrders({ userId, data, chainId: 622112261 });
// 4. Cancel the order
await skill.updateOrder({
apiKey, userId, sessionPrivateKey,
chainId: 622112261,
orderId: result.order.orderId,
isDelete: true,
});
```
### Key Requirements for Limit Buy
- `amount` must be in **raw units** (lamports for Solana, wei for EVM) — NOT float
- `profitPercent` and `lossPercent` are **mandatory** for `limit_buy` (both must be > 0)
- `profitPercent` and `lossPercent` are whole numbers (ABI-encoded as `uint64`); `lossPercent` must be below 100
- `userId` must be the **control** wallet address, **lowercase**
- `triggerPrice` is in USD (string)
### Minimum Order Size
The backend enforces `config.chains[chainId].minLimitOrder` per chain. For Solana, this is approximately 0.001 SOL (1000000 lamports). Going below returns "Insufficient balance".
### Order Cancellation
To cancel, use `updateOrder({ isDelete: true })`. There is no separate cancel endpoint. The `cancelLimitOrder()` alias calls this internally.
### Error Messages and What They Mean
| Error | Cause | Fix |
|-------|-------|-----|
| `lossPercent must be between 0 and 100` | ABI encoding used `string` type instead of `uint256` | SDK handles this correctly; only matters for manual encoding |
| `Insufficient balance` | Amount too small or managed wallet underfunded | Increase amount or fund the managed Solana wallet |
| `Order not found` (on update/delete) | Wrong `orderId` or order already filled/expired | Refresh order list with `getLimitOrders()` first |
| `Invalid nonce` | Reused or stale nonce | Generate fresh: `String(Date.now())` |
## Related Skills
- **gdex-authentication** — Auth setup required before creating orders
- **gdex-spot-trading** — Market orders (immediate execution) instead of limits
- **gdex-portfolio** — Track order fills in trade history
---
name: gdex-limit-orders-67b9ae9b4386
description: Limit buy, limit sell, update/delete, and list limit orders via managed-custody encrypted payloads
---
# GDEX: Limit Orders
Create limit buy/sell orders that trigger when a token reaches your target price. Uses the same managed-custody encryption flow as spot trades (ABI-encoded → signed → AES-encrypted `computedData`).
## Critical: Endpoint Structure
Limit orders use **separate endpoints for buy vs sell** (NOT a single create endpoint):
| Action | Endpoint | SDK Method |
|--------|----------|------------|
| List orders | `GET /v1/orders` | `getLimitOrders()` |
| Buy when price drops | `POST /v1/limit_buy` | `limitBuy()` |
| Sell when price rises/drops | `POST /v1/limit_sell` | `limitSell()` |
| Update or delete order | `POST /v1/update_order` | `updateOrder()` |
> There is NO `/v1/orders/create` or `/v1/orders/cancel` endpoint.
## When to Use
- Buy a token when its price drops to a target → `limitBuy()`
- Sell a token when its price rises (take-profit) or drops (stop-loss) → `limitSell()`
- Cancel an existing order → `updateOrder({ isDelete: true })`
- Update an order's price/amount → `updateOrder()`
- List all active orders → `getLimitOrders()`
## Prerequisites
- `@gemachdao/gdex-skill` installed
- Authenticated via `loginWithApiKey()` — see **gdex-authentication**
- Minimum order: `config.chains[chainId].minLimitOrder` (typically 0.01 native token)
## Limit Buy — Buy Token When Price Drops
```typescript
import { GdexSkill, GDEX_API_KEY_PRIMARY } from '@gemachdao/gdex-skill';
const skill = new GdexSkill();
skill.loginWithApiKey(GDEX_API_KEY_PRIMARY);
const result = await skill.limitBuy({
apiKey: GDEX_API_KEY_PRIMARY,
userId: '0x53D029a671bd1CF61a2fB1F4F6e4bD830BFBb2eD', // control wallet
sessionPrivateKey: '<session-private-key-hex>',
chainId: 622112261, // Solana
tokenAddress: 'EKpQGSJtjMFqKZ9KQanSqYXRcF8fBopzLHYxdM65zcjm', // WIF
amount: '10000000', // 0.01 SOL in lamports
triggerPrice: '0.50', // trigger when WIF price ≤ $0.50
profitPercent: '50', // take profit at 50% gain (optional)
lossPercent: '25', // stop loss at 25% loss (optional)
});
```
### LimitBuyParams
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `apiKey` | `string` | Yes | API key for AES encryption |
| `userId` | `string` | Yes | Control wallet address (NOT managed) |
| `sessionPrivateKey` | `string` | Yes | Session key from sign-in |
| `chainId` | `number` | Yes | Numeric chain ID (e.g. 622112261 for Solana) |
| `tokenAddress` | `string` | Yes | Token to buy |
| `amount` | `string` | Yes | Native token to spend (raw units: wei/lamports, positive integer string) |
| `triggerPrice` | `string` | Yes | USD price to trigger the buy |
| `profitPercent` | `string` | No | Take-profit % above trigger, whole number ("0" to skip) |
| `lossPercent` | `string` | No | Stop-loss % below trigger, whole number below 100 ("0" to skip) |
**ABI schema:** `['string','string','string','uint64','uint64','string']` = `[tokenAddress, amount, triggerPrice, profitPercent, lossPercent, nonce]`
**Signature:** `limit_buy-{userId}-{data}`
> **CRITICAL (Live-Tested):** `profitPercent` and `lossPercent` MUST be ABI-encoded as integers (`uint64`), NOT `string`. The backend decodes them as uint256 and validates `0-100` range. Using `string` type produces ABI byte-offsets (e.g. 192) that fail the range check with `"lossPercent must be between 0 and 100"`. The SDK handles this correctly — only matters if encoding manually.
## Limit Sell — Sell Token at Target Price
```typescript
// Sell WIF when price reaches $999.99 (take-profit)
const result = await skill.limitSell({
apiKey: GDEX_API_KEY_PRIMARY,
userId: '0x53D029a671bd1CF61a2fB1F4F6e4bD830BFBb2eD',
sessionPrivateKey: '<session-private-key-hex>',
chainId: 622112261,
tokenAddress: 'EKpQGSJtjMFqKZ9KQanSqYXRcF8fBopzLHYxdM65zcjm', // WIF
amount: '100000', // token amount in raw units
triggerPrice: '999.99', // trigger when WIF price reaches $999.99
});
```
### LimitSellParams
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `apiKey` | `string` | Yes | API key for AES encryption |
| `userId` | `string` | Yes | Control wallet address |
| `sessionPrivateKey` | `string` | Yes | Session key from sign-in |
| `chainId` | `number` | Yes | Numeric chain ID |
| `tokenAddress` | `string` | Yes | Token to sell |
| `amount` | `string` | Yes | Token amount to sell (raw units) |
| `triggerPrice` | `string` | Yes | USD price to trigger the sell |
**ABI schema:** `['string','string','string','string']` = `[tokenAddress, amount, triggerPrice, nonce]`
**Signature:** `limit_sell-{userId}-{data}`
> The backend auto-classifies as take-profit (trigger > current price) or stop-loss (trigger < current price).
## Update or Delete an Order
```typescript
// Delete an order
await skill.updateOrder({
apiKey: GDEX_API_KEY_PRIMARY,
userId: '0x53D029a671bd1CF61a2fB1F4F6e4bD830BFBb2eD',
sessionPrivateKey: '<session-private-key-hex>',
chainId: 622112261,
orderId: '64-char-hex-order-id',
isDelete: true,
});
// Update an order: the backend replaces amount, price and TP/SL together,
// so pass the full new state ('0' = no TP / SL; sell orders ignore both)
await skill.updateOrder({
apiKey: GDEX_API_KEY_PRIMARY,
userId: '0x53D029a671bd1CF61a2fB1F4F6e4bD830BFBb2eD',
sessionPrivateKey: '<session-private-key-hex>',
chainId: 622112261,
orderId: '64-char-hex-order-id',
triggerPrice: '1.50',
amount: '10000000',
profitPercent: '50',
lossPercent: '25',
});
```
### UpdateOrderParams
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `apiKey` | `string` | Yes | API key for AES encryption |
| `userId` | `string` | Yes | Control wallet address |
| `sessionPrivateKey` | `string` | Yes | Session key from sign-in |
| `chainId` | `number` | Yes | Numeric chain ID |
| `orderId` | `string` | Yes | Order ID from getLimitOrders() |
| `amount` | `string` | Unless `isDelete` | New amount, raw units as a positive integer string |
| `triggerPrice` | `string` | Unless `isDelete` | New trigger price (USD, plain decimal) |
| `profitPercent` | `string` | Unless `isDelete` | New take-profit %, whole number, `'0'` = none (buy orders) |
| `lossPercent` | `string` | Unless `isDelete` | New stop-loss %, whole number below 100, `'0'` = none (buy orders) |
| `isDelete` | `boolean` | No | Set true to cancel/delete the order |
**ABI schema:** `['string','string','string','uint64','uint64','string','bool']` = `[orderId, amount, triggerPrice, profitPercent, lossPercent, nonce, isDelete]`
**Signature:** `update_order-{userId}-{data}`
> **CRITICAL:** `profitPercent` / `lossPercent` are `uint64` and `isDelete` is an ABI `bool`, as the backend decodes them. An `isDelete` encoded as a string decodes as `true`, so every update would delete the order. The SDK encodes these correctly and rejects a malformed amount, price or percentage before signing.
## List Orders
```typescript
const { count, orders } = await skill.getLimitOrders({
userId: '0x53D029a671bd1CF61a2fB1F4F6e4bD830BFBb2eD',
data: encryptedSessionKey, // from buildGdexUserSessionData()
chainId: 622112261,
});
```
### GetLimitOrdersParams
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `userId` | `string` | Yes | Control wallet address |
| `data` | `string` | Yes | Encrypted session key (from `buildGdexUserSessionData`) |
| `chainId` | `number` | Yes | Numeric chain ID |
### LimitOrder Object (response)
```typescript
interface LimitOrder {
orderId: string; // unique 64-char hex ID
fromToken: string; // token being sold
toToken: string; // token being bought
isBuyLimit: boolean; // true = buy limit, false = sell limit
price: number; // trigger price in USD
takeProfitPrice: number; // TP price (0 = disabled)
stopLossPrice: number; // SL price (0 = disabled)
fromTokenAmount: string; // amount in raw units
toTokenAmount: string; // computed output amount
walletAddress: string; // managed wallet address
userId: string; // control wallet address
chainId: number; // numeric chain ID
pairAddress: string; // DEX pair address
isActive: boolean; // still pending?
isCancelled?: boolean; // was cancelled?
expiredAt: number; // expiry Unix timestamp
profitPercent?: string; // TP % (buy orders)
lossPercent?: string; // SL % (buy orders)
}
```
## Order Fill Logic
Orders are filled by background processes that monitor prices via NATS:
- **Buy limit:** triggers when `tokenPrice <= order.price`
- **Sell take-profit:** triggers when `tokenPrice >= takeProfitPrice`
- **Sell stop-loss:** triggers when `tokenPrice <= stopLossPrice`
## Error Codes
| Code | Meaning |
|------|---------|
| 101 | Missing required parameters |
| 102 | Invalid nonce or params |
| 103 | Unauthorized (wrong userId or session key) |
| 1011 | Invalid/expired order |
| 1012 | Order expired |
| 1031 | Unsupported token |
| 400 | Insufficient balance (need ≥ minLimitOrder in native token) |
## Legacy Aliases
For backward compatibility, older method names still work:
- `createLimitOrder()` → calls `limitBuy()`
- `cancelLimitOrder()` → calls `updateOrder({ isDelete: true })`
## Autonomous Agent Notes (Live-Tested)
### Verified Working Flow (Solana/WIF Example)
This exact sequence was tested end-to-end and succeeded:
```typescript
// 1. List existing orders
const orders = await skill.getLimitOrders({ userId, data, chainId: 622112261 });
// 2. Create a limit buy order
const result = await skill.limitBuy({
apiKey: GDEX_API_KEY_PRIMARY,
userId: controlAddress, // MUST be control address, lowercase
sessionPrivateKey,
chainId: 622112261, // Solana
tokenAddress: 'EKpQGSJtjMFqKZ9KQanSqYXRcF8fBopzLHYxdM65zcjm', // WIF
amount: '1000000', // ~0.001 SOL in lamports (raw units)
triggerPrice: '0.0001', // trigger when price drops to $0.0001
profitPercent: '50', // 50% take-profit
lossPercent: '30', // 30% stop-loss
});
// → { isSuccess: true, message: "Order created successfully", order: {...} }
// 3. Verify order appears in list
const updated = await skill.getLimitOrders({ userId, data, chainId: 622112261 });
// 4. Cancel the order
await skill.updateOrder({
apiKey, userId, sessionPrivateKey,
chainId: 622112261,
orderId: result.order.orderId,
isDelete: true,
});
```
### Key Requirements for Limit Buy
- `amount` must be in **raw units** (lamports for Solana, wei for EVM) — NOT float
- `profitPercent` and `lossPercent` are **mandatory** for `limit_buy` (both must be > 0)
- `profitPercent` and `lossPercent` are whole numbers (ABI-encoded as `uint64`); `lossPercent` must be below 100
- `userId` must be the **control** wallet address, **lowercase**
- `triggerPrice` is in USD (string)
### Minimum Order Size
The backend enforces `config.chains[chainId].minLimitOrder` per chain. For Solana, this is approximately 0.001 SOL (1000000 lamports). Going below returns "Insufficient balance".
### Order Cancellation
To cancel, use `updateOrder({ isDelete: true })`. There is no separate cancel endpoint. The `cancelLimitOrder()` alias calls this internally.
### Error Messages and What They Mean
| Error | Cause | Fix |
|-------|-------|-----|
| `lossPercent must be between 0 and 100` | ABI encoding used `string` type instead of `uint256` | SDK handles this correctly; only matters for manual encoding |
| `Insufficient balance` | Amount too small or managed wallet underfunded | Increase amount or fund the managed Solana wallet |
| `Order not found` (on update/delete) | Wrong `orderId` or order already filled/expired | Refresh order list with `getLimitOrders()` first |
| `Invalid nonce` | Reused or stale nonce | Generate fresh: `String(Date.now())` |
## Related Skills
- **gdex-authentication** — Auth setup required before creating orders
- **gdex-spot-trading** — Market orders (immediate execution) instead of limits
- **gdex-portfolio** — Track order fills in trade history
Imported from the listed AgentSkill.sh category. Complete supplied package files and notices are retained. Required external tools and credentials are not installed. No bundled code was executed during import. Individual agent task behavior has not been tested.