이 페이지는 자동 번역되었습니다. 영어 원문이 정본입니다. 영어로 읽기 →
메인 콘텐츠로 건너뛰기

에이전트 인가

마켓메이커를 위한 멀티키 서명 지원입니다.

개요​

에이전트 인가를 통해 전용 서명 키(에이전트)가 거래 지갑을 대신하여 주문을 제출하고 취소할 수 있습니다. 다음과 같은 경우에 유용합니다:

  • 보안: 거래 지갑 키는 콜드 스토리지에 보관하고, 서명에는 핫 키를 사용
  • 운영: 여러 팀원이 서로 다른 키로 서명 가능
  • 자동화: 자동화 시스템이 전용 키로 서명 가능

두 가지 인가 모델​

Hypercall에는 상품에 따라 두 가지 별도의 위임 시스템이 있습니다:

상품위임 유형저장 방식설정 방법
옵션 (REST API)에이전트 인가오프체인 (데이터베이스)POST /approve-agent
퍼프 (온체인 디렉티브)API 월렛온체인 (Exchange 컨트랙트)hc_update_api_wallet 디렉티브

이 두 시스템은 서로 독립적입니다. 옵션 거래용으로 에이전트를 승인해도 퍼프 거래에는 인가되지 않으며, 그 반대도 마찬가지입니다.

옵션: 에이전트 인가 (오프체인)​

에이전트는 거래 지갑을 대신하여 PlaceOrder 및 CancelOrder EIP-712 메시지에 서명합니다. API 서버는 엔진으로 전달하기 전에 데이터베이스에서 인가 여부를 검증합니다.

퍼프: API 월렛 (온체인)​

API 월렛은 HypercallApiSign EIP-712 도메인을 사용하여 퍼프 디렉티브에 서명합니다. Exchange 컨트랙트는 isApiWalletActive()를 통해 온체인에서 인가 여부를 검증합니다. 전체 디렉티브 서명 레퍼런스는 EIP-712 서명을 참조하세요.

API 월렛을 추가하거나 제거하려면 계정의 매니저 월렛이 서명한 hc_update_api_wallet 디렉티브를 제출하세요.

이는 Hyperliquid의 API 월렛 모델을 따릅니다. Hyperliquid는 이를 API 월렛(에이전트 월렛이라고도 함)으로 Nonces and API wallets에 문서화하고 있으며, approveAgent는 Exchange endpoint에 문서화되어 있습니다.

논스 재사용 방지​

논스 추적은 Hyperliquid 논스 모델을 따릅니다. 모든 서명된 액션(주문, 에이전트 승인/취소, QP 핸드셰이크)은 서명자별 논스 공간을 공유합니다. 엔진은 서명자 주소별로 상위 100개의 논스를 저장합니다. 새 논스는 다음 조건을 만족할 때 수락됩니다:

  1. nonce > min(stored_set) -- 저장된 논스 중 최솟값보다 커야 함
  2. !stored_set.contains(nonce) -- 중복이 아니어야 함
  3. nonce가 서버 타임스탬프 기준 (T - 2일, T + 1일) 범위 내여야 함

논스는 순서와 무관하게 허용됩니다(예: 논스 105 이후 102도 둘 다 세트 최솟값보다 크면 모두 유효합니다). 세트는 100개 항목으로 제한되므로 새 항목이 추가되면 가장 오래된 항목이 제거됩니다. 이를 통해 하나의 큰 논스로 인해 계정이 잠기는 것을 방지합니다.

논스 서명자는 EIP-712 메시지에 서명한 주소입니다: 주문의 경우 API 월렛, 에이전트 인가의 경우 복원된 서명자, 핸드셰이크의 경우 QP 월렛입니다. 클라이언트는 Date.now()(밀리초 단위 에포크)를 논스 시드로 사용하고 단조 증가시켜야 합니다.

옵션 에이전트 인가​

직접 서명​

signer == wallet인 경우, 주문은 항상 인가됩니다(자체 서명).

에이전트 서명​

signer != wallet인 경우, 서명자는 인가된 에이전트여야 합니다:

  • 에이전트가 엔진 소유 인가 상태에 존재해야 함
  • 인가가 만료되지 않았어야 함
  • 엔진 스냅샷과 엔진 저널이 재시작 시의 영구 복원 소스임

에이전트 승인​

엔드포인트: POST /approve-agent

요청: ApproveAgentRequest

{
"agent": "0x...",
"nonce": 1,
"signature": "0x..."
}

서명:

  • 지갑 소유자가 ApproveAgent 메시지에 서명
  • 지갑 주소는 복원된 서명에서 도출됨
  • 에이전트는 요청의 agent 필드임

EIP-712 구조체:

struct ApproveAgent {
address agent;
uint64 nonce;
}

응답: ApproveAgentResponse

{
"success": true,
"error": null
}

참고:

  • 에이전트 인가는 영구적입니다 (DB에 저장됨)
  • expires_at이 설정되지 않는 한 인가는 만료되지 않습니다 (아직 구현되지 않음)

에이전트 취소​

엔드포인트: DELETE /revoke-agent

요청: RevokeAgentRequest

{
"agent": "0x...",
"nonce": 2,
"signature": "0x..."
}

서명:

  • 지갑 소유자가 RevokeAgent 메시지에 서명
  • 지갑 주소는 복원된 서명에서 도출됨

EIP-712 구조체:

struct RevokeAgent {
address agent;
uint64 nonce;
}

응답: RevokeAgentResponse

참고:

  • 저널링된 RevokeAgent 명령을 엔진 소유 인가 상태에 적용합니다
  • 트레이딩 API 인가 검사는 백엔드 상태를 읽고 거래 요청에 대해 취소를 강제 적용합니다. 트롤박스 게시는 긍정적인 에이전트 인가를 더 오래 캐싱할 수 있으므로, 최근에 취소된 에이전트도 해당 캐시가 만료되거나 최선 노력(best-effort) 무효화가 관련 엣지 로케이션에 도달할 때까지 게시할 수 있습니다. 이 캐시는 트레이딩 API 변경 작업을 인가하지 않습니다.
  • 취소 후 에이전트는 더 이상 해당 지갑을 대신하여 서명할 수 없습니다

인가된 에이전트 조회​

엔드포인트: GET /authorized-agents?wallet=...

쿼리 파라미터:

  • wallet (필수)

응답:

{
"agents": [
"0x...",
"0x..."
]
}

참고:

  • 활성 상태이며 만료되지 않은 에이전트만 반환합니다
  • created_at DESC 순으로 정렬됩니다

에이전트 사용법​

에이전트로 주문 서명하기​

에이전트가 승인되면:

  1. 에이전트 월렛으로 주문 서명: 에이전트 월렛을 사용하여 PlaceOrder / CancelOrder 메시지에 서명
  2. wallet 필드 설정: wallet 필드를 거래 지갑 주소로 설정 (에이전트 주소가 아님)
  3. 미들웨어 검증: 미들웨어가 에이전트가 해당 지갑에 대해 인가되었는지 검증

예시:

// Agent wallet signs the order
const agentSigner = new ethers.Wallet(agentPrivateKey);

const message = {
wallet: "0x...", // Trading wallet (not agent)
symbol: "BTC-20250131-100000-C",
side: "Buy",
size: "0.1",
price: "100.0",
tif: "gtc",
clientId: "mm-1",
nonce: 1
};

// Sign with agent wallet
const signature = await agentSigner._signTypedData(domain, types, message);

// Send request
const response = await fetch('/order', {
method: 'POST',
body: JSON.stringify({
...message,
signature
})
});

에이전트를 통한 대량 주문​

대량 주문 엔드포인트는 항목별로 에이전트 인가를 검증합니다:

  • POST /bulk_order의 각 주문은 서로 다른 에이전트가 서명할 수 있음
  • 에이전트 인가는 항목별로 검사됨
  • 어떤 항목이 에이전트 인가에 실패하면, 해당 항목은 BulkOrderResult에서 오류를 반환함

인가 검사​

미들웨어 (단일 주문)​

엔드포인트:

  • POST /order
  • DELETE /order
  • DELETE /order_cloid

검사: signature_and_agent_middleware가 다음을 검증합니다:

  1. 서명 복원 성공
  2. 서명자가 인가됨 (signer == wallet 또는 에이전트가 인가됨)

핸들러 (대량 주문)​

엔드포인트:

  • POST /bulk_order
  • DELETE /bulk_order
  • DELETE /bulk_order_cloid

검사: 핸들러에서 항목별 검증:

  1. 항목별 서명 복원
  2. 항목별 에이전트 인가 검사

인가 저장​

에이전트 인가는 엔진 소유 상태입니다. ApproveAgent 및 RevokeAgent 명령은 저널링되고, 엔진 리플레이를 통해 복원되며, API 검사를 위해 읽기 스냅샷을 통해 노출됩니다.

인가 로직​

서명자 인가는 명시적인 OR 로직입니다:

  • 직접 서명: signer == wallet.
  • 에이전트 서명: 엔진 스냅샷에 wallet_address == <wallet> 및 agent_address == <signer>에 대한 인가 레코드가 존재하고, expires_at이 없거나 미래 시점인 경우.

만료​

expires_at은 엔진 스냅샷 인가 검사에서 강제 적용됩니다. expires_at < NOW()인 에이전트는 인가되지 않은 것으로 처리됩니다.

보안 고려사항​

  1. 에이전트 키 보안: 에이전트 개인 키를 보호하세요 (하드웨어 지갑 또는 안전한 키 관리 시스템 사용)
  2. 정기 감사: GET /authorized-agents를 통해 인가된 에이전트를 정기적으로 검토하세요
  3. 미사용 에이전트 취소: 더 이상 필요하지 않은 에이전트는 취소하세요
  4. 만료 설정: 승인 경로가 기본값이 아닌 만료 시간을 지원하는 경우, 임시 에이전트 인가에 expires_at을 사용하세요

모범 사례​

  1. 자동화에 에이전트 사용: 거래 지갑 키는 콜드 스토리지에 보관하고, 자동화 시스템에는 에이전트를 사용하세요
  2. 에이전트 범위 제한: 접근이 필요한 에이전트만 승인하세요
  3. 에이전트 사용 모니터링: 어떤 에이전트가 주문을 제출하는지 추적하세요
  4. 신속한 취소: 더 이상 필요하지 않은 에이전트는 즉시 취소하세요

일반적인 문제​

"Unauthorized: signer not authorized for wallet"​

원인: 에이전트가 승인되지 않았거나 인가가 만료/취소되었습니다.

해결: POST /approve-agent를 통해 에이전트를 승인하거나 지갑으로 직접 서명하세요.

에이전트 인가가 작동하지 않는 경우​

원인:

  • 에이전트가 엔진 소유 인가 상태에 존재하지 않음
  • 인가가 취소됨
  • 인가가 만료됨

해결: GET /authorized-agents?wallet=...를 통해 에이전트 상태를 확인하세요.