Sign
Overview
All DEX operations use standard Ethereum transactions with a specific structure:
- Standard Ethereum transaction sent to a fixed contract address
- To Address (FIXED):
0x00000000000000000000000000000000000000cc - Input Data Format:
[Command Byte] + [JSON Data]
Important Notes:
- Strict Schema: Only predefined fields are allowed in JSON data. Unknown fields will be rejected.
- Order ID: The order ID is the transaction hash (txHash) of the create order transaction
- Price and Quantity: All values in JSON contexts are already decimal-applied:
- Price "2.3" means 2.3 USDT
- Quantity "10.5" means 10.5 tokens
- No conversion to smallest units (wei) is needed
Transaction Structure:
{
from: "0x...", // Your wallet address
to: "0x00000000000000000000000000000000000000cc", // FIXED contract address
data: "[CommandByte][JSON(Context)]", // Command byte + JSON payload
value: "0x0", // Always 0 for DEX operations
gasLimit: "0x30000", // Arbitrary large value (gas-free on L2)
gasPrice: "0x0", // Set to 0 (gas-free on L2)
nonce: "...", // Your account nonce (supports timeNonce: Unix timestamp in ms)
chainId: "..." // Kaia chain ID
}
Command Bytes
| Command | Byte Value | Description |
|---|---|---|
| DexCommandSession | 0x01 | Session wallet operations |
| DexCommandTransfer | 0x02 | Kaia transfers |
| DexCommandTokenTransfer | 0x11 | Token-specific transfers |
| DexCommandOrder | 0x21 | Place new order |
| DexCommandCancel | 0x22 | Cancel specific order |
| DexCommandCancelAll | 0x23 | Cancel all orders |
| DexCommandModify | 0x24 | Modify existing order |
| DexCommandStopOrder | 0x25 | Place stop order |
Enums for Order Context
Side
| Value | Description |
|---|---|
| 0 | Buy order |
| 1 | Sell order |
Order Type
| Value | Description |
|---|---|
| 0 | Limit order |
| 1 | Market order |
Order Mode
| Value | Description |
|---|---|
| 0 | Base mode (default) - quantity in base token |
| 1 | Quote mode - quantity in quote token (market orders only) |
Note: Quote mode (orderMode=1) can only be used for market orders that execute at the best available price. It cannot be used for limit orders. This is particularly useful for market buy orders where you want to specify the amount in quote token (e.g., "buy with 1000 USDT").
Tick and Lot Size
Alpha Sec. enforces standardized price precision and minimum order sizes across all markets to ensure consistent execution, protect against dust orders, and maintain engine-level efficiency.
Price Precision
Prices support up to 5 significant digits and up to 8 decimal places. Depending on the price range, the allowed decimal places and the minimum order size change dynamically.
Decimal Rules by Price Range
The following table defines the allowed decimal precision and the minimum order size for each price tier. Lower priced assets allow deeper decimal precision but enforce larger minimum sizes to prevent excessively small orders.
| Price Range | Allowed Decimals | Minimum Size |
|---|---|---|
| 10,000 or higher | 0 | 0.00001 |
| 1,000 or higher | 1 | 0.0001 |
| 100 or higher | 2 | 0.001 |
| 10 or higher | 3 | 0.01 |
| 1 or higher | 4 | 0.1 |
| 0.1 or higher | 5 | 1 |
| 0.01 or higher | 6 | 1 |
| 0.001 or higher | 7 | 1 |
| 0.0001 or higher | 8 | 1 |
| 0.00001 or higher | 8 | 1 |
| 0.000001 or higher | 8 | 1 |
| 0.0000001 or higher | 8 | 1 |
| 0.00000001 or higher | 8 | 1 |
Valid Price and Size Conditions
An order is valid only if it satisfies the following conditions:
Price Rules:
-
The price must be within 5 significant digits
- Valid:
12345,0.0012345 - Invalid:
12345.6,0.00123456
- Valid:
-
The price cannot exceed the allowed decimal places for its price tier
- Example: If the price is
120, allowed decimals = 2- Valid:
120.34 - Invalid:
120.345
- Valid:
- Example: If the price is
Size Rules:
- The size must be equal to or greater than the minimum size defined for the current price tier
- Example: At
50dollars, minimum size is0.01- Valid:
0.01 - Invalid:
0.009
- Valid:
- Example: At
Note: Orders that do not meet these requirements will be rejected by the matching engine.
1. Session Wallet Operations (DexCommandSession - 0x01)
POST /api/v1/wallet/session
Manage session wallets for delegated trading. Session wallets allow trading without exposing the main wallet's private key.
Transaction Data Structure:
data = [0x01][JSON(SessionContext)]
SessionContext Structure:
{
"type": 1, // 1: create, 2: update, 3: delete
"publickey": "0xSessionWalletAddress",
"expiresAt": 1758005316, // Unix timestamp in seconds when session expires
"nonce": 0, // Session nonce for replay protection
"l1owner": "0x1234567890123456789012345678901234567890",
"l1signature": "0x..." // EIP-712 signature
}
SessionContext Fields:
| Field | Type | Mandatory | Description |
|---|---|---|---|
| type | INT | YES | Session command: 1 (create), 2 (update), 3 (delete) |
| publickey | STRING | YES | Session wallet address |
| expiresAt | LONG | YES | Unix timestamp in seconds when session expires |
| nonce | LONG | YES | Nonce for replay protection |
| l1owner | STRING | YES | Owner wallet address (master wallet address) |
| l1signature | STRING | YES | EIP-712 signature from owner wallet |
Session Command Types:
| Type | Value | Description |
|---|---|---|
| SessionCreate | 1 | Create new session wallet |
| SessionUpdate | 2 | Update existing session |
| SessionDelete | 3 | Delete session wallet |
EIP-712 Signature Structure
Session operations require an EIP-712 typed data signature:
const typedData = {
types: {
EIP712Domain: [
{ name: "name", type: "string" },
{ name: "version", type: "string" },
{ name: "chainId", type: "uint256" },
{ name: "verifyingContract", type: "address" }
],
RegisterSessionWallet: [
{ name: "sessionWallet", type: "address" },
{ name: "expiry", type: "uint64" },
{ name: "nonce", type: "uint64" }
]
},
primaryType: "RegisterSessionWallet",
domain: {
name: "DEXSignTransaction",
version: "1",
chainId: 8217, // 8217 for Mainnet L1 Chain ID
verifyingContract: "0x0000000000000000000000000000000000000000"
},
message: {
sessionWallet: "0xSessionWalletAddress",
expiry: "1758005316", // Unix timestamp in seconds as string
nonce: "0" // Nonce as string
}
};
// Sign the typed data with the L1 owner's private key
const signature = await signer._signTypedData(
typedData.domain,
{ RegisterSessionWallet: typedData.types.RegisterSessionWallet },
typedData.message
);
// IMPORTANT: When building the transaction, use the same nonce
const nonce = "0"; // Or Date.now().toString() for timeNonce
const tx = {
from: l1owner,
to: "0x00000000000000000000000000000000000000cc",
data: commandByte + JSON.stringify({
type: 1, // SessionCreate
publickey: sessionWallet,
expiresAt: 1758005316,
nonce: parseInt(nonce), // MUST match the nonce in EIP-712 message
l1owner: l1owner,
l1signature: signature
}),
nonce: nonce, // Transaction nonce MUST match the nonce in SessionContext
gasPrice: '0x0',
gasLimit: '0x30000'
};
Request Body:
{
"tx": "0x02f8730183...{full signed transaction hex}"
}
Response:
{
"code": 200,
"errMsg": "OK",
"result": "0x4c9980c4fd003e9aae2e7a8a87812382c84a695614225e423aaf1676089dbbfe"
}
Notes:
- Session wallets expire at the specified Unix timestamp (in milliseconds)
- The nonce prevents replay attacks
- Important: The nonce value in the EIP-712 message MUST match the nonce value in the actual transaction
- Important: The
chainIdin the EIP-712 domain must be the L1 chain ID (e.g., 8217 for Kaia Mainnet), not the L2 chain ID - L1 signature must be an EIP-712 signature from the owner wallet
- All session operations target the same fixed contract address:
0x00000000000000000000000000000000000000cc
2. Place Order (DexCommandOrder - 0x21)
POST /api/v1/order
Transaction Data Structure:
data = [0x21][JSON(OrderContext)]
OrderContext Structure:
{
"l1owner": "0x1234567890123456789012345678901234567890",
"baseToken": "1",
"quoteToken": "2",
"side": 0, // 0: buy, 1: sell
"price": "2.3", // Price
"quantity": "10.5", // Quantity
"orderType": 0, // 0: limit, 1: market
"orderMode": 0 // 0: base mode, 1: quote mode
}
OrderContext Fields:
| Field | Type | Mandatory | Description |
|---|---|---|---|
| l1owner | STRING | YES | Wallet address placing the order (master wallet address) |
| baseToken | STRING | YES | Base token ID (e.g., "1" for KAIA) |
| quoteToken | STRING | YES | Quote token ID (e.g., "2" for USDT) |
| side | INT | YES | 0 for buy, 1 for sell |
| price | STRING | YES | Limit price (set to "0" for market orders) |
| quantity | STRING | YES | Order quantity |
| orderType | INT | YES | 0 for limit, 1 for market |
| orderMode | INT | YES | 0 for base mode, 1 for quote mode (quote mode only available for market orders) |
Request Body:
{
"tx": "0x02f8730183...{full signed transaction hex}"
}
Response:
{
"code": 200,
"errMsg": "OK",
"result": "0x4c9980c4fd003e9aae2e7a8a87812382c84a695614225e423aaf1676089dbbfe"
}
2-1. Place TPSL Order (DexCommandOrder - 0x21)
POST /api/v1/order (with Take Profit/Stop Loss)
Transaction Data Structure:
data = [0x21][JSON(OrderContextWithTPSL)]
OrderContextWithTPSL Structure:
{
"l1owner": "0x1234567890123456789012345678901234567890",
"baseToken": "1",
"quoteToken": "2",
"side": 0, // 0: buy, 1: sell
"price": "2.3", // Main order price
"quantity": "10.5", // Quantity
"orderType": 0, // 0: limit, 1: market
"orderMode": 0, // 0: base mode, 1: quote mode
"tpsl": { // Take Profit/Stop Loss configuration
"tpLimit": "2.5", // Take profit limit price
"slTrigger": "2.1", // Stop loss trigger price
"slLimit": "2.09" // Optional: Stop loss limit price (if not set, SL is market)
}
}
OrderContextWithTPSL Fields:
| Field | Type | Mandatory | Description |
|---|---|---|---|
| l1owner | STRING | YES | Wallet address placing the order (master wallet address) |
| baseToken | STRING | YES | Base token ID |
| quoteToken | STRING | YES | Quote token ID |
| side | INT | YES | 0 for buy, 1 for sell |
| price | STRING | YES | Main order limit price |
| quantity | STRING | YES | Order quantity |
| orderType | INT | YES | 0 for limit, 1 for market |
| orderMode | INT | YES | 0 for base mode, 1 for quote mode (quote mode only available for market orders) |
| tpsl | OBJECT | YES | Take profit and stop loss configuration |
| tpsl.tpLimit | STRING | YES | Take profit limit price |
| tpsl.slTrigger | STRING | YES | Stop loss trigger price |
| tpsl.slLimit | STRING | NO | Stop loss limit price (omit for market SL) |
Request Body:
{
"tx": "0x02f8730183...{full signed transaction hex}"
}
Response:
{
"code": 200,
"errMsg": "OK",
"result": "0x4c9980c4fd003e9aae2e7a8a87812382c84a695614225e423aaf1676089dbbfe"
}
TPSL Order ID Generation:
When placing a TPSL order, both TP and SL must be set together. The order IDs are systematically generated from the original order's transaction hash:
// Generated based on original order ID (txHash)
TPIncrement = 1 // TP order: txHash[31] + 1
SLIncrement = 2 // SL order: txHash[31] + 2
// Note: Only the last byte is rotated
// Example:
// Original: 0x011...00ff → TP ID: 0x011...0000, SL ID: 0x011...0001
- Stop orders use the original txHash as-is (no increment)
- Both TP and SL orders must be configured when using the
tpslfield
3. Cancel Order (DexCommandCancel - 0x22)
POST /api/v1/order/cancel
Transaction Data Structure:
data = [0x22][JSON(CancelContext)]
CancelContext Structure:
{
"l1owner": "0x1234567890123456789012345678901234567890",
"orderId": "0x4c9980c4fd003e9aae2e7a8a87812382c84a695614225e423aaf1676089dbbfe"
}
CancelContext Fields:
| Field | Type | Mandatory | Description |
|---|---|---|---|
| l1owner | STRING | YES | Wallet address that owns the order (master wallet address) |
| orderId | STRING | YES | Order ID to cancel (transaction hash) |
Request Body:
{
"tx": "0x02f8730183...{full signed transaction hex}"
}
Response:
{
"code": 200,
"errMsg": "OK",
"result": "0x4c9980c4fd003e9aae2e7a8a87812382c84a695614225e423aaf1676089dbbfe"
}
4. Cancel All Orders (DexCommandCancelAll - 0x23)
POST /api/v1/order/cancel/all
Transaction Data Structure:
data = [0x23][JSON(CancelAllContext)]
CancelAllContext Structure:
{
"l1owner": "0x1234567890123456789012345678901234567890"
}
CancelAllContext Fields:
| Field | Type | Mandatory | Description |
|---|---|---|---|
| l1owner | STRING | YES | Wallet address whose orders to cancel (master wallet address) |
Request Body:
{
"tx": "0x02f8730183...{full signed transaction hex}"
}
Response:
{
"code": 200,
"errMsg": "OK",
"result": "0x4c9980c4fd003e9aae2e7a8a87812382c84a695614225e423aaf1676089dbbfe"
}
5. Modify Order (DexCommandModify - 0x24)
POST /api/v1/order/modify
Important: Modify operates as a "cancel and replace" mechanism. The original order is canceled and a new order is created with the modified parameters. The new order ID will be the transaction hash of the modify transaction.
Transaction Data Structure:
data = [0x24][JSON(ModifyContext)]
ModifyContext Structure:
{
"l1owner": "0x1234567890123456789012345678901234567890",
"orderId": "0x4bed76ae0c75b1d1d0b291873ad7fb58b0986955ae0d49ca642a0f8c48efbae5",
"newPrice": "2.35", // New price (null to keep current)
"newQty": "20.0" // New quantity (null to keep current)
}
ModifyContext Fields:
| Field | Type | Mandatory | Description |
|---|---|---|---|
| l1owner | STRING | YES | Wallet address that owns the order (master wallet address) |
| orderId | STRING | YES | Order ID to modify (original transaction hash) |
| newPrice | STRING | NO | New limit price (null to keep current) |
| newQty | STRING | NO | New quantity (null to keep current) |
Request Body:
{
"tx": "0x02f8730183...{full signed transaction hex}"
}
Response:
{
"code": 200,
"errMsg": "OK",
"result": "0x4c9980c4fd003e9aae2e7a8a87812382c84a695614225e423aaf1676089dbbfe"
}
6. Stop Order (DexCommandStopOrder - 0x25)
POST /api/v1/order/trigger
Transaction Data Structure:
data = [0x25][JSON(StopOrderContext)]
StopOrderContext Structure:
{
"l1owner": "0x1234567890123456789012345678901234567890",
"baseToken": "1",
"quoteToken": "2",
"stopPrice": "2.1", // Trigger price
"price": "2.09", // Limit price (0 for market order)
"quantity": "10.0", // Quantity
"side": 0, // 0: buy, 1: sell
"orderType": 0, // 0: limit, 1: market
"orderMode": 0 // 0: base mode, 1: quote mode
}
StopOrderContext Fields:
| Field | Type | Mandatory | Description |
|---|---|---|---|
| l1owner | STRING | YES | Wallet address placing the order (master wallet address) |
| baseToken | STRING | YES | Base token ID |
| quoteToken | STRING | YES | Quote token ID |
| stopPrice | STRING | YES | Price at which the stop order triggers |
| price | STRING | YES | Limit price after trigger ("0" for market) |
| quantity | STRING | YES | Order quantity |
| side | INT | YES | 0 for buy, 1 for sell |
| orderType | INT | YES | 0 for limit, 1 for market |
| orderMode | INT | YES | 0 for base mode, 1 for quote mode (quote mode only available for market orders) |
Request Body:
{
"tx": "0x02f8730183...{full signed transaction hex}"
}
Response:
{
"code": 200,
"errMsg": "OK",
"result": "0x4c9980c4fd003e9aae2e7a8a87812382c84a695614225e423aaf1676089dbbfe"
}
7. Transfer Assets (DexCommandTokenTransfer - 0x11)
POST /api/v1/wallet/transfer
Transaction Data Structure:
data = [0x11][JSON(TransferContext)]
TransferContext Structure:
{
"l1owner": "0x1234567890123456789012345678901234567890",
"to": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
"token": "2",
"value": "1000.0", // Amount
}
TransferContext Fields:
| Field | Type | Mandatory | Description |
|---|---|---|---|
| l1owner | STRING | YES | Wallet address initiating the transfer (master wallet address) |
| to | STRING | YES | Destination wallet address |
| token | STRING | YES | Token ID to transfer |
| value | STRING | YES | Amount to transfer |
Request Body:
{
"tx": "0x02f8730183...{full signed transaction hex}"
}
Response:
{
"code": 200,
"errMsg": "OK",
"result": "0x4c9980c4fd003e9aae2e7a8a87812382c84a695614225e423aaf1676089dbbfe"
}
Building and Signing Transactions
Fixed Contract Address
ALL transactions MUST be sent to:
0x00000000000000000000000000000000000000cc
Input Data Construction
The transaction's data field consists of:
- Command Byte (1 byte): Identifies the operation type
- JSON Data (remaining bytes): UTF-8 encoded JSON string with operation parameters
L2 Gas-Free Transactions
Important: The Kaia L2 DEX supports gas-free transactions, meaning:
- Gas Price: Set to
0(zero) for all transactions - Gas Limit: Use a sufficiently large arbitrary value (e.g.,
0x30000or196608) - Value: Always
0x0for DEX operations - Users don't need to hold native tokens for gas fees
Example: Building Order Transaction
// 1. Create OrderContext
const orderContext = {
l1owner: walletAddress,
baseToken: "1",
quoteToken: "2",
side: 0, // buy
price: "2.3",
quantity: "10.0",
orderType: 0, // limit
orderMode: 0 // base mode
};
// 2. Build transaction data
const commandByte = 0x21; // DexCommandOrder
const jsonData = JSON.stringify(orderContext);
const data = Buffer.concat([
Buffer.from([commandByte]),
Buffer.from(jsonData)
]);
// 3. Sign transaction (with gas-free parameters)
const tx = {
from: walletAddress,
to: MATCH_ENGINE_ADDRESS,
data: '0x' + data.toString('hex'),
value: '0x0', // Always 0 for DEX operations
gasLimit: '0x30000', // Arbitrary large value
gasPrice: '0x0', // Gas-free: set to 0
nonce: Date.now() // Can use timeNonce (Unix timestamp in ms) or sequential nonce
};
const signedTx = await web3.eth.accounts.signTransaction(tx, privateKey);
// 4. Send to API
const response = await fetch('/api/v1/order', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ tx: signedTx.rawTransaction })
});
Important Notes
-
Transaction Target: All order transactions must be sent to the Match Engine contract address
-
Order Mode:
- Base mode (0): Quantity specified in base token
- Quote mode (1): Quantity specified in quote token (only available for market orders, useful for market buy orders where you want to specify the amount in quote token)
-
Gas Estimation: Recommended gas limit is 0x30000 (196,608) for most operations
-
Nonce Management:
- Standard sequential nonces are supported
- TimeNonce Support: You can use Unix timestamp in milliseconds as the nonce value
- TimeNonce allows parallel transaction submission without nonce conflicts
- Example: Use
Date.now()(returns milliseconds) as the nonce value
-
TPSL Orders: Take Profit and Stop Loss can be attached to any limit order via the optional
tpslfield -
Null Values: In modify operations, set fields to null to keep current values unchanged