Spot Authentication
Two Signing Models¶
Spot Aster Code uses two distinct signing models depending on the endpoint type.
Model 1 — Main Wallet Signing (Management Endpoints)¶
Applies to:
POST /api/v3/approveBuilderPOST /api/v3/updateBuilderDELETE /api/v3/delBuilder
Signer: User's main wallet (no signer field in request)
Signature scheme: EIP-712 with a dynamic primaryType specific to each operation (e.g., ApproveBuilder, UpdateBuilder, DelBuilder).
Request includes: user, nonce, signature, signatureChainId, and endpoint-specific business parameters.
Request does NOT include: signer
EIP-712 Domain:
const domain = {
name: "AsterSignTransaction",
version: "1",
chainId: signatureChainId, // value from request parameter
verifyingContract: "0x0000000000000000000000000000000000000000",
};
Warning: The
chainIdin the domain must equal thesignatureChainIdparameter sent in the request. Do not use theMessage.msgchain IDs (1666 / 714) for management requests unless they happen to match the requiredsignatureChainIdfor your environment.
Typed data field names use Title Case (first letter uppercased), while request parameter names use camelCase. For example:
| Request parameter | Typed data field |
|---|---|
builder |
Builder |
maxFeeRate |
MaxFeeRate |
builderName |
BuilderName |
asterChain |
AsterChain |
user |
User |
nonce |
Nonce |
Model 2 — Agent / API Wallet Signing (Trading & Query Endpoints)¶
Applies to:
GET /api/v3/builderPOST /api/v3/order
Signer: Authorized API Wallet / Agent (the signer address whose private key is held by the Builder backend)
Signature scheme: EIP-712 fixed Message type, signing only the msg field.
EIP-712 Domain:
const domain = {
name: "AsterSignTransaction",
version: "1",
chainId: 1666, // mainnet; use 714 for testnet
verifyingContract: "0x0000000000000000000000000000000000000000",
};
Types:
const types = {
Message: [
{ name: "msg", type: "string" }
]
};
The msg value is the exact query string of the request (excluding signature), assembled in the same parameter order as the actual HTTP request.
// Example for GET /api/v3/builder:
const msg = `user=${user}&signer=${signer}&nonce=${nonce}`;
const value = { msg };
const signature = await signer.signTypedData(domain, types, value);
// Append: &signature=<signature>
Key rule: The signed string must match the actual request query string byte-for-byte, excluding only the
signatureparameter. Any difference in parameter order or encoding will cause signature verification to fail.
Signing Model Summary¶
| Endpoint | Signer | PrimaryType | chainId in domain |
|---|---|---|---|
POST /api/v3/approveBuilder |
User main wallet | ApproveBuilder |
signatureChainId |
POST /api/v3/updateBuilder |
User main wallet | UpdateBuilder |
signatureChainId |
DELETE /api/v3/delBuilder |
User main wallet | DelBuilder |
signatureChainId |
GET /api/v3/builder |
API Wallet / Agent | Message |
1666 (mainnet) / 714 (testnet) |
POST /api/v3/order |
API Wallet / Agent | Message |
1666 (mainnet) / 714 (testnet) |
EIP-712 Typed Data Structures¶
ApproveBuilder¶
const types = {
ApproveBuilder: [
{ name: "Builder", type: "string" },
{ name: "MaxFeeRate", type: "string" },
{ name: "BuilderName", type: "string" },
{ name: "AsterChain", type: "string" },
{ name: "User", type: "string" },
{ name: "Nonce", type: "uint256" },
]
};
UpdateBuilder¶
const types = {
UpdateBuilder: [
{ name: "Builder", type: "string" },
{ name: "MaxFeeRate", type: "string" },
{ name: "AsterChain", type: "string" },
{ name: "User", type: "string" },
{ name: "Nonce", type: "uint256" },
]
};
DelBuilder¶
const types = {
DelBuilder: [
{ name: "Builder", type: "string" },
{ name: "AsterChain", type: "string" },
{ name: "User", type: "string" },
{ name: "Nonce", type: "uint256" },
]
};
Message (for GET /api/v3/builder and POST /api/v3/order)¶
const types = {
Message: [
{ name: "msg", type: "string" }
]
};