Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

EIP-7702를 사용한 세션 키

세션 키는 계정에 서명할 수 있는 두 번째 키로, 소유자가 설정한 권한 및 만료 기간으로 제한됩니다. 소유자 키는 한 번 서명하여 권한을 부여합니다. 그 후 앱, 백엔드 또는 에이전트가 세션 키로 트랜잭션을 보내고 사용자는 각 트랜잭션을 승인할 필요가 없습니다.

이 가이드는 Stable 테스트넷에서 Alchemy Wallet API를 사용합니다. EOA는 감사된 스마트 계정인 Modular Account v2에 위임하므로 위임 계약을 작성하거나 배포할 필요가 없습니다.

작동 방식

  1. EOA 위임. 소유자는 EOA를 Modular Account v2로 지정하는 EIP-7702 권한을 서명합니다. EOA는 주소, 키 및 잔액을 유지합니다.
  2. 세션 부여. 소유자는 세션 부여에 서명합니다. 세션 키의 주소, 권한 및 만료 기간입니다. 아직 온체인에 기록된 내용은 없습니다.
  3. 세션 키로 전송. 유일한 서명자가 세션 키인 클라이언트가 소유자 계정으로 호출을 보냅니다. 첫 번째 호출은 온체인에 세션을 설치합니다.

전제 조건

  • Node 22 이상.
  • Stable 테스트넷이 활성화된 Alchemy 앱 및 API 키.
  • 선택 사항: Alchemy Gas Manager 정책 ID. 정책을 사용하면 Alchemy가 가스를 지원합니다. 정책이 없으면 EOA가 USDT0으로 가스를 지불하고 테스트넷 잔액이 필요합니다.
npm install @alchemy/wallet-apis viem
added 2 packages

1단계: 클라이언트 구성

소유자가 서명한 클라이언트 하나를 생성합니다. Wallet API는 기본적으로 EIP-7702 모드에서 실행되므로 소유자의 EOA 주소가 스마트 계정 주소입니다.

// config.ts
import { alchemyWalletTransport, createSmartWalletClient } from "@alchemy/wallet-apis";
import { createPublicClient, http, type Hex } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { stableTestnet } from "viem/chains";
 
export const chain = stableTestnet;
export const transport = alchemyWalletTransport({ apiKey: process.env.ALCHEMY_API_KEY! });
export const paymaster = process.env.ALCHEMY_GAS_POLICY_ID
  ? { policyId: process.env.ALCHEMY_GAS_POLICY_ID }
  : undefined;
 
export const USDT0_ADDRESS = "0x78Cf24370174180738C5B8E352B6D14c83a6c9A9";
 
export const owner = privateKeyToAccount(process.env.OWNER_PRIVATE_KEY as Hex);
export const account = owner.address;
 
export const ownerClient = createSmartWalletClient({ transport, chain, signer: owner, paymaster });
export const publicClient = createPublicClient({ chain, transport: http() });

2단계: EOA 위임

세션은 이미 위임된 계정에만 설치할 수 있습니다. 빈 호출 세트를 보냅니다. Wallet API는 누락된 위임을 감지하고 동일한 트랜잭션에서 EIP-7702 권한을 제출합니다.

// delegate.ts
import { account, ownerClient, publicClient } from "./config";
 
// 위임된 EOA는 코드 0xef0100 || 위임 주소를 가집니다.
const code = await publicClient.getCode({ address: account });
 
if (code?.startsWith("0xef0100")) {
  console.log("already delegated to", `0x${code.slice(8)}`);
} else {
  const { id } = await ownerClient.sendCalls({ calls: [] });
  const status = await ownerClient.waitForCallsStatus({ id });
  if (status.status !== "success") throw new Error("delegation failed");
  console.log("delegated in tx", status.receipts?.[0]?.transactionHash);
}
delegated in tx 0x...

3단계: 범위가 지정된 세션 키 부여

세션 키를 생성하고 사용 사례에 맞는 가장 좁은 권한을 부여합니다. 이 예제에서는 키가 1시간 동안 최대 10 USDT0를 전송할 수 있도록 합니다.

// grant.ts
import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
import { parseUnits } from "viem";
import { account, ownerClient, USDT0_ADDRESS } from "./config";
 
// 이 키는 이를 사용하는 앱 또는 에이전트가 실행되는 곳에 저장합니다.
export const sessionKey = privateKeyToAccount(generatePrivateKey());
const expirySec = Math.floor(Date.now() / 1000) + 60 * 60;
 
export const permissions = await ownerClient.grantPermissions({
  account,
  expirySec,
  key: { publicKey: sessionKey.address, type: "secp256k1" },
  permissions: [
    {
      type: "erc20-token-transfer",
      data: { address: USDT0_ADDRESS, allowance: parseUnits("10", 6) },
    },
  ],
});
 
console.log("session key", sessionKey.address);
console.log("expires    ", new Date(expirySec * 1000).toISOString());
session key 0x...
expires     2026-10-12T13:00:00.000Z

permissions.context는 부여 증명입니다. 세션 키가 보내는 모든 호출과 함께 이를 전달하십시오.

가스 정책이 가스를 후원하지 않는 경우, 세션 키의 트랜잭션은 계정의 USDT0에서 가스를 지불합니다. 지출 상한을 설정하려면 gas-limit 권한을 추가하십시오.

권한 유형

유형data부여 내용
erc20-token-transferaddress, allowance하나의 ERC-20 토큰에 대한 transfer 및 approve, 총 allowance까지
native-token-transferallowance총 allowance까지의 네이티브 값 전송
gas-limitlimit세션 키가 계정에서 사용할 수 있는 가스
contract-accessaddress하나의 계약에 대한 모든 함수
functions-on-contractaddress, functions하나의 계약에 대한 나열된 함수 선택자
functions-on-all-contractsfunctions모든 계약에 대한 나열된 함수 선택자
account-functionsfunctions계정 자체에 대한 나열된 함수 선택자
root없음만료 전까지 소유자가 할 수 있는 모든 것

4단계: 세션 키로 트랜잭션 보내기

소유자의 계정 역할을 하는 세션 키가 유일한 서명자인 두 번째 클라이언트를 생성합니다. 소유자 키는 여기부터 사용되지 않습니다.

// send.ts
import { createSmartWalletClient } from "@alchemy/wallet-apis";
import { encodeFunctionData, erc20Abi, parseUnits } from "viem";
import { account, chain, paymaster, transport, USDT0_ADDRESS } from "./config";
import { permissions, sessionKey } from "./grant";
 
const sessionClient = createSmartWalletClient({ transport, chain, signer: sessionKey, account, paymaster });
 
const { id } = await sessionClient.sendCalls({
  calls: [
    {
      to: USDT0_ADDRESS,
      data: encodeFunctionData({
        abi: erc20Abi,
        functionName: "transfer",
        args: ["0xRecipient...", parseUnits("1", 6)],
      }),
    },
  ],
  capabilities: { permissions },
});
 
const status = await sessionClient.waitForCallsStatus({ id });
if (status.status !== "success") throw new Error("session-key call failed");
console.log("sent in tx", status.receipts?.[0]?.transactionHash);
sent in tx 0x...

부여된 권한 외부의 호출은 실패하고 자금을 이동하지 않습니다. 예: 남은 허용량을 초과하는 전송 또는 다른 토큰의 전송.

세션 종료

세션은 expirySec에 작동을 중지합니다. 만료 기간을 짧게 유지하고 이전 세션이 끝나면 새 세션을 부여하십시오.

위임 해제

스마트 계정을 완전히 제거하려면 소유자는 EOA를 영주소에 다시 위임합니다. EOA는 이 트랜잭션을 직접 보내고 USDT0으로 가스를 지불합니다.

// undelegate.ts
import { createWalletClient, http, zeroAddress } from "viem";
import { chain, owner } from "./config";
 
const walletClient = createWalletClient({ account: owner, chain, transport: http() });
 
const authorization = await walletClient.signAuthorization({
  contractAddress: zeroAddress,
  executor: "self", // the EOA sends the transaction, so the authorization nonce is its nonce + 1
});
 
const hash = await walletClient.sendTransaction({
  to: owner.address,
  authorizationList: [authorization],
  maxPriorityFeePerGas: 0n,
});
console.log("delegation cleared in tx", hash);
delegation cleared in tx 0x...

Alchemy 플랜에 위임 해제를 위한 후원 정책이 포함되어 있는 경우, ownerClient.undelegateAccount()는 가스 후원과 함께 동일한 재설정을 보냅니다.

고려 사항

  • 세션 키는 자격 증명입니다. 이를 소유한 사람은 만료될 때까지 권한 내에서 행동할 수 있습니다. 다른 개인 키처럼 저장하십시오.
  • 위임은 지속됩니다. EOA는 소유자가 위임을 해제하거나 교체할 때까지 Modular Account v2를 실행합니다. 업그레이드할 의향이 있는 키로 테스트하십시오.
  • EOA당 하나의 위임. 구독 관리자와 같은 다른 계약에 위임하면 Modular Account v2가 대체되고 세션이 비활성화됩니다.

다음 추천