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

에이전트 인가

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

개요

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

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

두 가지 인가 모델

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

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

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

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

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

퍼프: API 월렛 (온체인)

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

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

이는 Hyperliquid의 API 월렛 모델을 따릅니다. Hyperliquid는 이를 API 월렛(에이전트 월렛이라고도 함)으로 Nonces and API wallets에 문서화하고 있으며, approveAgentExchange 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. 항목별 에이전트 인가 검사

인가 저장

에이전트 인가는 엔진 소유 상태입니다. ApproveAgentRevokeAgent 명령은 저널링되고, 엔진 리플레이를 통해 복원되며, 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=...를 통해 에이전트 상태를 확인하세요.