본문으로 건너뛰기

스마트 계정

SimpleAccount는 최소 단일 Owner ECDSA 참조 구현입니다. 자체 ERC-4337 스마트 계정도 구현할 수 있습니다.

SimpleAccount implementation은 모든 계정 프록시가 공유하는 구현 주소이며 사용자 계정 주소가 아닙니다. 각 인스턴스는 Owner와 salt로 결정됩니다.

1. SimpleAccountFactory API​

interface ISimpleAccountFactory {
function accountImplementation() external view returns (address);
function getAddress(address owner, uint256 salt) external view returns (address);
function createAccount(address owner, uint256 salt) external returns (address);
}
메서드설명
accountImplementation공유 SimpleAccount 구현 반환
getAddress배포 없이 Owner와 salt의 반사실적 프록시 주소 계산
createAccount코드가 없으면 프록시 생성, 배포되어 있으면 기존 계정 반환

최초 UserOperation의 Factory 데이터는 Factory 주소와 ABI 인코딩된 createAccount(owner, salt)입니다. EntryPoint는 Factory 반환 주소가 sender와 같고 배포 후 sender에 코드가 존재하도록 요구합니다.

2. SimpleAccount API​

interface ISimpleAccount {
function owner() external view returns (address);
function entryPoint() external view returns (address);
function getNonce() external view returns (uint256);
function initialize(address owner) external;
function execute(address dest, uint256 value, bytes calldata func) external;
function executeBatch(address[] calldata dest, uint256[] calldata value, bytes[] calldata func) external;
function getDeposit() external view returns (uint256);
function addDeposit() external payable;
function withdrawDepositTo(address payable withdrawAddress, uint256 amount) external;
}

2.1 계정 상태​

메서드설명
owner현재 단일 ECDSA Owner
entryPoint계정에 연결된 EntryPoint
getNonceEntryPoint key 0의 다음 nonce
initialize프록시 Owner를 한 번만 초기화

Factory가 생성 시 프록시를 초기화합니다. 초기화되지 않은 프록시를 외부에 노출하지 마세요.

2.2 비즈니스 실행​

메서드호출 권한동작
executeOwner 또는 연결된 EntryPoint단일 호출 실행 및 revert 데이터 전달
executeBatchOwner 또는 연결된 EntryPoint여러 호출을 원자적으로 실행

executeBatch는 대상 주소와 calldata 배열 길이가 같아야 합니다. value 배열은 비워 모든 호출이 BOT를 전송하지 않게 하거나 대상 배열과 같은 길이로 지정합니다.

Owner가 직접 호출하면 일반 트랜잭션 Gas를 지불합니다. EntryPoint 호출은 UserOperation을 사용하며 계정 또는 Paymaster deposit에서 Gas를 정산합니다.

2.3 EntryPoint deposit​

메서드설명
getDepositEntryPoint의 계정 Gas deposit 조회
addDeposit계정 deposit 충전
withdrawDepositToOwner가 deposit 인출

네이티브 BOT 잔액은 전송과 비즈니스 호출에, EntryPoint deposit은 UserOperation Gas에 사용되며 서로 독립적입니다.

2.4 토큰 수신​

SimpleAccount는 네이티브 BOT, ERC-721, ERC-1155를 수신하고 관련 receiver 인터페이스 감지를 구현합니다.

3. SimpleAccount 검증 동작​

function validateUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash, uint256 missingAccountFunds) external returns (uint256 validationData);
단계동작
호출자 검사연결된 EntryPoint만 허용
서명 hashuserOpHash에 EIP-191 적용
서명 검증ECDSA recover 결과가 Owner와 일치
서명 실패SIG_VALIDATION_FAILED(1) 반환
nonceEntryPoint가 고유성 관리, 기본 key 0
prefundmissingAccountFunds를 EntryPoint에 지급

SimpleAccount는 multisig, 소셜 복구, Session Key, Passkey, ERC-7579 모듈을 기본 제공하지 않습니다. 필요하면 자체 계정을 구현하고 문서화되지 않은 인터페이스를 가정하지 마세요.

4. 사용자 정의 스마트 계정​

IAccount를 직접 구현하거나 BaseAccount를 상속합니다. EntryPoint v0.7 및 Bundler 검증 규칙과 호환되어야 합니다.

4.1 필수 인터페이스​

interface IAccount {
function validateUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash, uint256 missingAccountFunds) external returns (uint256 validationData);
}
파라미터설명
userOp검증하고 실행할 PackedUserOperation
userOpHashEntryPoint와 chainId에 바인딩된 hash
missingAccountFunds계정 deposit과 필요 prefund의 차액
하위 160 bit: 0은 유효, 1은 실패, 그 외는 집계기 주소
다음 48 bit: validUntil, 0은 만료 없음
상위 48 bit: validAfter

4.2 필수 동작​

  • msg.sender가 신뢰하는 EntryPoint인지 확인합니다.
  • signature, 권한 정책, 필요한 계정 상태를 검증합니다.
  • 서명 불일치는 1을 반환하고 다른 형식·정책 오류는 revert할 수 있습니다.
  • 계정 nonce 정책을 적용하되 고유성 업데이트는 EntryPoint가 수행합니다.
  • Paymaster가 없고 deposit이 부족하면 missingAccountFunds를 지급합니다.
  • ERC-7562 opcode, storage 접근, 외부 호출 제한을 준수합니다.
  • 추정 중 결정론적이고 시뮬레이션 가능한 검증을 제공합니다.

BaseAccount 하위 클래스는 최소한 entryPoint()와 _validateSignature(...)를 제공하며 필요 시 _validateNonce(...)와 _payPrefund(...)를 재정의합니다.

4.3 실행 인터페이스 설계​

단일, 일괄, 모듈 또는 권한 계층 실행을 위한 자체 callData 인터페이스를 정의할 수 있습니다. 기본적으로 EntryPoint는 userOp.callData를 계정에 직접 전송합니다.

interface IAccountExecute {
function executeUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash) external;
}

executeUserOp selector를 사용하면 EntryPoint가 전체 UserOperation과 hash를 전달합니다. 선택적 인터페이스입니다.

4.4 Factory 및 배포​

  • 결정론적 파라미터로 안정적인 계정 주소를 계산합니다.
  • 생성 메서드는 실제 배포 주소를 반환합니다.
  • 최초 initCode의 앞 20 bytes에 Factory 주소, 나머지에 calldata를 둡니다.
  • 배포 결과는 UserOperation sender와 같아야 합니다.
  • 배포 후 Factory 필드를 생략합니다.

Bundler는 Factory와 계정 검증을 시뮬레이션하고 규칙을 위반하면 mempool 진입 전에 거부합니다.