bhlee4980

发布于 2024-04-16到 Mirror 阅读

[KOR] Minting NFTs from Ethereum or OP Mainnet

원문 링크:

https://blog.oplabs.co/minting-nfts-from-mainnet-or-op/?ref=the-optimistic-dev-blog-newsletter


Kiwi News의 게스트 포스트에서는 L1과 L2 모두에서 NFT를 발행하여 이더리움 유동성을 활용하는 방법에 대해 설명합니다.


이더리움 메인넷은 여전히 ​​OP보다 약 100배 더 많은 ETH 유동성을 보유하고 있습니다 . 동시에 우리 모두는 사용자가 L2 스마트 계약에 참여하여 모든 간단한 작업에 대해 50달러의 가스 요금을 지불하지 않기를 원합니다.

그렇다면 L2 계약을 사용하여 NFT를 발행하는 동안 어떻게 메인넷 유동성을 활용할 수 있을까요?

우리는 Kiwi News 프로젝트에서 바로 이 딜레마에 직면했습니다 . 암호화 기술, 제품 및 문화 콘텐츠에 초점을 맞춘 Hacker News와 유사한 링크 수집기입니다.

Kiwi는 Farcaster와 유사한 알고리즘(" 조정 설정 "이라고 함) 을 기반으로 구축된 앱이자 프로토콜입니다 . 이는 모든 사람이 Kiwi 네트워크를 포크하고 자신의 앱을 실행하여 다양한 알고리즘, 조정 등을 통해 콘텐츠에 액세스할 수 있음을 의미합니다.

하지만 실제로 앱을 찬성 투표, 링크 제출, 댓글 작성에 사용하려면 사용자는 먼저 NFT를 구매해야 합니다. Ethereum 거래를 보내기 위해 가스를 지불해야 하거나 Kiwi News에서 Farcaster 계정을 만들 때 비용을 지불해야 하는 것처럼 참여하려면 OP NFT를 발행해야 합니다.

하지만 우리는 실제로 OP 메인넷에서 NFT 판매를 시작하지 않았습니다. NFT는 처음에는 이더리움에서만 사용할 수 있었지만 $PEPE 매니아 기간 동안 $15 NFT를 발행하는 데 $19의 비용이 들었습니다 . 그래서 우리는 OP 메인넷으로 이전하기로 결정했습니다.

그리고 그것은 확실히 윈윈(win-win)처럼 보였습니다. 사용자는 더 적은 비용을 지불했고 우리는 동일한 금액을 벌었으며 기술적으로 가격을 인상할 수도 있었습니다.

그러나 우리는 대부분의 사람들, 심지어 오랜 이더리움 사용자들조차도 OP 메인넷에 돈이 연결되어 있지 않다는 것을 빨리 알게 되었습니다. 물론 브리지로 갈 수도 있지만 웹사이트에서 제거하는 것은 전반적인 판매 전환율을 낮추는 것을 의미했습니다. 그리고 오래된 유통 격언처럼 “물고기가 있는 곳에서 낚시를 해야” 합니다.

그래서 우리는 NFT 채굴을 L1과 L2 모두에서 사용할 수 있도록 하여 이 문제를 해결하기로 결정했습니다.

기술적 세부 사항

문제는 다음과 같습니다. NFT 계약은 L2에 있으며 mintWithRewards(...)NFT를 생성하기 위해 호출할 수 있는 Zora의 기능만 있습니다. 그러나 새로운 Kiwi News 사용자는 이더리움 메인넷에만 자금을 보유할 수 있습니다.

OP 메인넷에 자금이 있다면 정말 좋습니다. NFT를 직접 구매하고 발행할 수 있습니다.

그러나 이더리움 메인넷에 자금이 있는 경우 먼저 이 자금을 OP 메인넷에 브리지하고 이상적으로는 브리지 프로세스 중에 NFT를 구매하도록 해야 합니다.

이제 어떤 상황에서도 사용자가 여러 거래에 서명하는 것을 원하지 않습니다. 이렇게 하면 이탈률이 높아지고 전체 프로세스가 더 번거로워지기 때문입니다. 연속해서 여러 거래를 확인해야 한다는 것은 문제가 발생할 가능성이 더 높다는 것을 의미하므로 우리는 브리징과 NFT 구매를 원자적으로 결합하는 방법을 모색하기 시작했습니다.

그럼 이제 실제 코드로 들어가 보겠습니다.

우선 Optimism 시스템에는 L1과 L2 모두에 API가 있다는 것을 이해해야 합니다. 예를 들어, L2에서 계약을 호출하여 L1으로 자금을 인출할 수 있습니다. 또는 L1에서 함수를 호출하여 L2에 직접 입금할 수 있습니다.

Ethereum Mainnet의 OptimismPortal( Etherscan , 소스 코드 )에는 다음과 같은 기능이 있으므로 이러한 인터페이스는 특히 유용합니다.

OptimismPortal.depositTransaction(...)

/// @notice Accepts deposits of ETH and data, and emits a TransactionDeposited event for use in
///         deriving deposit transactions. Note that if a deposit is made by a contract, its
///         address will be aliased when retrieved using `tx.origin` or `msg.sender`. Consider
///         using the CrossDomainMessenger contracts for a simpler developer experience.

/// @param _to         Target address on L2.
/// @param _value      ETH value to send to the recipient.
/// @param _gasLimit   Amount of L2 gas to purchase by burning gas on L1.
/// @param _isCreation Whether or not the transaction is a contract creation.
/// @param _data       Data to trigger the recipient with.

function depositTransaction(
    address to,
    uint256 value,
    uint64 gasLimit,
    bool isCreation,
    bytes memory data
)
public
payable;

depositTransaction(...)의 인수가 일반 Ethereum 트랜잭션의 이름 지정과 어떻게 유사해 보이는지 확인하세요 . 함수 호출 세부정보를 인코딩하는 , 및 address to가 있습니다 . 여기서도 거래가 사용할 수 있는 최대 가스를 정의하고 새로운 계약을 생성할지 여부를 정의하는 것은 놀라운 일이 아닙니다.uint256 valuebytes memory datauint64 gasLimitbool isCreationbytes memory data

depositTransaction(...)내부적으로 브리징 프로세스 중에 L1 호출자의 브리징 프로세스가 성공하면 OP 메인넷 노드가 해당 매개변수와 함께 OP 메인넷에 트랜잭션을 보내기 때문에 의 인수는 유사합니다.

mintWithRewards(...)이는 OP 메인넷에서 Zora의 기능을 사용하여 NFT를 발행할 뿐만 아니라 사용자가 별도의 브리징 및 발행 트랜잭션 없이 이더리움 메인넷에서 이 기능을 호출할 수 있도록 허용하려는 경우에 특히 유용합니다 .

그럼 실제로 여기서 코드를 자세히 살펴보겠습니다. 다음은 Zora를 통해 배포된 OP 메인넷의 NFT 수집 계약에 대한 인터페이스입니다.


function mintWithRewards(
    address recipient,
    uint256 quantity,
    string calldata comment,
    address mintReferral
) external payable returns (uint256);

이 기능에는 address recipientNFT 수신자, uint256 quantity발행되어야 하는 NTF 수를 정의하는 a, string calldata comment온체인 댓글용 a, address mintReferral민트 추천을 위한 추천인의 크레딧을 위한 a가 필요합니다.

따라서 우리가 OP 메인넷과 ETH 메인넷 모두에서 작동하는 NFT 민트 버튼을 구축하는 프런트엔드 엔지니어의 역할을 맡는다고 가정하면, 계산해야 할 사항에 대한 단계별 프로세스는 다음과 같습니다.

  1. OP 메인넷에서 사용자의 ETH 잔액을 확인하세요. 사용자가 NFT를 발행할 여유가 있는 경우 사용자에게 mintWithRewards(...)Optimism에 직접 전화하도록 요청하세요.

  2. 사용자의 OP 메인넷에 충분한 ETH가 없는 경우 사용자의 이더리움 메인넷 잔액을 확인하세요. 사용자가 ETH 메인넷에서 NFT를 구매할 여유가 없는 경우 사용자에게 이에 대해 알립니다. 그렇지 않으면 3단계를 계속 진행하세요.

import { fetchBalance, getAccount } from "@wagmi/core";
import { mainnet, optimism } from "wagmi/chains";
Import { utils } from “ethers”;

const { address } = getAccount();
if (!address) {
  throw new Error("Account not available");
}

const balance = {
  mainnet: (await fetchBalance({ address, chainId: mainnet.id })).value,
  optimism: (await fetchBalance({ address, chainId: optimism.id })).value,
};

const mintPriceETH = utils.parseEther(“0.00256”);

if (balance.optimism >= mintPriceETH) {
  // mint on OP mainnet
} else if (balance.mainnet >= mintPriceETH) {
  // mint on ETH mainnet
} else {
  throw new Error(“Insufficient balance”);
}

3. 이제 사용자가 OptimismPortal을 통해 ETH 메인넷에서 NFT를 발행할 것이라는 것을 알았으므로 두 개의 ETH 호출을 준비해야 합니다. 하나는 depositTransaction(...)L1을 호출하기 위한 것이고, 다른 하나는 mintWithRewards(...)L2를 호출하기 위한 것입니다. OP 메인 depositTransaction(...)넷 에서 실행될 두 번째 호출을 의 에 전달합니다 bytes memory data. 그 방법은 다음과 같습니다.

3.1. L2에서 함수 mintWithRewards(...)에 대한 입력을 수집하여 함수 호출 데이터를 구축합니다 . mintWithRewards(...)우리는 에테르를 사용하여 interface.encodeFunctionData(name, [...inputs])호출을 16진수 문자열로 패키징합니다.

import { getAccount } from "@wagmi/core";
import { Contract } from "@ethersproject/contracts";
import { mainnet, optimism } from "wagmi/chains";

import { getProvider } from “./viem-adapter.mjs”;

const nftAddress = 0xabc…;
const nftABI = [{...}];

function prepareL2Call() {
  const { address } = getAccount();
  const opProvider = getProvider({ chainId: optimism.id });
  const contract = new Contract(nftAddress, nftABI, opProvider);
  const recipient = address;
  const quantity = 1;
  const comment = “minting this from mainnet!”
  const referrer = null;
  return contract.interface.encodeFunctionData("mintWithRewards", [
    recipient,
    quantity,
    comment,
    referrer,
  ]);
}

3.2. 의 경우 depositTransaction(...)함수 호출의 대상을 로 선택 하고 전달하려는 ETH 값을 로 address to설정합니다 . 에 대해서는 Optimism에 대한 ETH 콜 비용을 사용자 잔액으로 시뮬레이션해야 합니다. 하지만 사용자의 ETH 잔액이 부족합니다. 기억하시나요? 따라서 OP 메인넷 공급자 및 사용자 주소와의 모든 호출에는 오류가 발생합니다.uint256 valueaddress touint64 gasLimitestimateGas

따라서 mintWithRewards(...)수동으로 함수를 호출하고 코드에서 이 값을 사용하여 정적 게스트를 발견하는 것이 좋습니다.

다른 인수의 경우 3.1 단계에서 생성된 호출 데이터가 포함되어 있습니다 bool isCreation.falsebytes memory data

import { prepareWriteContract } from "@wagmi/core";
import { mainnet } from "wagmi/chains";

const optimismPortalAddress = 0x…;
const optimismPortalABI = [{...}, …];

async function writeToDeposit(nftAddress, price, data) {
  const isCreation = false;
  const gasLimit = 170000;

  return await prepareWriteContract({
    address: optimismPortalAddress,
    abi: optimismPortalABI,
    functionName: "depositTransaction",
    args: [nftAddress, price, gasLimit, isCreation, data],
    value: price,
    chainId: mainnet.id,
  });
}

3.3. 중요한 것은 L1 통화 uint256 value에 대해 최소한 금액 이상을 입금해야 한다는 것입니다 . msg.value이를 통해 일부 Ether가 Optimism에 예치되어 mintWithRewards(...)통화에 사용할 수 있게 됩니다. msg.value의 값으로 설정하여 이를 수행합니다 price.

3.4. 마지막으로 모든 인수를 조합한 후 사용자에게 이더리움 메인넷에 대한 이 트랜잭션에 서명하라는 메시지를 표시합니다.

import { useContractWrite } from "wagmi";
// …

function prepareL2Call(...) {...}
async function writeToDeposit(...) {...}
// …


const BuyButton = (props) => {
  // …
  const { write } = useContractWrite(config);
  // …

  return (
    <button disabled={!write} onClick={() => write?.()}>
    Buy NFT
    </button>
  );
}

그리고 그게 다야! 이것이 Ethereum 메인넷에서 직접 호출을 프로비저닝하면서 Optimism에서 NFT를 원자적으로 생성하려는 경우 수행해야 하는 작업입니다.

코드 조각은 우리가 Kiwi News에서 사용하는 프로덕션 코드와 정확히 일치하지는 않지만 우리가 오픈 소스로 제공한 코드와 매우 유사합니다. GitHub 에서 전체 준비 순서와 자세한 내용을 확인할 수 있습니다 . 실제로 NFT 발행 페이지 로 이동하여 직접 사용해 볼 수 있습니다 .

이제 OptimismPortal의 depositTransaction(...)기능을 사용하는 것이 L1에서 L2로 이동하는 유일한 옵션은 아닙니다. 현재 유사한 서비스를 제공하는 거래소도 많이 있습니다. 그러나 OP 포털의 특징은 msg.senderETH 메인넷에서 거래에 서명하고 보낸 주소를 보존한다는 것입니다. 이는 귀하의 dapp이 합법적이어야 하는 해당 주소에 의존할 때 특히 중요할 수 있습니다.

결론

NFT를 이더리움에서 OP 메인넷으로 마이그레이션할 때 모든 사용자가 OP 메인넷에서도 L1 유동성을 발행할 수 있도록 허용하는 방법이 필요했습니다.

OptimismPortal은 단일 원자 거래에서 자금을 연결하고 ETH 호출을 실행하는 편리한 기능을 제공하여 사용자가 호출을 보낼 때 높은 성공 가능성을 제공합니다.

우리는 Ethereum과 L2 잔액을 모두 확인하여 각 사용자에게 올바른 호출을 제공하는 React.js 코드를 자세히 설명했습니다. 사용자에게 OP ETH가 없으면 포털을 통해 연결하여 직접 온보딩됩니다.

앞으로는 더욱 흥미로운 기술 기회를 기대하고 있습니다. 예를 들어, 우리는 모든 Ethereum 사용자가 코드를 더 쉽게 호출할 수 있도록 유사한 포털 트랜잭션을 통해 기본 체인의 유동성을 원자적으로 활용할 수 있기를 원합니다.

이 게시물이 귀하의 업무에 도움이 되기를 바랍니다. Kiwi News에서는 항상 최신 뉴스, 블로그 게시물, GitHub 리포지토리 등 가능한 한 많은 유틸리티를 제공하여 생태계에 서비스를 제공하기 위해 노력하고 있습니다. 우리는 당신을 독자로 모시고 싶습니다! https://kiwinews.xyz 에서 확인해 보세요.