Skip to main content

Documentation Index

Fetch the complete documentation index at: https://daehan-base.mintlify.app/llms.txt

Use this file to discover all available pages before exploring further.

Base Account를 사용하면 단일 트랜잭션에서 여러 온체인 콜을 전송할 수 있습니다. 이를 통해 여러 단계의 상호작용을 단 한 번의 클릭으로 줄여 UX를 향상시킵니다. 배치 트랜잭션을 활용하고 싶은 일반적인 예는 ERC-20 approve 이후 스왑입니다. EIP-5792에 정의된 wallet_sendCalls RPC 메서드를 사용하여 배치 트랜잭션을 제출할 수 있습니다.
동영상 콘텐츠를 선호하시나요?이 페이지의 마지막 섹션에 구현을 자세히 다루는 동영상 가이드가 있습니다.

설치

Base Account SDK를 설치합니다:
npm install @base-org/account

설정

SDK 초기화

Base Account SDK 인스턴스를 가져오고 생성합니다:
batchTransactions.tsx
import { createBaseAccountSDK } from "@base-org/account";

const sdk = createBaseAccountSDK({
  appName: "Base Account SDK 데모",
  appLogoUrl: "https://base.org/logo.png",
});

const provider = sdk.getProvider();

기본 배치 트랜잭션

간단한 다중 전송

단일 트랜잭션에서 여러 ETH 전송을 보냅니다:
batchTransactions.tsx
import { createBaseAccountSDK, getCryptoKeyAccount } from "@base-org/account";
import { numberToHex, parseEther } from "viem";

const sdk = createBaseAccountSDK({
  appName: "배치 트랜잭션 데모",
  appLogoUrl: "https://base.org/logo.png",
});

const provider = sdk.getProvider();

async function sendBatchTransfers() {
  try {
    // 크립토 계정 가져오기
    const cryptoAccount = await getCryptoKeyAccount();
    const fromAddress = cryptoAccount?.account?.address;

    // 배치 콜 준비
    const calls = [
      {
        to: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
        value: numberToHex(parseEther("0.001")), // 0.001 ETH
        data: "0x", // 간단한 전송을 위한 빈 데이터
      },
      {
        to: "0x742d35Cc6634C0532925a3b844Bc9e7595f6E456",
        value: numberToHex(parseEther("0.001")), // 0.001 ETH
        data: "0x", // 간단한 전송을 위한 빈 데이터
      },
    ];

    // 배치 트랜잭션 전송
    const result = await provider.request({
      method: "wallet_sendCalls",
      params: [
        {
          version: "2.0.0",
          from: fromAddress,
          chainId: numberToHex(base.constants.CHAIN_IDS.base),
          atomicRequired: true, // 모든 콜이 성공하거나 모두 실패
          calls: calls,
        },
      ],
    });

    console.log("Batch transaction sent:", result);
    return result;
  } catch (error) {
    console.error("Batch transaction failed:", error);
    throw error;
  }
}

컨트랙트 상호작용

ERC-20 승인 및 NFT(ERC-721) 민팅

일반적인 패턴은 NFT 컨트랙트가 ERC-20을 이동하도록 승인한 다음 NFT(ERC-721)를 민팅하는 것입니다:
batchTransactions.tsx
import {
  createBaseAccountSDK,
  getCryptoKeyAccount,
  base,
} from "@base-org/account";
import { numberToHex, parseUnits, encodeFunctionData } from "viem";

// approve를 위한 ERC-20 ABI
const erc20Abi = [
  {
    inputs: [
      { name: "spender", type: "address" },
      { name: "amount", type: "uint256" },
    ],
    name: "approve",
    outputs: [{ name: "", type: "bool" }],
    stateMutability: "nonpayable",
    type: "function",
  },
] as const;

// mint 함수를 위한 ERC721 ABI
const erc721Abi = [
  {
    inputs: [
      { name: "to", type: "address" },
      { name: "tokenId", type: "uint256" },
    ],
    name: "mint",
    outputs: [],
    stateMutability: "nonpayable",
    type: "function",
  },
] as const;

// Base Sepolia의 USDC 컨트랙트 주소
const USDC_ADDRESS = "0x036CbD53842c5426634e7929541eC2318f3dCF7e";

// Base Sepolia의 NFT 컨트랙트 주소
const NFT_CONTRACT_ADDRESS = "0x82039e7C37D7aAac98D0F4d0A762F4E0d8c8DC273";

async function approveAndTransfer() {
  const sdk = createBaseAccountSDK({
    appName: "ERC-20 배치 데모",
    appLogoUrl: "https://base.org/logo.png",
  });

  const provider = sdk.getProvider();
  const cryptoAccount = await getCryptoKeyAccount();
  const fromAddress = cryptoAccount?.account?.address;

  // 첫 번째 approve 콜 인코딩 - NFT 컨트랙트에 USDC 승인
  const call1Data = encodeFunctionData({
    abi: erc20Abi,
    functionName: "approve",
    args: [
      NFT_CONTRACT_ADDRESS,
      parseUnits("1000", 6), // USDC는 소수점 6자리
    ],
  });

  // 두 번째 콜 인코딩 - 사용자 주소로 NFT 민팅
  const call2Data = encodeFunctionData({
    abi: erc721Abi,
    functionName: "mint",
    args: [fromAddress as `0x${string}`, BigInt("1")],
  });

  const result = await provider.request({
    method: "wallet_sendCalls",
    params: [
      {
        version: "2.0.0",
        from: fromAddress,
        chainId: numberToHex(base.constants.CHAIN_IDS.baseSepolia),
        atomicRequired: true,
        calls: [
          {
            to: USDC_ADDRESS,
            data: call1Data,
          },
          {
            to: NFT_CONTRACT_ADDRESS,
            data: call2Data,
          },
        ],
      },
    ],
  });

  return result;
}

고급 기능

지갑 기능 확인

배치 트랜잭션을 보내기 전에 지갑이 원자적 배치를 지원하는지 확인할 수 있습니다:
batchTransactions.tsx
async function checkCapabilities() {
  const provider = sdk.getProvider();

  try {
    const cryptoAccount = await getCryptoKeyAccount();
    const address = cryptoAccount?.account?.address;

    const capabilities = await provider.request({
      method: "wallet_getCapabilities",
      params: [address],
    });

    const baseCapabilities = capabilities[base.constants.CHAIN_IDS.base];

    if (baseCapabilities?.atomicBatch?.supported) {
      console.log("원자적 배치가 지원됩니다");
      return true;
    } else {
      console.log("원자적 배치가 지원되지 않습니다");
      return false;
    }
  } catch (error) {
    console.error("Failed to check capabilities:", error);
    return false;
  }
}

비원자적 배치

일부 실패해도 콜을 순차적으로 실행하고 싶을 때:
batchTransactions.tsx
const result = await provider.request({
  method: "wallet_sendCalls",
  params: [
    {
      version: "2.0.0",
      from: fromAddress,
      chainId: numberToHex(base.constants.CHAIN_IDS.base),
      atomicRequired: false, // 부분 실행 허용
      calls: calls,
    },
  ],
});

배치 트랜잭션 결과 가져오기

wallet_getCallsStatus는 이전에 wallet_sendCalls로 제출한 배치의 실행 상태를 반환합니다. wallet_sendCalls가 반환한 callsId를 캡처한 다음 배치가 확인되거나 실패할 때까지 상태를 폴링합니다.
batchTransactions.tsx
async function trackBatchTransaction(
  calls: Array<{
    to: `0x${string}`;
    data: `0x${string}`;
    value?: `0x${string}`;
  }>
) {
  const cryptoAccount = await getCryptoKeyAccount();
  const fromAddress = cryptoAccount?.account?.address;

  const callsId = await provider.request({
    method: "wallet_sendCalls",
    params: [
      {
        version: "2.0.0",
        from: fromAddress,
        chainId: numberToHex(base.constants.CHAIN_IDS.base),
        atomicRequired: true,
        calls,
      },
    ],
  });

  try {
    const status = await provider.request({
      method: "wallet_getCallsStatus",
      params: [callsId],
    });

    if (status.status === 200) {
      console.log("배치 완료", status.receipts);
    } else if (status.status === 100) {
      console.log("배치 대기 중", status.id);
    } else {
      console.error("배치 실패", status.status);
    }

    return status;
  } catch (error: any) {
    if (error.code === 4200) {
      throw new Error("제공된 callsId에 대한 배치를 찾을 수 없습니다.");
    }

    if (error.code === 4100) {
      throw new Error(
        "연결된 지갑이 wallet_getCallsStatus를 지원하지 않습니다."
      );
    }

    if (error.code === -32602) {
      throw new Error("callsId 파라미터가 유효하지 않습니다.");
    }

    throw error;
  }
}
wallet_getCallsStatus는 제출한 배치 호출의 상태를 조회할 때 사용합니다.
가스에 대한 더 많은 제어가 필요하신가요?gasLimitOverride 기능을 사용하여 배치의 개별 콜에 대한 가스 한도를 재정의할 수 있습니다. 이는 스왑과 같이 비결정적 가스 소비가 있는 콜에 유용합니다. 지원되는 기능은 사용 중인 지갑 및 프로바이더 설정과 함께 확인하세요.

동영상 가이드