MAPAE

에이전트 결제의
권한 레이어

실명이 검증된 사람이 소프트웨어에 범위를 정해 지출 권한을 넘긴다. 범위는 결제 순간마다 컨트랙트가 강제하고, 취소는 즉시 반영되며, 사고는 실명까지 역추적된다.

기술 문서 · 2026.07 GIWA Sepolia · 91342 Solidity 0.8.29 github.com/GrapeInTheTree/mapae

01요약

x402로 에이전트가 스스로 결제하는 경로는 이미 열렸다. 막힌 것은 권한을 넘기는 방법이다. 지금 선택지는 개인키를 통째로 주거나(한도·수취인·기한을 걸 수 없다) 수탁 서비스를 믿는 것 둘뿐이다.

마패는 세 번째 길이다. 위임 메커니즘 자체는 발명하지 않았다 — ERC-7710/7715와 x402를 채택하고, 어디에도 없던 조건 하나를 기여한다: 위임자의 신원.

컨트랙트8GIWA Sepolia 배포 · 전수 소스 검증
테스트153포크·불변식·3언어 바이트 패리티 포함, 정적 분석 심각·중대 0
라이브 트랜잭션20+정상 결제와 모든 거부 유형, 사유가 디코딩된 채로
백엔드 서버0권한의 유효성은 체인만 답한다

02문제

에이전트에게 결제를 맡기는 현재의 방법은 둘 다 같은 결함을 공유한다. 범위가 없다. 개인키를 넘기면 에이전트가 곧 지갑이 되고, 수탁에 맡기면 온체인 결제를 하려고 다시 중개인을 세우는 셈이다.

2026년 2월 — OpenClaw 프레임워크로 만든 트레이딩 에이전트가 요청 금액을 잘못 읽어 보유 토큰 5,243만 개(당시 약 25만 달러) 전량을 전송했다. 해킹도 컨트랙트 취약점도 아니었다. 에이전트의 오해 하나였다. 한도가 사람의 서명에 고정되어 있었다면, 에이전트가 오해해도 그 이상은 이동할 수 없다.

그리고 한도만으로는 부족하다. 사고가 났을 때 누가 이 권한을 줬는지가 남지 않으면 책임 주체를 특정할 수 없고, 가맹점은 에이전트 결제를 받을 이유가 없다. 이 마지막 조각이 기와에만 있다 — 다른 체인에는 조건으로 걸 신원 자체가 없다.

03아키텍처

사람 (EOA)도장 보유
조건을 서명
서명
마패오프체인 위임장
가스 0 · 트랜잭션 0
전달
에이전트범위 안에서
자율 결제
도장 (DojangScroll)결제 시점 liveness 조회
조회
위임 매니저서명·사슬·조건 전수 검사
실행
계정 (자금)owner immutable
조건 4종이 매니저에서 평가된다 — 신원 · 기간 한도 · 수취인 · 기한. 하나라도 실패하면 결제가 통째로 거부된다.
컨트랙트역할
MapaeDelegationManagerERC-7710 위임 실행. 서명·사슬·비활성 검사 후 조건을 평가하고, 통과해야만 계정에 실행을 위임
MapaeAccount자금과 위임 상태를 보유. owner는 immutable
MapaeAccountFactoryCREATE2 배포 + 소유자 동의 서명(EIP-712) 검증 + 등록부
DojangVerifiedEnforcer기여물. 위임자의 실명 증명을 결제 조건으로 건다
AllowedPayeeEnforcer이체 calldata의 수취인을 검사 — 타겟이 아니라
ERC20PeriodTransferEnforcer
TimestampEnforcer
MetaMask 감사본을 무수정 vendoring — 호환성의 실증
VerifiedCodeEnforcer사람 확인 티어. 살아 있는 오프체인 확인이 있을 때만 통과

04신원과 자금의 분리

도장은 컨트랙트에 붙지 않는다. 거래소는 KYC를 통과한 사람의 지갑 주소에 발급하지, 방금 배포된 컨트랙트에 발급하지 않는다. 그래서 위임자 주소를 그대로 검증하도록 설계하면 프로덕션에서 도장이 없고, 데모는 자기 발급 attestation으로만 통과한다 — 논지가 무너진다.

그래서 주소를 둘로 나눴다. 자금과 위임 상태는 계정이, 신원은 그 계정의 소유자인 사람이 가진다. 조건은 계정이 아니라 owner를 평가한다.

이 분리는 위조 경로를 하나 연다. 아무나 컨트랙트를 배포해 owner()가 남의 검증된 주소를 가리키게 만들 수 있다 — 훔치는 것은 없지만 책임 사슬을 위조하는 것이며, 그 사슬이 이 시스템이 보증하는 전부다. 두 겹으로 막는다.

① 계정 생성에 소유자 본인의 EIP-712 동의 서명을 요구한다

팩토리가 서명을 검증하고 등록한다. 동의 없이는 그 주소를 owner로 하는 계정이 존재할 수 없다.

② 조건은 등록 여부를 먼저 확인한 뒤에만 owner()를 신뢰한다

등록되지 않은 컨트랙트의 owner()는 공격자가 정하는 값이다. 순서가 뒤바뀌면 방어가 무의미해진다.

부수 효과로 리스크 하나가 소멸한다 — 소유자 EOA가 도장을 직접 발급받으므로 "컨트랙트가 attestation을 받을 수 있는가"라는 가정 자체가 불필요해진다.

05결제가 지나는 경로

에이전트가 매니저에 redeemDelegations 호출
배열 길이 → 호출자가 말단 delegate인가 → 사슬의 모든 서명(EOA는 ECDSA, 계정은 ERC-1271) → 비활성 플래그와 authority 연결
조건 평가: beforeAllbefore말단에서 뿌리 방향으로
실행은 뿌리 위임자의 계정에서 (ERC-7579 단일 실행)
afterafterAll을 뿌리에서 말단 방향으로
검증이 조건보다 항상 먼저 온다. 이 순서는 가정이 아니라 테스트로 고정돼 있어서, 두 킬스위치가 동시에 걸렸을 때 어떤 에러가 나는지가 결정적이다. 배치는 원자적이다 — 2건 중 2번째가 실패하면 1번째도 롤백된다.

06조건 — 무엇을 서명하나

조건은 {enforcer, terms, args}다. terms위임자가 서명하고, args는 사용 시점에 사용자가 낸다. 위임 해시는 signatureargs를 제외하고 계산되므로, 사용자가 낸 값이 서명을 바꿀 수 없다.

terms는 전부 고정 오프셋으로 tightly-pack되며, 길이가 틀리면 잘라내는 게 아니라 revert한다. 조건들은 논리곱이다 — 한도의 마지막 1원까지 쓸 수 있고, 1원도 넘을 수 없다.

조건길이레이아웃
신원52attesterId(32) ‖ principal(20)
기간 한도116token(20) ‖ periodAmount(32) ‖ periodDuration(32) ‖ startDate(32)
수취인20×N패킹된 주소 목록. 빈 목록은 전체 허용이 아니라 에러
기한32afterThreshold(uint128) ‖ beforeThreshold(uint128)

07기여물 — 신원 조건

배포된 위임 프레임워크들은 거의 모든 지출 조건을 이미 표현한다. 금액·기간·스트리밍· 타겟·메서드·calldata·시간 범위·호출 횟수. MetaMask 프레임워크 하나만 해도 감사된 조건이 38종이다.

그중 위임을 신원에 걸리게 하는 것은 없다 — 어떤 배포된 프레임워크에도, 어떤 체인에도. 조건으로 걸 온체인 신원이 없었기 때문이다.

설계 결정 넷

① 에이전트가 아니라 위임자의 신원을 건다

감사인·거래상대·보험사가 묻는 것은 "이 소프트웨어가 검증됐나"가 아니라 "어떤 실명이 이 지출을 허락했나"다.

② 발급자는 가정하지 않고 서명한다

발급자 식별자가 서명된 terms 안에 있다. 업비트로 범위가 정해진 위임은 자가 발급 attestation으로 만족될 수 없다 — 라이브로 증명됨. 발급자가 배포 상수가 아니라 서명 시점의 선택이라, 도장 생태계가 자랄수록 컨트랙트 변경 없이 넓어진다.

③ liveness는 캐시하지 않고 사용 시점에 읽는다

Dojang의 리졸버 자체가 "attestation은 사용 시점에 검증되어야 하며 인덱서는 liveness의 진실 소스가 아니다"라고 명시한다. 이 설계를 그대로 따랐고, 그래서 취소와 만료가 트랜잭션 없는 즉시 킬스위치가 된다.

④ boolean 조회 먼저, uid 조회는 나중

uid 게터는 미검증 주소에 revert한다. boolean 읽기가 부재·만료·취소를 전부 false로 접어주므로, 결제자는 항상 행동 가능한 에러 하나를 받는다.

이 컨트랙트는 무상태이고 실행 calldata를 파싱하지 않는다. 그래서 어떤 호출 형태와도 조합되고, 훅을 직접 불러 오염시킬 회계도 없다.

두 번째 빈칸 — 수취인 조건

작업 중에 격차가 하나 더 드러났다. 타겟 allowlist는 토큰 컨트랙트를 검사하는데, ERC-20 결제의 실제 수취인은 calldata 바이트 [4:36]에 있고 배포된 것 중 이걸 보는 게 없다. AllowedPayeeEnforcer"이 가맹점들에만 지불 가능"을 표현 가능하게 만든다.

08킬스위치 — 2×2 직교

두 개의 독립적인 스위치가 있고, 각각 되돌릴 수 있다.

도장 유효 · 위임 활성
결제 성공
도장 유효 · 위임 비활성
거부
위임 킬스위치가 단독으로 작동
도장 취소 · 위임 활성
거부
신원 킬스위치가 단독으로 작동
도장 취소 · 위임 비활성
거부
검증이 조건보다 먼저라 위임 쪽 에러가 결정적으로 나온다

각 축을 다른 축이 온전한 상태에서 시험했다. 도장이 살아 있는 채로 위임만 끄고, 위임이 켜진 채로 도장만 취소한다. 그래서 결과가 매니저의 체크 순서라는 가정에 의존하지 않는다. 되돌리는 것도 각각 증명했다 — 다시 켜면 쓰던 한도 그대로 재개되지, 리셋되지 않는다.

신원 스위치가 특별한 이유: 도장을 취소하면 그 사람이 발급한 모든 마패가 한 번에 멈춘다. 마패 컨트랙트를 건드리는 트랜잭션은 하나도 없이.

09재위임 — 좁히기만 가능

재위임은 ERC-7710의 일급 연산이다. 에이전트가 자기 권한의 일부를 다른 에이전트에게 넘길 수 있다. 사슬의 모든 링크의 조건이 평가되므로, 자식은 받은 것을 좁힐 수만 있고 넓힐 수 없다.

뿌리를 비활성화하면 상위에서 존재를 모르는 하위 에이전트까지 함께 정지한다. 이 성질을 지키는 것이 사슬 테스트 스위트의 존재 이유다.

10x402 정산

x402 v2의 exact 스킴은 EVM에서 세 가지 자산 이전 방식을 정의한다. 그중 둘은 토큰 레이어에서 승인하며, 그 승인은 nonce 한 번으로 소진된다. 세 번째 erc7710위임 매니저를 시뮬레이션해서 검증하며, 하나의 승인으로 여러 번 정산할 수 있는 유일한 방식이다.

마패는 이 세 번째 방식을 구현한다. 정산자는 정책도 자금도 갖지 않는다 — 모든 한도·수취인·기한·신원 검사가 온체인에서 돌고, 정산자의 키는 가스만 낸다. 이것은 우회가 아니라 설계 목표다. 정책 판정이 전부 온체인에 있으므로 정산자는 정책을 알 필요가 없고, 알 수도 없다.

GIWA에는 EIP-3009 토큰이 없어 다른 두 방식은 애초에 불가능하다. 라이브 증명에서는 같은 서명 payload로 정산이 두 번 일어나고, 세 번째는 브로드캐스트 전에 거부된다.

11에이전트 연동

npx mapae-mcp. MCP는 AI 에이전트에 외부 도구를 꽂는 표준 규격이고, 마패는 이 규격의 서버로 npm에 배포되어 있다. 클로드 코드·코덱스 같은 에이전트에 설치 한 줄이면 붙고, 그다음부터는 전부 자연어다.

도구하는 일
list_permissions보유한 마패 목록과 각각의 조건
check_budget이번 기간의 사용액과 잔여 한도
pay결제 — 수취인·토큰은 서명된 정책에서 나온다
agent_status에이전트 주소·가스 잔량·남은 결제 여력
request_permission사람에게 보낼 권한 요청 링크 생성 (ERC-7715)
load_context발급받은 마패를 대화 안에서 바로 장착
redelegate더 좁은 범위로만 재위임
발급과 취소 도구는 일부러 없다. 그 권한은 사람의 서명에만 속하고, 온체인에서도 위임자만 할 수 있다. 그리고 결제의 수취인과 토큰은 인자가 아니라 서명된 정책에서 나온다 — 프롬프트 인젝션으로 에이전트를 속여도 엉뚱한 주소로 보낼 수 없다. 에이전트 키는 첫 실행 때 로컬에서 생성되어 밖으로 나가지 않는다.

12제품

익스플로러는 정적 SPA다. 서버가 없다 — 브라우저가 GIWA를 직접 읽는다. 세 화면이 있다.

발급

조건을 조합하고 자기 언어의 한 문장으로 읽은 뒤 서명한다. 가스 0, 트랜잭션 0. 문장과 바이트가 같은 구조에서 생성되므로, 읽은 것과 서명한 것이 어긋날 수 없다 — 코덱이 서로의 역함수임을 테스트가 강제한다.

권한 관리

발급한 것, 한도 대비 쓴 것, 그리고 끄는 스위치. 발급 사실은 브라우저가, 일어난 일은 매 마운트마다 체인이 답한다. 어긋나면 체인이 이기고, UI가 어느 쪽인지 말한다.

추적

결제 해시를 넣으면 위임 사슬 전체를 조건과 함께 펼친다.

블록 익스플로러와 다른 점 둘. 거부가 일급이다 — 거부된 결제에는 로그가 없으므로 위임을 calldata에서 복원하고, 블록 직전 상태에 재생해 거부 사유를 되살린다. 그리고 시제가 정직하다 — 당시엔 유효했던 결제는 두 사실을 다 보여준다. 게이트 이벤트가 증명하는 그때의 유효함과, 라이브 조회가 말하는 지금의 취소됨.

13검증

테스트 153개 전부 통과. 층위별로 무엇을 증명하는지가 개수보다 중요하다.

개수증명하는 것
포크 테스트10실제 도장 배포본 상대로 — 진짜 업비트 KYC 주소가 통과하고, 발급자가 구별되고, 취소·만료가 즉시 닫힌다
인코딩 적합성16타입해시, 해시 제외 필드, ERC-7579 모드워드 — 리터럴 상수로 고정, 재계산 금지
위임 사슬16자식이 부모 한도를 넓힐 수 없음, 위조 접합 거부, 뿌리 차단이 하위까지 관통
매니저 API16킬스위치 권한, 잘못된 배치, 훅 재진입 불가, 훅 순서 고정
Enforcer · 계정77위조 경로, 실행 형태 거부, 팩토리 동의 바인딩
통합13전 구간 시나리오, 배치 원자성, 2×2 킬스위치 행렬
불변식51000회 × 256콜. 독립 유령 원장 대비 — 신원이 죽으면 결제 없음, 한도 유지, 토큰 보존
3언어 바이트 패리티31같은 위임을 Solidity·TypeScript·Go가 각각 인코딩해 바이트 단위로 일치
정적 분석0 / 0Slither 심각·중대 0. 예외 5건은 전부 근거 주석과 함께
소스 검증8 / 8Blockscout API의 검증 플래그를 직접 읽는다
마지막 항목이 사소해 보이지만 아니다. 테스트 토큰은 익스플로러에 소스가 보이고 검증 도구도 "이미 검증됨"이라 답했는데 API는 false였다 — Blockscout이 바이트코드가 같은 남의 주소에서 소스를 빌려 보여주고 있었다. 지금은 자기 자격으로 검증되어 있다.

검증이 실제로 잡은 버그

  • 모드워드 패킹 오류가 실행 형태 가드 둘을 조용히 무력화하고 있었다. all-zero 테스트가 공허하게 통과하는 동안 숨어 있다가 비-zero 왕복에 걸렸다.
  • 빌드 설정 하나가 아무것도 브로드캐스트하지 않으면서 배포 성공을 보고했다. 체인에서 코드를 되읽어 발견했다.
  • 계정 생성 서명이 잘 만들어졌는데 온체인에서 거부됐다. 팩토리의 EIP-712 다이제스트가 아니라 EIP-191로 서명하고 있었다.

14만들지 않은 것

지갑기와 월렛의 자리다. ERC-7715 요청 경로를 미리 구현해 두었다 — 월렛이 표준을 켜면 통합이 아니라 스위치다
스테이블코인원화 스테이블이 나오면 주소만 바꾼다. 테스트 토큰은 어떤 표준 확장도 일부러 구현하지 않은 맨몸 ERC-20이고, 그 위에서 전부 동작한 것이 자산 불가지론의 증명이다
위임 표준발명하지 않고 채택했다. 감사된 조건들이 무수정으로 우리 매니저에서 돌고, 우리 신원 조건도 그들 매니저에 꽂힌다
온체인 레지스트리발급 시점 저장을 강요하면 "발급은 오프체인 서명, 트랜잭션 없음"이라는 모델이 깨진다. 게이트 이벤트 한 줄이 역추적 고리를 닫는다
ERC-8004퍼미션리스 자가 등록은 책임 사슬에 아무것도 보태지 않는다. 에이전트 신원은 기와 방식으로 — 검증된 코드 조건으로
자체 백엔드권한이 유효한지는 체인만 답해야 한다. 조회를 빠르게 할 인덱서는 로드맵에 있지만, 그것은 가공과 캐시이지 진실의 원본이 아니다

15신뢰 가정과 위협 모델

이 시스템이 무엇을 신뢰하고 무엇을 신뢰하지 않는지를 명시한다. 신뢰 경계를 적지 않은 보안 주장은 검증할 수 없다.

신뢰하는 것

대상가정
도장 발급자거래소가 실명 확인을 정확히 수행하고, 취소 사유가 생기면 취소한다. 마패는 발급 정확성을 검증하지 않는다 — 다만 어떤 발급자를 믿을지는 위임자가 서명으로 고른다
EAS · DojangScrollattestation의 만료·취소 상태를 정확히 반영한다. 조건은 이 값을 매 결제마다 읽는다
체인GIWA의 합의와 재구성 내성. 이 문서의 모든 강제는 온체인 실행에 의존한다
vendoring한 코드기간 한도·기한 조건은 MetaMask 감사본을 무수정으로 쓴다. 감사 결과를 신뢰하되, 실제 실행은 우리 테스트가 재확인한다

신뢰하지 않는 것

대상이유와 방어
에이전트침해되었다고 가정한다. 서명된 조건 밖으로는 지출할 수 없고, 수취인은 인자가 아니라 정책에서 나온다. 에이전트 키 유출의 최대 피해는 남은 한도까지, 허용된 수취인에게
정산자 (x402)정책도 자금도 갖지 않는다. 정산자가 악의적이어도 조건을 우회할 수 없다 — 판정이 전부 온체인이다. 매니저 주소를 하나로 고정해, 공격자가 지정한 매니저로 수수료 지불자를 소모시키는 경로를 막는다
프런트엔드백엔드가 없고, 화면의 값은 브라우저가 체인에서 직접 읽는다. 서명 문장과 서명 바이트가 같은 구조에서 생성되며 코덱이 서로의 역함수임을 테스트가 강제한다 — 표시와 서명이 어긋나는 경로를 코드 수준에서 닫는다
임의의 컨트랙트등록되지 않은 컨트랙트의 owner()는 공격자가 정하는 값이므로, 조건은 팩토리 등록 여부를 먼저 확인한다
재위임 하위 사슬사슬의 모든 링크의 조건이 평가되므로 자식은 부모를 넓힐 수 없다. 뿌리 비활성화가 사슬 전체를 관통한다

알려진 한계

  • 발급 시점의 신원은 보증하지 않는다. 조건은 결제 순간의 liveness를 읽을 뿐, 거래소가 잘못 발급한 attestation을 걸러내지 못한다. 이는 도장 계층의 책임이다.
  • 가스는 에이전트가 낸다. 잔액이 떨어지면 결제가 실패한다. 대납(paymaster)은 기와에 번들러 인프라가 서면 검토한다.
  • 공개 RPC의 읽기 일관성. 로드밸런싱된 엔드포인트가 서로 다른 높이의 상태를 반환할 수 있다. 강제는 온체인이라 안전에는 영향이 없지만, 조회 UI는 재시도로 대응한다.

16배포 주소

GIWA Sepolia (91342). 전부 소스 검증되어 있다.

17다음

감사된 조건 38종 전부 탑재

지금은 결제에 필요한 5종이 올라가 있다. 표준 호환이라 나머지는 수정이 아니라 검증의 일이다 — 건당 상한, 누적 총액, 호출 횟수, 허용 함수 셀렉터, 결제를 목적에 묶는 주문 해시. 구독·법인 경비 같은 시나리오 프리셋으로 조합을 제품화한다.

기와 월렛 연동 · 도장 세분화

ERC-7715 요청 경로는 구현되어 있어 월렛 쪽 스위치만 남았다. 그리고 거래소별·등급별 도장이 늘수록 걸 수 있는 조건이 코드 변경 없이 촘촘해진다 — 발급자는 배포 상수가 아니라 서명 안의 선택이기 때문이다.

조회 인프라

GIWA에는 도장을 조회할 오프체인 API가 없다. 실 발급자 attestation과 마패 사용 기록을 인덱싱해 생태계가 쓸 조회 계층을 연다. 진실은 체인이 쥐고, 속도는 인덱서가 낸다.

EOA 직접 위임 — EIP-7702

GIWA에서 활성화되어 있음을 행동 테스트로 확인했다. 소유자 EOA가 직접 위임자가 되면 계정 컨트랙트 없이 검증된 주소 자체가 위임을 보유한다. 조건은 이 형태를 이미 받아들인다.

18참고 표준

ERC-7710스마트 컨트랙트 위임 — redeemDelegations 인터페이스와 조건 훅
ERC-7715지갑에 실행 권한을 요청하는 표면. 요청 경로를 구현해 두었다
ERC-7579모듈형 계정의 실행 인코딩 — 모드워드와 단일 실행 레이아웃
EIP-712 · ERC-1271구조화 데이터 서명, 컨트랙트 서명 검증
EIP-7702EOA에 코드를 부여하는 경로. 기와에서 활성 확인, 로드맵
x402 v2HTTP 402 결제 프로토콜. exact 스킴의 erc7710 방식을 구현
EASEthereum Attestation Service. 도장이 이 위에 서고, 만료·취소를 결제 시점에 읽는다
MetaMask delegation-framework구조·해싱의 바이트 호환 기준. 조건 2종은 감사본을 무수정 사용 (MIT AND Apache-2.0)