> For the complete documentation index, see [llms.txt](https://docs.ticko.xyz/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.ticko.xyz/api-documentation/authentication/signing.md).

# Signing

Signed write requests use EIP-712. The client builds the endpoint-specific signing payload, signs the resulting `signing_hash` with the private key for `signer_address`, and sends the ECDSA signature in the HTTP request body.

There are two signing types:

| Signing type   | Used for                                                                        | Allowed signer                                  | What gets signed                                                                                                            |
| -------------- | ------------------------------------------------------------------------------- | ----------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| Signing Type A | Orders and trading-related account settings                                     | User wallet private key or authorized Agent key | Endpoint business fields are canonicalized into `actionHash`, then `actionHash` is signed inside an EIP-712 `Agent` struct. |
| Signing Type B | Funds operations, Agent key management, and wallet-authority account operations | User wallet private key only                    | The endpoint-specific EIP-712 struct is signed directly.                                                                    |

Each signed POST endpoint specifies `Authentication: Signing Type A` or `Authentication: Signing Type B`. Use that signing type for that endpoint. Both signing types use the same EIP-712 hashing and field-encoding rules for `domainSeparator`, `typeHash`, `structHash`, and final `signing_hash`; those shared rules are defined in [Shared EIP-712 Hashing And Encoding](#shared-eip-712-hashing-and-encoding).

In the steps below, "endpoint business fields" means the operation parameters documented in that endpoint's request table. For example, the business fields for `POST /v1/trade/orders` include `symbol_id`, `is_buy`, `order_type`, `quantity`, and other order parameters. They do not include the signing envelope fields.

## Signing Type A: ActionHash

Signing Type A is used by order endpoints and trading-setting endpoints. A Type A request body contains the endpoint business fields plus the Type A signing envelope:

```
endpoint business fields + Type A signing envelope
```

Type A signing envelope fields:

| Field            | Type    | Required in final request | Description                                                                          |
| ---------------- | ------- | ------------------------- | ------------------------------------------------------------------------------------ |
| `signer_address` | string  | Yes                       | Wallet or Agent key address signing the request.                                     |
| `target_address` | string  | No                        | Account the request operates on. If omitted, the target account is `signer_address`. |
| `nonce`          | integer | Yes                       | Millisecond timestamp nonce.                                                         |
| `expires_after`  | integer | Yes                       | Millisecond timestamp after which the request expires.                               |
| `signature`      | object  | Yes                       | ECDSA signature object `{ r, s, v }`, added after signing.                           |

Type A action tags:

| Tag | Action            | Endpoint                             |
| --: | ----------------- | ------------------------------------ |
|   7 | `PlaceOrder`      | `POST /v1/trade/orders`              |
|   8 | `CancelOrder`     | `POST /v1/trade/orders/cancel`       |
|   9 | `CancelAll`       | `POST /v1/trade/orders/cancel-all`   |
|  10 | `SetPositionMode` | `POST /v1/account/position-mode`     |
|  11 | `SetLeverage`     | `POST /v1/account/leverage`          |
|  12 | `ModifyOrder`     | `POST /v1/trade/orders/modify`       |
|  13 | `ChaseOrder`      | `POST /v1/trade/orders/chase`        |
|  15 | `UpdateMargin`    | `POST /v1/account/isolated-margin`   |
|  16 | `BatchCancel`     | `POST /v1/trade/orders/batch/cancel` |
|  17 | `BatchOrder`      | `POST /v1/trade/orders/batch`        |
|  18 | `BatchModify`     | `POST /v1/trade/orders/batch/modify` |

When computing the signature, start from the unsigned request body before `signature` is added.

{% stepper %}
{% step %}

### Start with business fields

Start with the endpoint's documented business fields as `business_fields`.
{% endstep %}

{% step %}

### Build canonical JSON

Build `canonical_json = canonicalJson(business_fields)`:

* Remove omitted optional fields and optional fields sent as `null`.
* Sort object keys alphabetically at every object level.
* Preserve array order.
* Serialize as compact JSON with no spaces, newlines, or indentation.
  {% endstep %}

{% step %}

### Look up the action tag

Look up the endpoint's `action_tag` from Type A action tags.
{% endstep %}

{% step %}

### Compute actionHash

`actionHash = keccak256(concat(uint8(action_tag), utf8_bytes(canonical_json)))`
{% endstep %}

{% step %}

### Build the EIP-712 domain

```
domain = {
  name: "Ticko",
  version: "1",
  chainId: 84256 for mainnet, 84257 for testnet,
  verifyingContract: "0x0000000000000000000000000000000000000000"
}
```

{% endstep %}

{% step %}

### Build the Agent message

This defines `encodeType` and `messageFields`.

If `target_address` is present:

```
encodeType = "Agent(address signerAddress,address targetAddress,bytes32 actionHash,uint64 nonce,uint64 expiresAfter)"
messageFields = [
  signerAddress = signer_address,
  targetAddress = target_address,
  actionHash = actionHash,
  nonce = nonce,
  expiresAfter = expires_after
]
```

If `target_address` is omitted:

```
encodeType = "Agent(address signerAddress,bytes32 actionHash,uint64 nonce,uint64 expiresAfter)"
messageFields = [
  signerAddress = signer_address,
  actionHash = actionHash,
  nonce = nonce,
  expiresAfter = expires_after
]
```

{% endstep %}

{% step %}

### Produce signing\_hash

Pass `domain`, `encodeType`, and `messageFields` into [Shared EIP-712 Hashing And Encoding](#shared-eip-712-hashing-and-encoding) to produce `signing_hash`.
{% endstep %}

{% step %}

### Sign

Sign `signing_hash` with the private key for `signer_address`: `(v, r, s) = ecdsaSign(signing_hash, privateKey)`.
{% endstep %}

{% step %}

### Submit

Submit the same request body with `signature: { r, s, v }` added.
{% endstep %}
{% endstepper %}

## Signing Type B: Direct Typed Data

Signing Type B is used by endpoints that require wallet authority: funds operations, Agent key management, and sub-account creation. A Type B request body contains the endpoint business fields plus the Type B signing envelope:

```
endpoint business fields + Type B signing envelope
```

Type B signs an endpoint-specific EIP-712 struct directly. It does not build `canonical_json` and does not compute `actionHash`.

Type B signing envelope fields:

| Field                | Type    | Required in final request | Description                                                          |
| -------------------- | ------- | ------------------------- | -------------------------------------------------------------------- |
| `ticko_chain`        | string  | Yes                       | Ticko business environment. Allowed values: `Mainnet`, `Testnet`.    |
| `signature_chain_id` | integer | Yes                       | EIP-712 domain chain ID. Currently only `1` (Ethereum) is supported. |
| `signer_address`     | string  | Yes                       | Wallet address signing the request.                                  |
| `nonce`              | integer | Yes                       | Millisecond timestamp nonce.                                         |
| `expires_after`      | integer | Yes                       | Millisecond timestamp after which the request expires.               |
| `signature`          | object  | Yes                       | ECDSA signature object `{ r, s, v }`, added after signing.           |

Type B operation structs:

| Endpoint                         | EIP-712 type                                                                                                                                                          |
| -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `POST /v1/account/approve-agent` | `ApproveAgent(address signerAddress,string tickoChain,address agentAddress,address authorizedAddress,uint32 validDays,string label,uint64 nonce,uint64 expiresAfter)` |
| `POST /v1/account/revoke-agent`  | `RevokeAgent(address signerAddress,string tickoChain,address agentAddress,uint64 nonce,uint64 expiresAfter)`                                                          |
| `POST /v1/account/renew-agent`   | `RenewAgent(address signerAddress,string tickoChain,address agentAddress,uint32 validDays,uint64 nonce,uint64 expiresAfter)`                                          |
| `POST /v1/account/create-sub`    | `CreateSubAccount(address signerAddress,string tickoChain,string label,uint64 nonce,uint64 expiresAfter)`                                                             |
| `POST /v1/account/transfer`      | `Transfer(address signerAddress,string tickoChain,address fromAddress,uint32 coinId,string amount,address toAddress,uint64 nonce,uint64 expiresAfter)`                |
| `POST /v1/account/withdraw`      | `Withdraw(address signerAddress,string tickoChain,uint32 coinId,string amount,uint64 chainId,address toAddress,uint64 nonce,uint64 expiresAfter)`                     |

When computing the signature, start from the unsigned request body before `signature` is added.

{% stepper %}
{% step %}

### Choose the encodeType

Set `encodeType` to the endpoint's EIP-712 type from Type B operation structs.
{% endstep %}

{% step %}

### Build messageFields

Build `messageFields` in the exact field order declared by `encodeType`:

* Signing envelope fields map to EIP-712 fields as `signer_address` -> `signerAddress`, `ticko_chain` -> `tickoChain`, `nonce` -> `nonce`, and `expires_after` -> `expiresAfter`.
* Endpoint business fields map to the matching `camelCase` EIP-712 fields, for example `agent_address` -> `agentAddress`, `valid_days` -> `validDays`, and `chain_id` -> `chainId`.
  {% endstep %}

{% step %}

### Build the EIP-712 domain

Type B currently supports only Ethereum mainnet `signature_chain_id = 1`. Note that `signature_chain_id` is used only for the EIP-712 domain check and must be `1`. It is not a field in `messageFields`.

```
domain = {
  name: "Ticko",
  version: "1",
  chainId: 1,
  verifyingContract: "0x0000000000000000000000000000000000000000"
}
```

{% endstep %}

{% step %}

### Produce signing\_hash

Pass `domain`, `encodeType`, and `messageFields` into [Shared EIP-712 Hashing And Encoding](#shared-eip-712-hashing-and-encoding) to produce `signing_hash`.
{% endstep %}

{% step %}

### Sign

Sign `signing_hash` with the wallet private key for `signer_address`: `(v, r, s) = ecdsaSign(signing_hash, privateKey)`.
{% endstep %}

{% step %}

### Submit

Submit the same request body with `signature: { r, s, v }` added.
{% endstep %}
{% endstepper %}

## Shared EIP-712 Hashing And Encoding

This section takes the EIP-712 inputs prepared by Signing Type A or Signing Type B and returns `signing_hash`. Type A and Type B decide which `encodeType` and message fields to use; this section defines how those inputs are encoded and hashed.

Inputs:

| Input                      | Signing Type A                                                             | Signing Type B                                                                           |
| -------------------------- | -------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| `domain.name`              | `Ticko`                                                                    | `Ticko`                                                                                  |
| `domain.version`           | `1`                                                                        | `1`                                                                                      |
| `domain.chainId`           | `84256` on mainnet, `84257` on testnet                                     | `1`; HTTP `signature_chain_id` must be `1`                                               |
| `domain.verifyingContract` | `0x0000000000000000000000000000000000000000`                               | `0x0000000000000000000000000000000000000000`                                             |
| `encodeType`               | The `Agent(...)` type selected by whether `target_address` is present      | The full EIP-712 type string from the endpoint row in the Type B operation structs table |
| `messageFields`            | The `Agent` field values shown in the Type A branch, in `encodeType` order | The EIP-712 message fields built from the Type B operation struct, in `encodeType` order |

The HTTP `signature` object is not an input. It is added only after `signing_hash` is signed.

{% stepper %}
{% step %}

### Domain separator

```
domainType = "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"

domainSeparator = keccak256(concat(
  keccak256(utf8_bytes(domainType)),
  keccak256(utf8_bytes(domain.name)),
  keccak256(utf8_bytes(domain.version)),
  pad32(domain.chainId),
  pad32(domain.verifyingContract)
))
```

Field encoding:

| Type          | Encoding                                |
| ------------- | --------------------------------------- |
| `address`     | 20-byte address left-padded to 32 bytes |
| `bytes32`     | Raw 32 bytes                            |
| `uint32`      | `uint32` value left-padded to 32 bytes  |
| `uint64`      | `uint64` value left-padded to 32 bytes  |
| `string`      | `keccak256(utf8_bytes(value))`          |
| {% endstep %} |                                         |

{% step %}

### Struct hash

```
typeHash = keccak256(utf8_bytes(encodeType))

encodedFields = [
  encode(message_field_1),
  encode(message_field_2),
  ...
]

structHash = keccak256(concat(
  typeHash,
  encodedFields[0],
  encodedFields[1],
  ...
))
```

Encode message fields in exactly the order shown by `encodeType`. For Type A, the Type A section gives the exact `encodeType` and field list for both cases: `target_address` present and `target_address` omitted. For Type B, `encodeType` is the endpoint operation struct, such as `ApproveAgent(...)` or `Transfer(...)`.
{% endstep %}

{% step %}

### Signing hash

```
signing_hash = keccak256(concat(
  "\x19\x01",
  domainSeparator,
  structHash
))
```

Output: `signing_hash`. This is the value signed by ECDSA and is also the on-chain transaction hash (`tx_hash`).
{% endstep %}
{% endstepper %}

## Nonce And Expiry

* Nonces are tracked per `signer_address`.
* Each nonce must be unused.
* Each nonce must be within `(block_time - 2 days, block_time + 1 day)`.
* Concurrent requests must use different nonces.
* `expires_after` must be greater than the block time when the request is checked.


---

# 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 dynamically by asking a question.

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

```
GET https://docs.ticko.xyz/api-documentation/authentication/signing.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
