Account Abstraction

진정한 디지털 데이터 소유권과 블록체인 대중화를 위한 솔루션

blgamann
twouplabs
28 min readNov 25, 2022

--

Special thanks to Carl Park and Andy Kang for feedback and review.

이 글은 Account Abstraction이 무엇이고 왜 필요한지에 대해 설명합니다. 그리고 이와 관련한 주요 EIP(EIP-2938, EIP-4337)들과 유즈케이스들을 살펴 봅니다.

작성의 편의를 위해 해당 내용들은 반말로 작성되어 있습니다. 그리고 잘못된 내용이 있다면 지적 부탁드립니다.

이더리움 어카운트 모델

이더리움은 유저의 자산을 추적하기 위해 어카운트 모델을 사용한다. 각 어카운트는 자신만의 고유한 주소를 갖는다.

이더리움 어카운트는 두 가지 타입으로 존재한다.

https://www.preethikasireddy.com/post/how-does-ethereum-work-anyway
  • EOA(Externally Owned Account): 고유한 키(private key)에 의해 주소가 결정된다.
  • CA(Contract Account): 스마트 컨트랙트를 배포하여 어카운트를 생성한다. 해당 어카운트의 주소는 배포자의 주소와 nonce 값에 의해 결정된다.

실제로 둘의 자료구조는 동일하지만 EOA는 codeHashstorageRoot 값을 갖지 않는다.

이더리움 지갑

지갑은 어카운트(EOA, CA)를 관리한다. EOA용 지갑은 private key를 관리하여 어카운트를 관리한다. 반면 CA용 지갑은 지갑의 기능을 하는 dApp으로 컨트랙트에서 자산을 관리한다. dApp이기 때문에 다양한 지갑들이 존재할 수 있는데 대표적으로 멀티시그 지갑이 존재한다.

EOA용 지갑과 CA용 지갑의 가장 큰 차이는 EOA는 직접 트랜잭션을 생성할 수 있는 반면 CA는 스스로 트랜잭션을 만들 수 없다는 점이다. 그렇기 때문에 CA가 동작하기 위해서는 EOA가 CA를 호출(트랜잭션 생성)해야만 한다. 따라서 모든 CA용 지갑은 EOA에 종속적이고 이더리움에서 EOA와 CA는 아래처럼 취급된다.

  • EOA: first-class citizen
  • CA: second-class citizen

문제점

오늘날 대부분의 유저가 사용하는 지갑은 EOA용 지갑이다. 그렇기 때문에 이더리움 상의 모든 dApp은 EOA용 지갑과 상호작용하는 것을 가정하고 만들어진다.

하지만 EOA는 securityUX 측면에서 한계점을 갖고 있다.

security

EOA는 서명자(signer)와 결합되어 있다. 즉 EOA에 존재하는 크립토 자산은 EOA가 소유하지만 해당 자산의 사용 권한은 서명자에게 있다. 서명자는 어카운트의 개인키를 소유한다. 따라서 개인키를 잃어버리면 어카운트를 잃게 되고 심지어 recovery도 불가능하다.

개인키를 관리하는 것은 매우 어렵고 힘들다. 현재까지도 많은 사람들이 개인키를 제대로 관리하지 못해 자산을 잃고 있다. 이런 점 때문에 많은 사람들이 중앙화된 커스터디 서비스(e.g., Coinbase/Upbit 거래소 지갑 또는 Bitgo와 같은 솔루션)를 사용하고 있다.

블록체인은 진정한 디지털 데이터 소유권을 가능하게 만들어준 기술이다. 우리 자신이 직접 디지털 자산을 관리(self-custody)하지 않는다면 우리는 그 자산을 진정으로 소유하고 있다고 말할 수 없다.

EOA를 first-class citizen으로 사용하는 이더리움의 구조에서 self-custody를 하기는 매우 어렵다.

UX

현재 이더리움의 UX는 좋지 않다. 유저는 아래와 같은 절차와 지식을 준수해야만 dApp 서비스를 사용할 수 있게 된다.

EOA 생성(개인키) → ETH 구매(거래소) → 지갑 로그인(서명) → 트랜잭션 생성(가스) → 트랜잭션 처리(마이닝)

그리고 현재 EOA에는 어카운트 별 역할이나 지출 정책을 별도로 지정할 수 없다. 멀티시그 기능을 사용하고 싶으면 멀티시그 지갑을 별도로 사용해야 하고 EOA에 접근 제한을 별도로 설정할 수도 없다.

또한 EOA는 반드시 ETH가 있어야만 트랜잭션을 전송할 수 있다. 비용 측면에서도 한계를 가지는데 예를 들어 유니스왑에서 처음 토큰 스왑을 하게 되면 approve + transferFrom 반드시 두 개의 트랜잭션을 보내야 한다. 원하는 기능은 스왑 하나인데 두 번의 서명이 필요한 것이다.

이제는 self-custody를 위한 방안과 UX 개선이 필요한 시점이다. 그래야만 진정한 디지털 데이터 소유권과 블록체인 대중화를 가져올 수 있다.

Account Abstraction

위에서 언급한 security와 UX의 문제는 AA를 통해 해결될 수 있다. AA는 다음과 같다:

  1. CA를 first-class citizen으로 만든다(현재 이더리움에서는 이를 위해 코어 변경이 필요하다).
  2. CA 지갑이 직접 트랜잭션을 생성하고 수수료를 지불한다.
  3. 유저의 필요에 따라 다양한 기능을 CA 지갑에 커스텀해서 추가할 수 있다.

결국 AA의 핵심은 CA를 기본 지갑으로 사용하는 것이다.

https://youtu.be/OwppworJGzs

AA를 구현하기 위해 다양한 제안(EIP)들이 존재하는데 대표적으로 EIP-2938과 EIP-4337이 존재한다.

EIP-2938

EIP-2938은 이더리움 코어 변경을 통해 AA(Account Abstraction)를 도입하는 것을 목표로 한다. 이를 위해 AA 트랜잭션과 AA 어카운트를 제안한다.

AA 트랜잭션

AA 트랜잭션은 새로운 트랜잭션 타입이다(EIP-2718: Typed Transaction Envelope 베를린 하드포크에 포함되면서 다양한 트랜잭션 타입이 만들어질 수 있고, 현재 EIP-1559와 EIP-2930 트랜잭션 타입이 존재한다). AA 트랜잭션의 payload는 다음과 같다:

RLP[(nonce, target, data])

현재 우리가 사용하는 트랜잭션의 payload는 RLP([nonce, gas_price, gas_limit, to, value, data, v, r, s])이다.

차이점을 살펴보면 다음과 같다(noncedata은 동일):

  • gas_limit, gas_price: AA 어카운트 내부에서 명시된다(gas_limit은 remaining gas를 사용하고 gas_price는 base_gas를 사용하게 된다).
  • to: target 주소로 대체된다. target은 AA 어카운트 주소다.
  • v, r, s: AA 어카운트 내부에 정의된 서명 알고리즘으로 대체된다. AA 트랜잭션은 EOA의 서명(ECDSA)을 필요로 하지 않는다. 그렇기 때문에 base_gas_cost가 21,000이 아닌 15,000이다.
  • value: AA 트랜잭션은 내부적으로 tx.origin을 0xfff…fff (entry_point)로 변경한다. 그렇기 때문에 value 값을 사용하지 않는다.

정리하면, AA 트랜잭션 payload를 구성하는 target은 AA 어카운트 주소, nonce는 target AA 어카운트의 nonce 그리고 data는 실제 실행하고자 bytecode가 된다.

핵심은 AA 트랜잭션의 target은 항상 AA 어카운트여야 하고, AA 트랜잭션은 내부적으로 tx.origin을 0xfff…fff로 변경된다는 점이다.

AA 어카운트

AA 트랜잭션은 서명되지 않기 때문에 코드 내부에 서명 알고리즘이 포함되어 있어야 하고 스스로 수수료를 지불할 수 있어야 한다.

아래는 이를 위한 예시 코드로 2-of-2 멀티시그 기능을 가진 AA 어카운트다.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

account contract TwoOfTwo {
struct Signature {
uint8 v;
bytes32 r;
bytes32 s;
}

address public owner0;
address public owner1;

constructor(address _owner0, address _owner1) payable {
owner0 = _owner0;
owner1 = _owner1;
}

function transfer(
uint256 gasPrice,
uint256 gasLimit,
address payable to,
uint256 amount,
bytes calldata payload,
Signature calldata sig0,
Signature calldata sig1
) external {
bytes32 digest = keccak256(abi.encodePacked(this, gasPrice, gasLimit, to, amount, tx.nonce, payload));

address signer0 = recover(digest, sig0);
require(owner0 == signer0);

address signer1 = recover(digest, sig1);
require(owner1 == signer1);

paygas(gasPrice, gasLimit);

(bool success, ) = to.call{ value: amount }(payload);
require(success);
}

function recover(bytes32 digest, Signature calldata signature) private pure returns (address) {
return ecrecover(digest, signature.v, signature.r, signature.s);
}
}
  • account contract TwoOfTwo: AA 어카운트를 나타내기 위해 새로운 account 키워드를 사용한다.
  • constructor: 2-of-2 멀티시그 지갑기 때문에 두 명의 owner 주소들을 상태에 저장해둔다.
  • function transfer(…): 실제 실행 코드다. 내부적으로 서명 검증(2-of-2)을 수행하고 PAYGAS opcode를 실행하여 수수료를 지불한다.

NONCE & PAYGAS opcode

AA 트랜잭션과 AA 어카운트가 이더리움에서 동작하도록 하기 위해 새로운 opcode 두개가 필요하다. 즉 프로토콜의 변경이 필요하다.

  • NONCE: 유저가 보낸 nonce와 AA 컨트랙트(target)의 nonce를 비교한다. target AA 컨트랙트의 nonce를 구하기 위해 NONCE opcode가 필요하다.
  • PAYGAS: PAYGAS opcode를 실행해 AA 어카운트가 수수료를 지불한다. 이를 위해 AA 어카운트의 잔액은 gas_price * gas_limit보다 많아야 한다. PAYGAS opcode는 실행을 위한 체크포인트로 사용되는데, 만약 PAYGAS 이후에 revert가 발생하면 일반적인 revert와 마찬가지로 모든 수수료는 지불되고 실행은 롤백된다. 간단히, PAYGAS opcode 이전은 검증 단계이고 PAYGAS opcode 이후는 실행 단계라고 볼 수 있다.

AA 트랜잭션 검증

이더리움의 모든 트랜잭션은 노드에 전송되면 검증 절차를 거치게 된다. AA 트랜잭션도 검증 절차를 거치게 되는데 절차가 조금 더 복잡하다. 우선 mempool에 존재하는 AA 트랜잭션이 펜딩 중인 다른 트랜잭션의 상태에 의존성을 갖지 않도록 하기 위해서 다음의 조건이 필요하다.

  1. PAYGAS opcode가 실행되기 전에 코드에서 다음의 opcode들 — BLOCKHASH, COINBASE, TIMESTAMP, NUMBER, DIFFICULTY, GASLIMIT, BALANCE, CALL, CALLCODE, STATICCALL, CREATE, CREATE2, EXTCODESIZE, EXTCODEHASH, EXTCODECOPY, DELEGATECALL — 이 포함되어서는 안된다. 즉 PAYGAS opcode 이전인 검증 단계에서 의존성을 갖는 opcode가 존재해서는 안된다. 만약 AA 트랜잭션이 노드에 전송되면 해당 노드는 이와 같은 룰을 위반했는지 확인한다. 즉 PAYGAS opcode 이전에 의존성을 갖는 opcode들이 존재한다면 해당 트랜잭션을 받아들이지 않는다.
  2. AA 트랜잭션이 아닌 트랜잭션이 AA 어카운트에 영향을 주지 못하도록 막아야 한다. 이를 위해 AA 컨트랙트가 배포되면 bytecode에 AA_PREFIX를 두고 저장한다. 만약 트랜잭션의 target(또는 to) 필드의 주소가 AA 컨트랙트이면 해당 컨트랙트에는 AA_PREFIX가 존재할 것이다. AA_PREFIX가 존재하면 노드는 해당 트랜잭션의 tx.origin이 0xfff…fff인지를 확인한다. tx.origin이 0xfff…fff가 아니면 AA 트랜잭션이 아니기 때문에 AA 트랜잭션이 아닌 트랜잭션이 AA 어카운트를 실행할 수 없게 막을 수 있다.

EIP-2938은 오랜 기간동안 논의된 제안이지만 이더리움 프로토콜에 반영되지 않았다. 현재 더 머지(The Merge)가 이루어지긴 했지만, 이더리움에게 있어서 AA를 구현하는 것보다 더 머지와 같은 프로토콜 변경에 더 많은 관심과 리소스가 소요되고 있었다. 또한 이더리움 프로토콜 변경은 완전한 합의가 없이는 매우 힘든 부분들이 존재한다.

EIP-4337

이후 비탈릭은 AA(Account Abstraction)을 위한 새로운 EIP-4337을 제안한다. 해당 제안은 EIP-2938과 달리 프로토콜 변경없이 AA를 구현할 수 있도록 한다. 이런 특성으로 현재 EIP-4337이 AA를 주도하고 있다.

https://medium.com/infinitism/erc-4337-account-abstraction-without-ethereum-protocol-changes-d75c9d94dc4a

EIP-4337은 UserOperation을 위한 새로운 레이어를 필요로 한다. UserOperation은 트랜잭션과 유사한 것으로, 유저는 트랜잭션 대신 UserOperation을 전송한다. UserOperation은 UserOperation mempool에 쌓이게 되는데 이를 Bundler가 번들링한다. 번들링된 UserOperation들은 하나의 Bundle 트랜잭션으로 이더리움 노드에 전송되어 처리된다.

UserOperation을 처리하기 위해 3개의 컨트랙트(EntryPoint, Wallet, Paymaster)가 필요하다(Paymaster 컨트랙트는 조건에 따라 사용되지 않을 수도 있다).

  • EntryPoint: UserOperation을 검증하고 실행한다.
  • Wallet: 컨트랙트 어카운트 지갑으로 UserOperation의 sender다. 수수료를 지불하고 서명 검증 로직을 담고 있다.
  • Paymaster: UserOperation의 sender가 ETH가 아닌 ERC20 토큰으로 수수료를 지불할 수 있게 해준다. 심지어 수수료를 내지 않고도 트랜잭션을 보내도록 해줄 수 있다.

번들러는 UserOperation들을 패키징하고 EntryPoint 컨트랙트의 handleOps 함수를 호출한다. handleOps 함수는 UserOperation들을 검증하고 실행하게 된다.

function handleOps(UserOperation[] calldata ops, address payable beneficiary);

각각의 UserOperation이 handleOps 함수 내에서 어떻게 처리되는지 코드를 통해 단계별로 살펴보도록 한다.

UserOperation

UserOperation 필드값은 위와 같다.

1/ 번들러(bundler)는 handleOp 함수를 호출한다.

번들러는 UserOperation을 번들링해서 하나의 번들 트랜잭션을 만든다. 번들 트랜잭션은 EntryPoint 컨트랙트의 handleOps 함수를 호출하는 트랜잭션이다.

handleOps 함수 내부에서는 _verifyOp 함수와 _executeOp 함수를 호출하는데, 이곳에서 UserOperation에 대한 검증실행을 하게 된다.

2/ _verifyOp

UserOperation을 검증하는 함수다. 다음의 검증들이 이루어진다.

  1. nonce & signature 검증
  2. op.verificationGas 검증
  3. balance 검증
  4. (Paymaster 검증 (Paymaster 섹션에서 다루게 된다))

2–1/ nonce & signature 검증

Wallet을 검증하기 위해 UserOperation의 op.sender, op.nonce 그리고 op.signature가 사용된다(Wallet 검증은 트랜잭션을 검증하기 위해 EOA의 nonce와 signature 그리고 upfront cost보다 많은 balance가 있는지 검증하는 것과 같다).

op.으로 시작하는 값들은 모두 UserOperation의 필드값을 의미한다.

op.sender는 Wallet 주소이고, op.nonce는 Wallet의 nonce 값이다. op.signature는 requestId를 서명한 값이다. requestId는 UserOperation을 인코딩해서 해싱한 뒤, 이를 EntryPoint 컨트랙트의 주소와 chainId 3개의 값을 다시 해싱한 값이다. 이를 통해 유효한 EntryPoint 주소가 사용되었는지 확인할 수 있고, chainId를 사용함으로써 replay 공격을 막을 수 있다.

중간 과정으로, 만약 Wallet이 존재하지 않으면 Wallet을 생성해 준다. 이를 위해 op.initCode를 확인한다. op.sender의 주소로 아직 Wallet 컨트랙트가 배포되지 않았고, op.initCode가 존재한다면 CREATE2 opcode를 통해 Wallet 컨트랙트를 새로 배포한다.

Wallet 검증은 다음과 같이 이루어진다:

  1. (Wallet이 존재하지 않는 경우 Wallet을 생성)
  2. nonce 검증op.sender 주소를 가진 Wallet의 nonce와 op.nonce를 비교한다.
  3. signature 검증 Wallet 컨트랙트 내부에서 op.signature의 signer가 유효한 주소인지를 확인한다. signer의 주소가 Wallet에서 허용되는 주소이면 해당 검증은 통과된다.

signature 검증 과정에서 AA의 장점이 들어난다. signature 검증이 스마트 컨트랙트 코드 내에서 일어나기 때문에 signature 검증 과정을 커스텀할 수 있다.

Wallet 검증 과정에서 UserOperation의 4개의 필드값(sender, nonce, initCode, signature)의 역할에 대해서 이해할 수 있었다.

  • sender: Wallet 컨트랙트의 주소로 유저는 더이상 EOA를 사용하지 않고 CA(Wallet 컨트랙트)를 사용한다.
  • nonce: Wallet 컨트랙트의 nonce 값이다. op.nonce와 Wallet의 nonce가 같아야 한다. UserOperation이 처리되면 Wallet의 nonce는 1 증가할 것이다.
  • initCode: sender 주소가 CA가 아니면 Wallet 컨트랙트를 새로 배포하는데 이를 위해 필요한 bytecode다.
  • signature: Wallet 내부에서 서명 검증에 이용되는 서명값이다. signer가 Wallet이 허용하는 주소라면 서명 검증은 통과하게 된다.

2–3/ op.verifiactionGas 검증

UserOperation 검증은 Wallet 검증과 Paymaster 검증으로 이루어진다. 검증 과정을 거치면서 가스를 소모하게 되는데 소모하게 되는 gas는 op.verifiactionGas보다 적거나 같아야 한다. 해당 조건을 충족하지 못하면 UserOperation은 처리되지 않는다.

2–3/ balance 검증

번들 트랜잭션의 수수료는 번들러(Bundler)가 지불한다. 번들러는 UserOperation을 처리하는 대가로 UserOperation의 Wallet 주소(op.sender)로부터 수수료를 받게 된다.

Wallet은 EntryPoint 컨트랙트에 수수료를 지불하기 위해 UserOperation이 처리되기 위해 필요한 수수료만큼 ETH를 보유하고 있어야 한다. 이를 확인하는 과정을 balance 검증이라고 한다.

balance 검증을 하기 위해서는 upfront cost를 구해야 한다. 트랜잭션의 upfront cost는 gasLimit * gasPrice로 구해지는데 반해 UserOperation의 upfront cost는 totalGas(op.preValidationGas + op.validationGas + op.callGas) * gasPrice로 구해진다.

validationGas는 UserOperation 검증 단계에서 소모된 가스라면 preValidationGas는 번들 트랜잭션 생성에 대한 가스를 말한다. callGas는 UserOperation을 실행할 때 소모될 gas다.

gasPrice를 구하기 위해 op.maxFeePerGasop.maxPriorityFeePerGas를 사용한다. 해당 로직은 EIP-1559의 스펙과 동일하다.

구한 upfront cost를 EntryPoint 컨트랙트로 보낸다. 만약 upfront cost만큼 Wallet에 ETH가 없다면 revert될 것이다.

우리는 op.verificationGas 검증과 balance 검증을 통해 아래의 필드값이 어떻게 사용되는지 알 수 있다.

3/ _executeOp

검증 단계가 끝이 났다. 이제는 UserOperation을 실행할 단계다. 실행 단계는 검증 단계보다 과정이 단순하다.

  1. 지갑을 실행한다. 이를 위해 op.callGasop.callData가 사용된다.
  2. 실행에 소모된 gas를 더해준다. 검증 단계에서 소모한 가스와 실행 단계에서 소모한 가스를 더하면 totalGasUsed가 된다. 여기에 gasPrice를 곱하면 totalGasCost가 된다.
  3. upfront cost에서 totalGasCost를 빼준 만큼을 Wallet(op.sender)에게 환불 해준다.

지갑 실행

Wallet 컨트랙트로 op.callGasop.callData를 보낸다. 실행 단계에서 op.callGas보다 많은 가스를 소모하게 되면 out-of-gas 에러가 발생할 것이다.

op.callData는 executeUserOp 함수를 호출하기 위한 4 bytes와 executeUserOp 함수의 인자값을 인코딩한 값으로 구성될 것이다.

[function_selector + encoded[to, value, data]]

to는 Wallet이 호출하고자 하는 컨트랙트 주소이고 value는 전송할 wei가 될 것이다. data는 to 컨트랙트의 함수 호출과 관련된 calldata가 들어가게 될 것이다.

Paymatser

UserOperation 검증과 실행은 EntryPoint가 수행하지만 실행을 위한 수수료는 Wallet이 지불한다. 하지만 EntryPoint가 원한다면 수수료 지불을 위해 ETH가 아닌 다른 토큰을 Wallet으로부터 받을 수도 있을 것이다. 예를 들어 Wallet은 DAI를 EntryPoint로 보내고 EntryPoint는 자신의 ETH를 사용해 UserOperation을 처리해준다. 이러한 기능을 담당하는 것이 Paymaster 컨트랙트다.

ETH가 아닌 토큰을 받고 UserOperation을 처리하기 위해서는 EntryPoint 컨트랙트에 ETH가 어느정도 stake되어 있어야 한다. Staking 컨트랙트는 이러한 기능을 담당한다.

Paymaster 검증과 실행

Paymaster만을 위한 검증과 실행 단계가 존재한다. 이 단계들은 위에서 설명한 검증 단계와 실행 단계에 포함된다.

검증 단계

Paymaster를 검증하기 위해 op.paymasterop.paymasterData 값이 사용된다. op.paymaster는 Paymaster 컨트랙트 주소이고, op.paymatserData[uint256 fee, PaymasterMode mode, IERC20Metadata token, AggregatorV3Interface feed, bytes memory signature]를 인코딩한 값이다.

mode(PaymasterMode)는 4가지가 존재한다. 이러한 모드에 따른 fee 값도 다를 것이다.

signature는 Paymaster 사용을 하기 위해 필요한 서명값으로 해당 서명의 signer가 Paymaster로부터 허용되는 주소라면 signature 검증은 통과하게 된다.

token은 수수료로 지급할 ERC20 토큰 주소가 된다. AggregatorV3Interface 컨트랙트 주소는 Chainlink 가격 피드 시스템으로부터 ETH와 해당 토큰의 비율을 구하기 위해 사용된다. upfront cost인 ETH의 수량은 ETH <> 토큰의 가격 비율값을 통해 토큰 수량으로 변환된다. 해당 토큰 수량만큼 op.sender가 보유하고 있는지 확인을 하는 것으로 Paymaster 검증을 마친다.

실행 단계

_executePostOp 함수는 UserOperation 실행이 모두 끝난 이후에 호출된다. 실행까지 끝났기 때문에 총 소요한 gasCost를 알 수 있다. 이 gasCost는 하나의 UserOperation의 검증과 실행에서 소모한 총 가스량이 된다.

postOp 함수는 ETH <> 토큰 가격 비에 맞게 gasCost(wei)에 해당하는 토큰 수량을 구한다. 해당 토큰 수량만큼 Wallet에서 Paymaster 컨트랙트로 전송하는 것으로 수수료를 지급한다.

마지막으로 실행을 모두 끝내고 남은 가스는 다시 Staking 컨트랙트에 stake된다.

하나의 UserOperation 위와 같은 과정으로 처리되고, 모든 UserOperation의 처리가 끝나면 번들 트랜잭션의 실행은 종료된다.

Use cases

AA가 구현되면 어카운트와 서명자의 분리가 가능해진다. 이로 인해 다양한 장점과 유즈케이스가 생긴다.

Key management

AA는 하나의 키(key)에 의존적이지 않다. 다양한 키를 만들어서 사용할 수 있다. 예를 들어 지갑에 메인 키를 변경할 수 있는 함수나 여러 키들을 관리하는 함수를 둘 수 있다. 이에 따라 social recovery도 가능해진다. 예를 들어 메인 키를 잃어버렸을 때, 메인 키에 대한 3명의 guardian들이 존재한다고 했을 때, 이들로부터 합의를 통해 메인 키를 변경해줄 수 있을 것이다.

그리고 키별로 역할과 정책을 다르게 둘 수도 있다. 예를 들어 어떤 키는 회사 내의 C-레벨만 사용하는 것으로 두고 동시에 특정 함수만 호출 가능하도록 할 수 있다. 그 뿐만 아니라 기기 별로 키를 할당해서 사용할 수 있다. 메인 키는 하드웨어 지갑에서 관리하고 모바일 기기와 데스크탑에서 사용하는 키는 다른 것을 사용한다. 이 키들은 메인 키들로부터 승인을 받은 것이다.

오늘날 모바일 지갑은 대부분 읽기만 하고 인터랙션 용도로 잘 사용하지 않는다. 인터랙션을 하기 위해서는 모바일에 키가 존재해야 하는데 폰을 잃어버리면 자산을 잃어버릴 수도 있기 때문이다. 하지만 모바일에 할당된 키를 특정 함수만 호출할 수 있도록 설정한다면 폰을 잃어버리더라도 자산을 잃어버릴 위험은 사라진다. 결국 AA를 통해 기기에 상관없이 더욱 안전하게 블록체인을 사용할 수 있게 된다.

Gas payment

EOA는 트랜잭션을 전송하기 위해 ETH가 반드시 필요하다. 하지만 AA를 이용하면 ETH가 없어도 트랜잭션을 보낼 수 있다. ERC-4337에서 살펴본 것처럼 다른 토큰으로 수수료를 대체해도 되고 심지어 Paypal을 통해 fiat으로 지불하도록 만들 수도 있다.

또한 이를 통해 privacy 문제도 해결될 수 있다. 우리는 거래소에서 ETH를 구매하는 순간 privacy가 깨진다. 트랜잭션들은 모두 추적되기 때문이다. ETH를 구매하지 않고도 트랜잭션을 보낼 수 있다면 privacy 측면에서도 장점이 생긴다.

Signature

현재 트랜잭션은 ECDSA 서명 알고리즘에 의해 암호화된다. 하지만 AA는 컨트랙트 코드에 의해 서명 검증이 이루어지기 때문에 ECDSA 서명 알고리즘에 의존하지 않아도 된다. ECDSA보다 더 나은 서명 알고리즘이 있다면 그것을 사용해도 된다. 예를 들어 BLS 서명 알고리즘이나 양자 저항성을 띤 서명 알고리즘을 사용할 수 있을 것이다. 게다가 하나의 서명이 아니라 동시에 여러 개의 서명을 받아 이를 검증하는 multisig 방식을 지갑에 구현할 수 있다.

Batch transaction

일반적인 트랜잭션은 하나의 함수만 호출가능하다. 하지만 AA를 통해 여러 트랜잭션을 단 하나의 트랜잭션으로 처리되도록 만들 수 있다. 예를 들어 ERC20의 approve + tranfserFrom + revoke 과정이 필요하다고 했을 때 3번의 서명이 필요하다.

AA는 3개의 트랜잭션을 하나의 트랜잭션으로 처리되도록 만들 수 있다. 유저가 필요한 기능을 사용하기 위해 단 하나의 서명만을 필요로 하게 만드는 것이다. 이를 통해 유저 경험을 더욱 좋게 만든다.

Session key

온체인 게임은 앞으로 많이 나올 것이다. 온체인 게임에서 유저가 액션을 할 때마다 서명을 해야 한다면 이는 유저 경험을 해친다. 세션 키는 정해진 기간 내에 특정 트랜잭션에 대해 유저 서명 없이 트랜잭션이 전송되도록 만드는 것을 말한다. 세션 키에는 유효 기간은 존재하고 이 유효 기간이 끝나면 해당 키는 소멸될 것이다.

Plugin

위에서 언급한 모든 기능들이 AA 지갑에 플러그인 방식으로 구현될 수 있다. multisig 플러그인, session key 플러그인 그리고 BLS signature 플러그인 등등 유저가 원하는 플러그인들을 사용할 수 있다.

마치며

AA는 앞으로 이더리움의 미래에 가장 중요한 기술 중 하나다. 현재 AA는 이더리움에 구현되어 있지 않다. 대신 몇몇 L2 프로젝트에서 AA를 사용하고 있다. 특히 zk 계열의 L2인 StarkNet와 zkSync는 AA를 default 어카운트로 사용하고 있다. zk 계열의 L2는 execution 비용이 싸고 L2이기 때문에 L1보다 다소 코드 변경에 용이하기 때문에 AA를 적극 도입할 수 있었다.

L2에서 AA 관련해서 여러 실험들이 이루어진 뒤 L1에서도 자연스럽게 도입될 것이다. 이를 통해 우리 모두가 self-custody를 통해 진정한 디지털 데이터 소유권을 얻음과 동시에 블록체인 대중화가 급속도록 이루어지는 것을 지켜볼 수 있을 것이다.

Reference

--

--