MetaMask Snaps는 MetaMask를 세계에서 가장 확장 가능한 지갑으로 만들기 위한 로드맵입니다. 개발자라면 완전히 새로운 방식으로 MetaMask에 기능과 API를 추가할 수 있습니다. Web3 개발자들은 이러한 성장의 핵심이며, 이 시리즈는 현재 개발 중인 혁신적인 MetaMask Snaps를 소개하는 것을 목표로 합니다.
AA Snap
Snap 저장소: https://github.com/a42io/AAsnap
왜 만들었나요?
AA Snap은 모든 개발자와 사용자를 위해 Account Abstraction(AA)을 민주화하기 위해 만들어졌습니다. 저희는 AA가 앞으로 널리 사용될 것이라고 믿습니다. 하지만 현재로서는 개발자가 dapp에 AA를 통합하거나 사용자가 이를 활용하는 데 상당한 노력이 필요합니다.
개발자 입장에서는 EOA 외에도 AA를 지원하는 추가 코드를 작성해야 합니다.
사용자 입장에서는 MetaMask와 같이 익숙한 지갑을 사용할 수 없고, AA를 지원하는 별도의 지갑을 설치해야 하므로 UX가 좋지 않습니다.
따라서 저희는 MetaMask Snaps를 활용하여 AA를 쉽게 통합하고 사용할 수 있도록 만들고자 했습니다.
기술적인 구현 방식을 설명해 주실 수 있나요?
AA Snap은 예시 프론트엔드, MetaMask snap, 임시 서버, 이렇게 세 가지 구성 요소로 이루어져 있습니다. 이 snap을 통해 개발자와 사용자는 AA 지갑(EIP-4337을 지원하는 컨트랙트 지갑)을 매우 쉽게 사용할 수 있습니다. 전체 구현 내용은 저장소를 참고해 주세요.
예시 프론트엔드
예시 프론트엔드는 MetaMask에서 제공하는 템플릿을 기반으로 합니다. 이를 통해 개발자들이 AA Snap을 사용하여 dapp에 AA를 손쉽게 통합할 수 있음을 보여줍니다.
예를 들어, AA 지갑의 잔액은 아래의 간단한 코드로 조회할 수 있습니다.
const balance = (await window.ethereum.request({
method: 'wallet_invokeSnap',
params: [
defaultSnapOrigin,
{
method: 'balance',
},
],
})) as string;
AA 지갑에서 트랜잭션을 전송하려면 수신자 주소와 금액을 전달하여 아래 코드를 작성하기만 하면 됩니다.
await window.ethereum.request({
method: 'wallet_invokeSnap',
params: [
defaultSnapOrigin,
{
method: 'transfer',
params: {
to,
value,
},
},
],
});
사용자 입장에서 AA 지갑을 얼마나 쉽게 사용할 수 있는지 직접 확인해 보세요: https://AAsn.app
Snap
Snap은 아래 코드를 통해 AA 인스턴스를 가져옵니다. AA를 구현하기 위해 @account-abstraction/sdk npm 패키지를 사용했습니다.
AA 지갑 주소는 사용자의 EOA로부터 결정론적으로 도출될 수 있으므로, 별도의 사용자 입력이 필요하지 않습니다.
export const getAbstractAccount = async (): Promise<SimpleAccountAPI> => {
const provider = new ethers.providers.Web3Provider(wallet as any);
await provider.send('eth_requestAccounts', []);
const owner = provider.getSigner();
const aa = new SimpleAccountAPI({
provider,
entryPointAddress,
owner,
factoryAddress,
});
return aa;
};
AA 지갑에서 트랜잭션을 전송하는 데는 세 가지 단계가 있습니다:
Snap은 snap의 snap_confirm 메서드를 사용하여 MetaMask 내에서 확인 창을 표시합니다. 이 과정은 필수는 아니지만, 사용자가 서명할 내용의 세부 정보를 알 수 없기 때문에 더 나은 UX를 위해 필요합니다.
코드는 AA 지갑의 user operation을 생성하고 해당 user operation의 해시에 서명을 요청합니다. 이 과정은 EOA에서 트랜잭션을 생성하고 서명하는 것과 거의 동일합니다.
서명된 user operation을 저희 서버를 통해 bundler로 전송합니다.
export const transfer = async (target: string, ethValue: string) => {
const value = ethers.utils.parseEther(ethValue);
const aa = await getAbstractAccount();
const address = await aa.getAccountAddress();
const result = await wallet.request({
method: 'snap_confirm',
params: [{
prompt: 'Transfer',
description: 'Transfer from your Abstraction Account',
textAreaContent: `from: ${address}\ntarget: ${target}\nvalue: ${ethValue}`,
}],
});
if (!result) {
return;
}
const op = await aa.createSignedUserOp({
target,
value,
data: '0x',
maxFeePerGas,
maxPriorityFeePerGas,
});
const printedOp = await printOp(op);
const body = JSON.stringify({
op: printedOp,
});
const response = await fetch(SERVER_END_POINT {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body,
});
};
임시 서버
해커톤 진행 중, snap 내부에서 sendUserOpToBundler 메서드를 호출할 때 오류가 발생했습니다. 문제를 깊이 파고들 시간이 없었기 때문에, 임시방편으로 서버를 만들어 해결하기로 했습니다. 임시 서버는 서명된 user operation을 받아 bundler로 전달하는 역할만 합니다.
이 오류는 MetaMask Snaps 실행 환경에 일부 제한이 있어 의존성 문제에서 비롯된 것으로 보입니다. 다음 문서를 참고하면 임시 서버를 제거할 수 있을 것으로 생각합니다: 의존성 패치하기
app.post('/aa', async (req, res) => {
const provider = new ethers.providers.JsonRpcProvider(
process.env.RPC_ENDPOINT,
);
const client = await getHttpRpcClient(
provider,
process.env.BUNDLER_URL as string,
process.env.ENTRY_POINT_ADDRESS as string,
);
try {
const uoHash = await client.sendUserOpToBundler(JSON.parse(req.body.op));
return res.json({
uoHash,
});
} catch (e) {
console.log(e);
return res.status(400).send();
}
});
이를 구현한다면 다음 단계는 무엇인가요?
불필요한 서버 측 코드를 제거하고 snap만으로 실행할 수 있도록 하고 싶습니다. 또한 현재는 저희와 같은 MetaMask Snaps 개발자가 서명할 트랜잭션 해시를 악의적인 것으로 교체할 가능성이 있기 때문에, 이를 방지하는 메커니즘을 도입하거나 제안하고자 합니다.
본인과 팀에 대해 간략히 소개해 주시겠어요?
저희 팀은 일본과 싱가포르에서 소규모 스타트업 a42를 운영하고 있습니다. a42는 NFT 및 ENS를 포함한 스마트 컨트랙트로 인증이 가능한 Web3 스마트 잠금장치 "wΞlock"을 개발하고 있습니다: https://a42.io/w3lock 2022년에는 MetaMask Snaps와 같은 새로운 기술을 배우기 위해 여러 해커톤에 참가했습니다.
Hideyoshi Moriya (piyo.eth): Hideyoshi는 2017년부터 이더리움 기반 앱을 실험하고 개발해 왔습니다. 2017년에는 협업 NFT 아트 프로젝트 "Pixereum"을 개발했습니다. Google에서 기술 제품 전문가로 근무했으며, 2019년에 자신의 회사 "a42"를 설립했습니다. a42에서는 실제 세계에서 작동하는 dapp을 개발하고 있습니다. 현재는 2021년에 개발한 PoC를 기반으로 ENS/NFT로 열 수 있는 Web3 스마트 잠금장치 "wΞlock"을 개발 중입니다: https://twitter.com/hm0429/status/1465241679800111107
Hiroyuki Tachibana (tachibana.eth): Hiroyuki는 a42의 공동 창업자이자 엔지니어입니다. IoT 기기를 위한 블록체인 인증 모듈 "w3a.io" 구축 프로젝트를 이끌었으며, Ethereum Foundation으로부터 그랜트를 받았습니다. 2022년 ETHGlobal 해커톤에서 여러 차례 수상했습니다. 현재는 Web3 스마트 잠금장치 제품을 위한 zkp 프라이버시 솔루션을 개발 중입니다.
Yusuke Moriya (yskmyskm.eth): Yusuke는 a42의 디자이너입니다. 다양한 영상 제작에서 CG/VFX 아티스트로 활동했으며, 글로벌 브랜드부터 소규모 뮤직비디오까지 다양한 프로젝트에 참여했습니다. 영화 산업에서 12년의 경력을 보유하고 있으며, 컴퓨터 그래픽을 활용한 추상적 표현을 전문으로 합니다. 촬영 감독 및 다큐멘터리 감독으로도 활동한 바 있습니다.
MetaMask Snaps와 Web3 공간에서 이것이 열어주는 가능성에 대해 어떤 기회를 보고 계신가요?
저희는 MetaMask Snaps가 복잡한 Web3 기술을 개발자와 사용자 모두에게 더 쉽게 만들어 주고, 기존 웹 애플리케이션이 Web3와 통합하는 데 크게 기여할 것이라고 믿습니다. 저희는 첫 번째 모바일 앱 스토어가 출시되었을 때만큼이나 MetaMask Snaps를 만드는 것에 대해 설레고 있습니다. 직접 시도해 보고 여러분의 아이디어를 실현해 보시길 권장합니다!
MetaMask Snaps에 도전하려는 개발자들에게 공유하고 싶은 조언이 있나요?
MetaMask Snaps 템플릿 (https://github.com/MetaMask/template-snap-monorepo)으로 시작하여 먼저 수정해 보는 것을 권장합니다.
팁: 주입된 ethereum 객체를 어떻게 가져오는지 궁금하실 수 있습니다. wallet 객체가 이와 동일합니다.
MetaMask Snaps로 개발하기
MetaMask Snaps를 시작하려면:
개발자 문서를 확인하세요
MetaMask Flask를 설치하세요
MetaMask Snaps 가이드를 참고하세요
Twitter, GitHub discussions, Discord에서 저희와 소통하세요
가까운 지역에서 열리는 다음 해커톤에서 저희 팀을 만나보세요! 즐거운 BUIDLing ⚒️
면책 조항: MetaMask Snaps는 일반적으로 Consensys Software 이외의 제3자에 의해 개발됩니다. 제3자가 개발한 MetaMask Snaps의 사용은 전적으로 본인의 판단과 책임 하에 이루어지며, 그로 인해 발생하는 손실이나 피해에 대한 책임은 전적으로 사용자 본인에게 있음에 동의하는 것으로 간주됩니다. Consensys는 제3자가 개발한 MetaMask Snaps에 대해 구두 또는 서면을 불문하고 어떠한 명시적 또는 묵시적 보증도 하지 않으며, 제3자가 개발한 Snaps에 대한 모든 책임을 부인합니다. 블록체인 관련 소프트웨어 사용에는 위험이 따르며, MetaMask Snaps를 사용함으로써 해당 위험을 전적으로 감수하는 것에 동의하게 됩니다.