본문으로 건너뛰기

Web2 애플리케이션을 위한 NFT

Web3로 넘어가기 위한 첫 번째 단계로, 블록체인 기술을 사용하여 디지털 자산의 소유권을 분산시켜 봅시다. 이를 통해 개발자의 참여나 통제 없이 디지털 자산이 교환되고 거래되는 사용자 소유 경제를 만들 수 있습니다. 나중에 다음 단계로, 대체 가능한 토큰을 추가하는 방법에 대해서도 논의할 것입니다.

이전에 논의한 것처럼, Web3 세계에서 NFT는 자산의 소유권을 나타내는 데 사용됩니다. 이는 사용자가 소유한 모든 것이 될 수 있습니다. 예를 들어 게임의 경우 캐릭터, 업그레이드, 제작 재료, 스킨 등이 될 수 있습니다. 그러나 NFT는 블록체인에 존재하고 나머지 애플리케이션은 기존 서버에서 동작하므로, 서로 다른 두 세계를 연결할 방법을 찾아야 합니다.

블록체인 어플리케이션 아키텍쳐

우선 Web2 어플리케이션의 일반적인 아키텍처에 대해 개략적으로 설명하겠습니다. 대부분의 경우 기존의 클라이언트-서버 모델이 사용됩니다.

image

이러한 아키텍처에는 일반적으로 3개의 레이어가 있습니다.

  • 데이터베이스 - 어플리케이션의 데이터를 저장합니다. 이것은 단일 혹은 여러 개의 데이터베이스일 수 있지만 대부분 구현에 따라 달라집니다. 논리 구조상 하나의 데이터베이스로 볼 수 있습니다.
  • 서버 - 중앙 집중식 웹 서버입니다. 다양한 아키텍처 패턴(모놀리틱, 마이크로서비스, 서버리스) 및 기술을 사용하여 구현될 수 있지만 이도 역시 논리 구조상 하나의 서버로 간주할 수 있습니다.
  • 클라이언트 - 클라이언트 측 애플리케이션 사용자가 직접 상호 작용합니다. 웹, 모바일 또는 데스크탑과 같은 다양한 클라이언트 유형이 존재합니다. 나중에 논의할 블록체인 통합과 관련하여 이러한 클라이언트 간에 차이가 존재합니다.

이제 dApp 아키텍처와 비교해 보겠습니다.

image

이러한 아키텍처에는 클라이언트 애플리케이션이라는 공통 구성 요소가 있음을 알 수 있습니다. 즉, 이를 이용해 위 두 가지 아키텍처를 함께 연결할 수 있음을 의미합니다.

image

예리한 독자라면 서버와 RPC 노드 간의 추가 연결을 발견하였을 것입니다. 이는 클라이언트-서버 아키텍처에서 클라이언트를 신뢰할 수 없기 때문에 필요합니다. 그렇기 때문에 클라이언트에서 수행되는 모든 작업은 백엔드 서버에서 유효성이 검사되어야 합니다. 그러나 우리의 경우에는 기본적으로 Web2 서버와 스마트 컨트랙트라는 두 개의 백엔드가 있으므로, 두 가지 가능한 유효성 검사 방식이 가능하기 때문에 복잡한 구조가 형성됩니다.

  • 클라이언트는 블록체인 데이터와 관련된 서버에서 작업을 수행합니다. 이 경우 서버는 블록체인과의 통신을 통해, 유효한 데이터가 제공되었는지 확인해야 합니다.
  • 클라이언트는 스마트 컨트랙트에 대한 작업을 수행하고, 이는 서버 소유 데이터와 관련되어 있습니다. 스마트 컨트랙트는 서버 소유 데이터를 확인하기 위해 서버와 직접 통신할 수 없기 때문에, 데이터의 진위를 확인하기 위해 다른 방법을 사용해야 합니다. 블록체인 용어로 이러한 서버를 오라클이라고 합니다. 나중에 이러한 접근 방식을 모두 구현하는 방법을 살펴보도록 하겠습니다.

이제 클라이언트 유형이 중요해지기 시작하는 지점에 도달했습니다. 특히 dApp 지불 모델에서 문제가 발생합니다. 사용자는 가스를 사용하여 블록체인 인프라에 대한 비용을 지불하므로, 자금은 인프라 제공자에게 직접 전달됩니다. 또한 사용자는 은행이나 결제 서비스와 같은 중개자를 거치지 않고 블록체인에서 직접 결제합니다. 이 접근 방식은 모바일 앱 스토어(Google 플레이 스토어 및 Apple 앱 스토어)와 상충됩니다. 그들은 허락 없이 해당 플랫폼 내 결제를 허용하지 않습니다. 정책의 일부 변화가 일어나기 시작했지만(예: Apple 대 Epic Games), 이 글을 쓰는 시점에서 블록체인 지원 애플리케이션을 스토어에 올리는 것은 아마도 거부될 것입니다. 예를 들어 Android에서 플레이 스토어를 사용하지 않는 등 이러한 제한을 우회할 수 있는 몇 가지 방법이 있지만, 이러한 모든 방법은 사용성 측면에서 수준 이하이거나 스토어에서 아예 금지될 위험이 있습니다. 그렇기 때문에 모바일 애플리케이션의 경우 다른 접근 방식이 필요합니다.

때로는 앞으로 나아가기 위해 한 걸음 뒤로 물러나야 합니다. 우리의 경우 모바일 클라이언트의 문제를 해결하기 위해 블록체인 통합용 클라이언트와 Web2 서버용 클라이언트의 두 클라이언트를 갖는 초기 개념으로 돌아갈 수 있습니다. 블록체인 클라이언트는 상점의 제약을 받지 않는 일반적인 웹 애플리케이션일 수 있습니다. 또한 블록체인과 기존 애플리케이션 간의 연결 지점 역할을 할 수 있습니다.

image

이 아키텍처에서 모바일 클라이언트는 여전히 블록체인과 통신할 수 있지만, 지갑 연결이나 지불이 필요하지 않은 읽기 전용 방식으로만 가능합니다. 대신 블록체인의 모든 작업은 웹 클라이언트에서 발생합니다. 또한 이 가이드에서는 이중 클라이언트 아키텍처를 사용할 것인데, 이는 두 개의 클라이언트를 병합하는 방식으로 단일 클라이언트가 있는 더 간단한 아키텍처를 직접 만들어낼 수 있기 때문입니다.

이 시점에서, 우리의 아키텍처는 애플리케이션 구축을 시작하는 데 필요한 거의 모든 것을 다룹니다. 그러나 우리는 사용자 소유 경제를 구축하기를 원하기 때문에, 이를 위한 마켓플레이스가 필요합니다. 할 수 있는 선택 중 하나는 이 마켓플레이스를 웹 클라이언트에 넣는 것이지만, 여기에는 한 가지 문제가 있습니다. 스마트 컨트랙트의 스토리지 모델은 복잡한 데이터 쿼리를 제공하는 데 적합하지 않으므로, 인덱서를 사용하여 블록체인에서 적절한 데이터베이스로 데이터를 집계해야 한다는 것입니다.

image

이제 모든 빌딩 블록이 준비되었으며 실제로 이 아키텍처를 구현하는 방법을 알아볼 수 있습니다.

Web2 어플리케이션 내 NFT

하이브리드 Web2 - Web3 아키텍처를 사용하여 완전한 기능을 갖춘 애플리케이션을 구현하려면, 인증 및 권한 부여, 클라이언트 및 서버에서의 원활한 NFT 사용, 적절한 NFT 스토리지 모델과 같은 많은 기술적 문제를 해결해야 합니다. 다음 섹션에서는 이에 대해 자세히 살펴보고 일반적인 패턴과 접근 방식을 설명합니다.

인증 및 승인

우리의 디지털 자산은 블록체인에서 NFT로 표시되기 때문에, Web 2 애플리케이션에서 사용하려면 서버에서 사용을 승인하는 방법이 필요합니다. 기본 아이디어는 매우 간단합니다. 스마트 컨트랙트 메서드를 호출하고 소유자의 계정 ID를 확인하여 블록체인에서 데이터를 읽는 것입니다. 이러한 흐름에는 3명의 참여자가 있습니다.

  • 일부 디지털 자산(NFT)을 사용하려는 클라이언트.
  • NFT용 스마트 컨트랙트. NEAR NFT 표준에 따라 구현되어야 합니다.
  • NFT의 소유권을 확인하고 내부 로직에 따라 사용하는 서버.

일반적인 흐름은 다음과 같습니다.

image

그러나 이러한 권한 부여 과정은 인증 없이는 수행할 수 없으므로, 서버에서도 사용자를 인증할 수 있는 방법이 필요합니다.

블록체인에서 사용자의 신원은 키 쌍으로 표시됩니다. 그러나 NEAR에서는 사용자가 여러 개의 키 쌍을 가질 수 있고, 계정이 별도의 엔터티이므로 인증 절차가 조금 더 복잡합니다.

요청을 인증하기 위해 공개 키 암호화를 사용할 수 있습니다. 클라이언트는 사용자의 개인 키를 사용하여 요청에 서명할 수 있으며 그런 다음 서버는 서명과 키 소유권을 확인할 수 있습니다. 인증이 포함된 일반적인 요청은 다음과 같습니다.

{
"payload": { /* request-specific payload */ },
"accountId": "account.near",
"publicKey": "...",
"timestamp": 1647091283342,
"signature": "..."
}

여기서:

  • accountId – NEAR의 사용자 계정 ID입니다.
  • publicKey - 서명에 사용되는 키 쌍의 공개 키입니다. 해당 계정에 대한 함수 호출 또는 전체 액세스 키여야 합니다.
  • timestamp - 현재 날짜/시간은 서버에서 확인해야 합니다. replay attack을 방지하기 위해 필요합니다. 타임스탬프의 대안은 nonce를 사용하는 것이지만, 이는 조금 더 복잡합니다.
  • signature - 요청 페이로드 및 기타 필드의 서명입니다. 일반적으로 페이로드는 사전에 해시됩니다.

구현에 따라 요청 본문, 헤더 또는 기타 사이드 채널을 사용하여 인증 데이터를 전송할 수 있습니다. 정확한 구현은 사용되는 기술 및 프로토콜에 따라 다릅니다.

서버는 이 데이터를 사용하여, 다음과 같은 접근 방식을 통해 요청을 인증할 수 있습니다.

image

3가지 인증 단계가 서버에서 수행됩니다.

  1. 서명 확인 - 서명이 정확하면 클라이언트가 제공된 공개 키에 대한 개인 키를 실제로 가지고 있음을 확신합니다. 또한 이것은 요청 데이터가 전송 중에 수정되지 않았음을 증명합니다.
  2. 타임스탬프 확인 - replay attack을 방지합니다. 서버는 요청의 타임스탬프가 너무 오래되지 않았는지(예: 생성된 지 10초 이내) 확인할 수 있습니다.
  3. 공개 키 소유권 확인 - view_access_key 메서드를 호출 하여 제공된 공개 키가 실제로 계정과 연결되어 있는지 확인할 수 있습니다.

이러한 인증 방식은 가장 간단한 방식이지만 다음과 같은 몇 가지 주요 단점이 있습니다.

  • RPC 노드에 대한 REST API 호출을 수행하는 것은 성능 관점에서 매번 수행하는 데 비용이 많이 듭니다.
  • 모바일 클라이언트의 요청에 서명할 수 없습니다. 일반적으로 스토리지 정책으로 인해 블록체인에서 연결이 끊어져야 하므로 키 쌍이 없기 때문입니다.
  • 애플리케이션 사용을 시작하려면 NEAR 계정이 필요한데, 이는 온보딩 프로세스를 복잡하게 만듭니다.

첫 번째 문제를 해결하기 위해, 성공적인 NEAR 계정 인증 후 JWT 토큰을 발행하거나 다른 방식으로 연결을 인증할 수 있습니다. 즉, 이는 일종의 "로그인" 역할을 합니다.

image

이것은 일부 애플리케이션에 충분할 수 있지만, 뒤 두 가지 문제를 해결하지 못합니다. 이 모든 문제를 해결하기 위해 2개의 계정을 통한 하이브리드 인증 방식을 사용할 수 있습니다.

  1. "기존의" Web2 계정 - 모든 클라이언트가 이 계정을 사용하여 서버를 호출할 수 있습니다. 예를 들어 간단한 사용자 이름/암호 또는 JWT 토큰을 사용한 OAuth 2 로그인일 수 있습니다.
  2. NEAR 계정 - 모바일이 아닌 클라이언트에서만 사용할 수 있습니다. NEAR 계정 인증을 사용해야 할 때마다 수행하는 대신, 이 계정을 기존 Web2 계정에 "연결"하고 서버 데이터베이스에 Classic-NEAR 계정 연결을 저장하는 방식으로 한 번만 수행할 수 있습니다. 이러한 방식으로 우리는 모든 문제를 해결할 수 있습니다. 서버는 인증을 수행하려고 할 때마다 NEAR 계정을 인증할 필요가 없으며, 대신 자체 데이터베이스에서 연결된 NEAR 계정을 읽기만 하면 됩니다.

이러한 하이브리드 접근 방식에서는, 블록체인과 서버에 서로 다른 인증 방법이 사용됩니다.

image

NEAR 계정 연결 시퀀스는 이미 설명한 NEAR 인증 방법과 매우 유사한 방식으로 구현할 수 있습니다. 마지막에 인증된 계정을 데이터베이스에 저장합니다.

image

여기에서 한 가지 더 개선할 수 있습니다. 웹 클라이언트는 두 계정을 모두 사용하기 때문에, 사용자는 Web 2 로그인 방법(예: 로그인/비밀번호)과 NEAR 지갑을 모두 사용하여 로그인해야 합니다. 이는 UX 관점에서 이상적이지 않으므로, 사용자가 이미 지갑을 연결한 경우 "지갑으로 로그인" 방법을 서버에 도입하여 단순화할 수 있습니다. 이는 계정 연결과 유사한 방식으로 수행될 수 있습니다.

image

이제 논의한 대로 클라이언트에 대한 전체 로그인 흐름을 요약해 보겠습니다.

image

물론 이것은 하나의 방식일 뿐이며 설명된 빌딩 블록에서 다른 솔루션과도 조합할 수 있습니다. 올바른 인증 흐름을 선택하기 위한 가장 중요한 고려 사항은 다음과 같습니다.

  • 클라이언트 유형 - 웹/데스크톱 클라이언트 또는 사이드로드된 Android 클라이언트의 경우, 지갑을 단일 인증 방법으로 사용할 수 있습니다. 스토어에서 설치한 모바일 클라이언트의 경우 여러 인증 방법을 사용하는 하이브리드 접근 방식을 사용해야 합니다.
  • 대상 고객 - 블록체인 기술에 익숙하지 않은 일반 사용자를 대상으로 하는 경우, 하이브리드 인증 방법을 사용하여 온보딩을 간소화하는 것이 사용자가 어플리케이션을 사용하기 전에 블록체인을 배우도록 강요하는 것보다 나을 수 있습니다.

블록체인 인증

지금까지 Web2 서버 측의 인증 및 권한 부여에 대해 논의했습니다. 그러나 Web3 스마트 컨트랙트는 어떻습니까? 이 경우 모든 것이 훨씬 더 간단합니다.

모든 것이 블록체인의 공개 데이터이므로, 읽기 호출에 대한 인증은 필요하지 않습니다. 트랜잭션의 경우 각 계정의 개인 키로 서명되며 인증은 네트워크에서 수행됩니다. More details on transaction signing can be found in the docs.

반면 권한 부여는 스마트 컨트랙트 자체에서 수행되어야 합니다. 가장 간단한 방법은 호출자가 작업을 수행할 수 있는지 확인하는 것입니다.

assert_eq!(
env::predecessor_account_id(),
self.tokens.owner_id,
"Unauthorized"
);

NFT 사용

사용자를 인증하는 방법과 NFT 사용 권한을 부여하는 방법을 배웠으니, 이제 어플리케이션에서 NFT를 실제로 사용할 수 있는 방법을 알아보겠습니다.

기본적으로 애플리케이션에는 서버와 스마트 컨트랙트라는 두 개의 백엔드가 있으므로, 둘 다 다른 목적으로 NFT를 사용할 수 있습니다.

  • 서버는 일반적으로 실제 기능적 목적을 위해 NFT를 사용합니다. 예를 들어 NFT를 게임 내 캐릭터로 취급하면, NFT의 속성과 통계를 읽고 일부 로직을 통해 적용할 수 있습니다.
  • 스마트 컨트랙트는 NFT 소유권은 물론 NFT 생성, 수정 및 소각(파기)을 담당합니다.

이것이 NFT 데이터 스토리지 모델이 등장하는 지점입니다. 3가지 가능한 옵션이 있음을 기억해 봅시다.

  1. 스마트 컨트랙트(온체인)에 데이터를 저장합니다
  2. IPFS(오프체인)와 같은 오프체인 분산 저장소에 데이터를 저장합니다.
  3. 애플리케이션 자체(인앱)에 데이터를 저장합니다.

처음 2가지 접근 방식은 탈중앙화된 방식이지만, 특히 속성을 수정해야 하는 경우 NFT를 사용하기 어렵게 만듭니다. 사용된 스토리지 모델에 따라 사용 옵션을 고려해 보겠습니다.

  1. 온체인 스토리지:
    • 서버는 API 호출을 통해 블록체인에서 데이터를 읽을 수 있습니다. 서버는 데이터를 직접 수정할 수 없으며 대신 스마트 컨트랙트 호출을 수행해야 합니다(트랜잭션 발행을 통해).
    • 스마트 컨트랙트는 NFT 데이터를 직접 읽고 수정할 수 있습니다.
    • 클라이언트는 블록체인에서 직접 모든 데이터를 읽을 수 있습니다.
  2. 오프체인 스토리지:
    • 서버는 API 호출을 통해 스토리지에서 데이터를 읽을 수 있습니다. 오프 체인 스토리지의 데이터는 일반적으로 변경할 수 없으므로 수정이 불가능합니다.
    • 스마트 컨트랙트는 데이터를 직접 읽을 수 없으므로 오라클을 사용해야 합니다. 데이터는 수정할 수 없습니다.
    • 클라이언트는 블록체인과 오프체인 스토리지 모두에서 데이터를 읽어야 합니다.
  3. 인앱 스토리지:
    • 서버는 자체 데이터베이스에서 데이터를 읽고 수정할 수 있습니다.
    • 스마트 컨트랙트는 데이터를 직접 읽을 수 없으므로 오라클을 사용해야 합니다. 데이터는 수정할 수 없습니다.
    • 클라이언트는 블록체인과 서버 모두에서 데이터를 읽어야 합니다.

특정 사용 사례에 따라, 세 개 모두 또는 이들의 조합을 사용할 수 있습니다. 가장 간단한 경우는 동적 NFT 데이터가 없고 도메인별로 데이터를 쉽게 나눌 수 있는 경우입니다.

  • 스마트 컨트랙트에서 사용하는 데이터는 온체인에 저장됩니다.
  • 다른 데이터는 오프체인 또는 인앱에 저장됩니다.
image

이 접근 방식에서 서버는 스마트 컨트랙트 및 선택적으로 오프체인 저장소(예: IPFS 또는 데이터베이스)에서 데이터를 읽어야 합니다.

이것은 간단한 사용 사례에는 잘 작동하지만, NFT와 관련된 동적 데이터가 필요한 경우 모든 것이 더 복잡해집니다. 예를 들어 게임 캐릭터와 관련된 경험치를 원할 수 있습니다. 이러한 데이터는 온체인 또는 인앱에 저장할 수 있습니다(오프체인 스토리지도 가능하지만 더 복잡하므로 여기에서 논의하지 않겠습니다).

인앱 스토리지의 경우, 문제 없이 서버에서 데이터를 수정할 수 있지만 다음과 같은 몇 가지 단점이 있습니다.

  • 이 데이터를 읽으려면 클라이언트가 서버에 API 호출을 해야 합니다. 이것은 NFT에 대한 중앙 집중식 지점이 추가되는 것이고, 모든 어플리케이션에 적합하지 않을 수 있습니다.
  • 스마트 컨트랙트에 이 데이터가 필요한 경우, 서버는 블록체인 오라클 역할을 해야 하므로 상황이 복잡해집니다.

서버가 스마트 컨트랙트의 오라클 역할을 하게 하려면, 가장 쉬운 방법은 서버의 데이터를 암호로 서명하고 컨트랙트 측에서 확인하는 것입니다(이 경우 서명에 사용된 서버의 공개 키는 컨트랙트에 저장되어야 함).

replay attack을 방지하기 위해, 서명된 데이터에는 타임스탬프가 포함되어야 하며 이 또한 확인되어야 합니다. However, there’s one trick to this - smart contracts can’t access current time, since it would make them non-deterministic. 이 경우, 트랜잭션 서명 시간을 사용하면 됩니다. 이는 env::block_timestamp() 함수를 사용하여 액세스할 수 있습니다.

image

이러한 모든 복잡성을 피하기 위해, 동적 데이터를 온체인에 저장하고 스마트 컨트랙트 호출을 사용하여 업데이트할 수 있습니다.

image

이러한 접근 방식에는 한 가지 단점이 있습니다. 스마트 컨트랙트의 메서드를 호출하려면, 서버에서 트랜잭션을 생성해야 하고 트랜잭션을 생성하려면 계정의 키를 사용하여 서명해야 합니다. 그렇기 때문에 서버에서 사용할 별도의 NEAR 계정을 만들어야 합니다. 스마트 컨트랙트에 대한 작업은 이 계정에만 권한을 부여하도록 할 수 있으므로, 일반 사용자는 이러한 데이터를 수정할 수 없습니다.

또 다른 옵션은 서버 측에 데이터를 저장하는 것이지만, 스마트 컨트랙트는 이 데이터에 의존하는 호출에 대해 서버 계정에만 권한을 부여할 수 있습니다. 이전 시나리오와 마찬가지로, 서버에는 자체 NEAR 계정이 있어야 합니다.

image

일반적으로 스마트 컨트랙트에 동적 데이터를 저장하는 접근 방식이 훨씬 쉽지만, 중요한 제약 사항을 고려해야 합니다.

지금까지 애플리케이션에서 NFT를 저장하고 상호 작용하는 방법을 다루었으며, 사용 사례 및 제약 조건에 따라 정확한 전략을 선택해야 합니다. 기억해야 할 몇 가지 사항은 다음과 같습니다:

  • 애플리케이션의 데이터베이스와 같은 중앙 집중식 스토리지에 NFT 데이터를 저장하는 것은 Web 3 철학에 어긋나므로 신중하고 신중하게 사용해야 합니다.
  • 블록체인의 스토리지는 저렴하지 않으므로, 분산형 오프체인 스토리지를 사용하여 대용량 데이터를 저장할 수 있습니다.
  • 동적 NFT 데이터를 저장하고 사용하는 것은 매우 까다롭기 때문에 신중하게 설계해야 합니다. 이러한 동적 데이터가 스마트 컨트랙트에 필요한 경우, 가능하면 컨트랙트 내부에 저장하는 것이 좋습니다.

NFT 발행

지금까지 애플리케이션에서 NFT를 사용하는 방법에 대해서만 논의했지만, NFT는 어떻게 생성되나요?

블록체인 세계에서 새로운 NFT를 생성하는 것을 일반적으로 민팅이라고 합니다. 기존의 디지털 자산과 마찬가지로, 이를 생성하는 방법은 다음과 같습니다.

  • 사용자가 직접 민팅할 수 있습니다. 처음부터 NFT를 민팅하도록 허용하거나, 브리딩 또는 업그레이드와 같은 보다 복잡한 프로세스를 사용하여 수행될 수 있는 작업입니다. The most famous example of such process is breeding in CryptoKitties game - new NFTs are created by combining existing ones. 이 접근 방식을 사용하면 일반적으로 사용자는 NFT 생성의 스토리지 및 가스 비용을 충당하기 위해 비용을 지불해야 합니다.
  • NFT는 개발자에 의해 일련의 사용자에게 배포될 수 있습니다. 이를 일반적으로 NFT 에어드랍이라고 합니다. 대부분의 경우 이것은 애플리케이션에서 NFT 사용을 시작하기 위한 마케팅 전략으로 사용됩니다. 이 경우 스토리지 및 가스 비용은 개발자가 부담합니다.
  • NFT를 시장에서 구입하거나 전리품 상자에서 얻을 수 있습니다. 정확한 전략에 따라 비용은 사용자 또는 개발자가 지불할 수 있습니다. 또한 이 경우 NFT는 때때로 주문 형식으로 발행될 수 있습니다.

NFT 민팅에 사용되는 정확한 전략은 애플리케이션 사용 사례에 따라 다릅니다. 그러나 스마트 컨트랙트에 정의되어 있는 nft_mint _function이 존재할 것이고, 여기에서 거의 항상 새로운 토큰 생성을 처리할 것입니다. 이 함수 자체는 표준에 정의되어 있지 않으며, 구현하는 애플리케이션에 달려 있지만 표준 라이브러리는 이를 위한 핵심 구현 사항인 mint_internal을 제공합니다. 이 함수 위에 추가 로직(예: 권한 부여)을 추가할 수 있습니다.

#[payable]
pub fn nft_mint(
&mut self,
token_id: TokenId,
receiver_id: AccountId,
token_metadata: TokenMetadata,
) -> Token {
assert_eq!(
env::predecessor_account_id(),
self.tokens.owner_id,
"Unauthorized"
);

let token = self
.tokens
.internal_mint(token_id, receiver_id, Some(token_metadata));

return token;
}

이 접근 방식은 매우 간단하지만, 선불 비용을 지불하지 않기 위해 주문형 발행 기능을 제공하려는 경우 모든 것이 약간 복잡해집니다. 예를 들어 미리 정의된 아이템 세트가 일정 확률로 나타나는 전리품 상자를 만들고 싶을 수 있습니다.

한 가지 접근 방식은 서버 측에서 이 로직을 처리하는 것입니다. 이 경우 서버는 계산된 매개변수를 통해 nft_mint 함수를 호출합니다. 그러나 이 경우 개발자는 민팅 비용을 지불해야 합니다. 이를 피하려면 전리품 상자 로직을 스마트 컨트랙트 자체로 옮길 수 있습니다. 사용자가 전리품 상자를 열려면 스마트 컨트랙트 함수를 호출하고, 이 작업에 대한 비용을 지불할 수 있습니다(예: NEAR 또는 대체 가능 토큰 사용). 개발자는 가능한 항목 및 확률과 같은 전리품 상자 구성 비용만 지불하면 됩니다.

블록체인 온보딩

온보딩 전략을 설계하기 전에 대상 고객을 신중하게 분석해야 합니다. 앞에서 간략히 언급했듯이 사용자는 두 가지 범주로 나눌 수 있습니다.

  1. 이미 블록체인에 익숙하고 자신의 지갑을 가지고 있으며 암호화폐 기본 사항을 이해하는 사용자.
  2. 블록체인에 익숙하지 않고 잘 모르는 "일반" 사용자.

첫 번째 범주만 타겟으로 지정하면 모든 것이 매우 간단합니다. 사용자는 이미 기본 개념에 익숙하며 자신의 지갑을 연결하거나 새 지갑을 만드는 데 아무런 문제가 없습니다. 그러나 두 번째 범주의 사용자도 타겟으로 삼으려면, 블록체인 세계에 최대한 원활하게 온보딩할 수 있는 전략을 개발해야 합니다. 많은 것이 적절한 UX에 의존하고 애플리케이션에 따라 다르지만, 이 프로세스를 단순화하기 위한 몇 가지 아키텍처 패턴과 기술이 존재합니다: 수탁 지갑, NEAR 드롭, 선불 가스 및 암시적 계정과 같은 것들이 그것입니다.

수탁 지갑은 제3자가 관리하는 지갑입니다. 우리의 경우 서버 측에서 지갑을 생성하고 저장할 수 있으며, 모든 블록체인 작업은 서버를 프록시로 사용하여 수행됩니다.

image

이러한 방식으로 사용자는 이 계정의 소유권을 주장하기에 충분히 편안해질 때까지 블록체인의 복잡성에 대해 인식하지 않아도 됩니다. 준비가 되면 서버는 계정 소유권을 이전할 수 있습니다. 그러나 사용자를 위한 UX 단순화에도 불구하고, 이러한 접근 방식에는 몇 가지 중요한 단점이 있습니다.

  • 사용자는 자신의 계정을 관리하기 위해 우리의 애플리케이션을 신뢰해야 합니다.
  • 계정 생성은 무료가 아니므로, 개발자가 비용을 지불하지 않는 한 이 비용을 충당하기 위해 사용자로부터 자금을 받아야 합니다. 이를 위해 PayPal 또는 Apple/Google Pay와 같은 기존 결제 수단을 사용할 수 있습니다. 그러나 이러한 접근 방식은 모바일 어플리케이션의 경우 앱 스토어 정책을 주의하여 사용해야 합니다. 또는 NEAR 암시적 계정을 사용하여 계정 생성 비용을 지불하지 않아도 됩니다.
  • 수탁 지갑을 지원되는 유일한 지갑 유형으로 두지 않으려면, 어플리케이션에서 두 가지 유형의 지갑(수탁형 및 비수탁형)을 모두 지원해야 합니다. 이렇게 하면 2가지 트랜잭션 유형을 지원해야 하므로 구현 복잡성이 증가합니다.
    • 수탁 지갑의 경우 서버 서명 트랜잭션.
    • 비수탁 지갑의 경우 클라이언트 서명 트랜잭션.

As we mentioned above, Implicit Accounts can be used to avoid paying account creation costs. NEAR 계정을 무료로 만들 수 있기 때문에, 수탁 지갑에 특히 유용합니다. 기본적으로 공개 키를 계정 ID로 사용하여 Ethereum/Bitcoin 내 계정처럼 작동하며, 나중에 완전한 NEAR 계정으로 전환할 수 있습니다. 그러나 단점도 있습니다. 우선 사람이 읽을 수 있는 계정 이름은 사용할 수 없습니다. 또한 함수 호출 키를 지원할 수 있는 적절한 NEAR 계정으로 전환하려면 계정 생성 수수료를 여전히 지불해야 합니다.

수탁 계정은 매우 강력하지만, 구현하기가 매우 복잡하고 까다롭습니다. 사용자 온보딩을 용이하게 하는 다른 접근 방식은 지갑 자체 생성을 단순화하는 것입니다. NEAR에서는 NEAR Drops를 사용하여 이를 수행할 수 있습니다. 빠른 지갑 생성 프로세스를 통해 사용자를 안내하는 링크를 생성할 수 있습니다. 그러나 수탁 계정과 동일한 문제가 적용됩니다. 계정 생성은 무료가 아니라는 점입니다. 그렇기 때문에 이러한 링크에는 NEAR 토큰이 부착되어 계정 생성 비용을 충당하고 새로 생성된 지갑의 초기 잔액 역할을 합니다. 수탁 계정과 마찬가지로 기존 결제 채널을 사용하여 이 비용을 충당하기 위해 사용자로부터 자금을 이체해야 합니다.

Another option to simplify onboarding is usage of the Prepaid Gas concept. 예를 들어 사용자가 계정을 생성하지 않고도 블록체인과 상호 작용할 수 있도록 하는 함수 호출 키를 발행할 수 있습니다. 이 경우 자금은 개발자 계정에서 인출됩니다. 이는 데모 목적으로 사용하거나 NEAR 계정이 없는 사용자가 일부 스마트 컨트랙트 작업을 수행할 수 있도록 허용할 수 있습니다.

NFT 마켓플레이스

지금까지 NFT를 Web2 어플리케이션에 통합하는 방법을 자세히 다루었지만 경제적인 부분은 다루지 않았습니다. 이러한 기능을 유지하기 위한 필수적인 부분은, 사용자가 NFT를 자유롭게 거래하고 교환할 수 있는 마켓플레이스입니다. 이러한 시장은 일반적으로 스마트 컨트랙트와 클라이언트 어플리케이션으로 구성됩니다. 이 스마트 컨트랙트는 교차 컨트랙트 호출을 사용하여 NFT의 스마트 컨트랙트와 밀접하게 통합됩니다. 별도의 스마트 컨트랙트가 있는 이유는 두 가지입니다.

  • 이를 통해 시스템을 분리할 수 있습니다. NFT 컨트랙트와 독립적으로 마켓플레이스를 수정하고 업그레이드할 수 있습니다.
  • 여러 마켓플레이스를 사용할 수 있습니다. 예를 들어 내부 마켓플레이스를 가질 수 있고, 여기에 추가로 사용자는 외부 마켓플레이스에 자신의 NFT를 나열할 수 있습니다. 이는 모든 마켓플레이스가 신뢰할 수 있는 공통 NFT 표준이 존재하기 때문에 가능합니다.

간단한 마켓플레이스 통합의 일반적인 흐름은 다음과 같습니다.

image

  1. 클라이언트는 NFT 스마트 컨트랙트에서 nft_approve 메서드를 호출합니다. 이렇게 하면 이 NFT를 판매하기 위한 마켓플레이스 스마트 컨트랙트가 승인됩니다.
  2. 계정을 승인한 후 NFT 스마트 컨트랙트는 판매 객체 생성하기 위해 마켓플레이스에 대한 교차 컨트랙트 호출을 발행합니다. 이 호출에 대한 인수는 nft_approve 호출의 일부로 제공됩니다.
  3. 다른 사용자는 판매 중인 NFT를 구매하기를 원하므로 구매를 제안하는 마켓플레이스 컨트랙트에 대한 호출을 만듭니다. 이러한 작업에 대한 정확한 호출 서명은 표준화되지 않았으며, 마켓플레이스 내 구현 방식에 따라 다릅니다.
  4. NFT 구매 제안이 유효한 경우, 마켓플레이스는 nft_transfer_payout 호출을 발행하여 NFT를 전송하고 지급 정보를 반환합니다. 이 정보는 마켓플레이스에서 수령인 간 판매 수익을 분배하는 데 사용됩니다. 가장 간단한 경우 모든 이익은 판매자에게 돌아갑니다.

이러한 흐름은 비교적 단순해 보이지만 몇 가지 중요한 세부 정보가 빠져 있습니다.

우선, 판매를 생성하려면 스토리지 비용을 지불해야 합니다. 일반적으로 판매자가 비용을 지불해야 하지만, 다른 모델도 가능합니다. 예를 들어 마켓플레이스나 애플리케이션 개발자가 비용을 부담할 수 있습니다. 사용자가 판매 비용을 지불하도록 하려면 스토리지 예약 접근 방식을 사용할 수 있습니다.

  • NFT 판매를 승인하기 전에 사용자는 판매 스토리지 요구 사항을 충족하기 위해 Marketplace 컨트랙트에 스토리지를 예약해야 합니다.
  • NFT를 구매하거나 리스팅을 철회한 후, 사용자는 스토리지 예약을 철회할 수 있습니다(NEAR 스토리지 스테이킹 모델이 사용되므로 데이터가 삭제되고 잠긴 토큰이 환불될 수 있음을 기억하세요).

이 모델은 비교적 간단하지만 UX 관점에서는 이상적이지 않습니다. 사용자가 NFT를 판매하려면 스토리지를 예약하기 위해 별도의 조치를 취해야 합니다. 이를 개선하기 위해 nft_approve 호출과 스토리지 예약을 결합하고, NFT의 리스팅이 철회된 후 스토리지 비용을 자동으로 환불할 수 있습니다.

image

또 다른 누락 사항은 클라이언트가 가능한 매물들에 대한 데이터를 읽을 수 있는 방법입니다. 물론 판매 정보는 스마트 컨트랙트에서 직접 읽을 수 있지만, 여기에서의 데이터 구조는 검색이나 필터링에 최적화되어 있지 않습니다. 또한 클라이언트 측에서 NFT 및 마켓플레이스 컨트랙트의 데이터를 결합해야 하는데 이는 비효율적입니다. 이러한 문제를 해결하기 위해 인덱서를 사용하여 데이터를 적절한 데이터베이스로 집계할 수 있습니다. 여기서 데이터는 검색에 최적인 방식으로 저장될 수 있습니다(예: 관계형 데이터베이스 또는 ElasticSearch 인덱스를 사용할 수 있음).

image

이것은 마켓플레이스가 어떻게 설계될 수 있는지에 대한 한 가지 예일 뿐이지만, 이를 통해 모든 기본 개념과 문제를 다루었습니다. 기억해야 할 가장 중요한 사항은 다음과 같습니다:

  • 마켓플레이스를 별도의 컨트랙트로 구현하는 것이 좋습니다.
  • 스토리지 관리는 UX를 염두에 두고 신중하게 설계해야 합니다.
  • 적절한 검색/필터링 기능을 구현하기 위해서는 별도의 인덱싱 서비스가 필요합니다.

간단한 마켓플레이스의 예는 여기에서 찾을 수 있습니다. 보다 복잡한 마켓플레이스에서는 결제 수단으로 대체 가능 토큰을 사용한 구매를 허용할 수 있습니다.

구성 요소 구현

이제 아키텍처를 구현하는 데 사용할 수 있는 라이브러리, 프레임워크 및 타사 솔루션을 선택해 보겠습니다.

클라이언트 & 서버

우선, 고객으로부터 블록체인까지 어떻게 상호 작용할 수 있을까요?

읽기 수준 액세스만 필요한 경우 REST API를 사용하면 문제 없이 모든 언어 및 기술에 통합될 수 있습니다. 그러나 클라이언트에서 트랜잭션을 게시해야 하는 경우 모든 것이 더 복잡해집니다. 트랜잭션은 지갑에 저장된 개인 키로 서명되어야 합니다.

  • 함수 호출 키의 경우 지갑에서 획득하여 클라이언트에서 직접 사용할 수 있습니다.
  • 전체 액세스 키의 경우 사용자는 트랜잭션을 승인하기 위해 지갑으로 리디렉션되어야 합니다.

이러한 모든 시나리오를 처리하기 위해 JavaScript API가 존재 합니다. 여기에 Web/Node.JS 어플리케이션을 블록체인과 통합하는 데 필요한 모든 기능이 들어가 있습니다. 이 SDK는 웹 기반 클라이언트를 위한 완벽한 선택이지만, 데스크톱 또는 모바일 기반 클라이언트에는 적합하지 않습니다. 이 경우 다른 라이브러리를 사용할 수 있습니다.

동일한 SDK 및 라이브러리를 서버에 사용할 수 있습니다. 유일한 차이점은 서버가 지갑과 상호 작용할 수 없기 때문에 안전한 방식으로 저장하고 액세스해야 하는 전체 액세스 키에 대한 액세스 권한이 있어야 한다는 것입니다.

또한 서버가 NEAR SDK를 사용할 수 없는 기술을 사용하는 경우 다른 솔루션을 사용할 수 있습니다. 예를 들어, 모든 블록체인 상호 작용을 처리하는 Node.js를 사용하여 별도의 (마이크로)서비스를 만들 수 있습니다.

image

이러한 프록시 서버의 예는 여기에서 찾을 수 있습니다 .

컨트랙트

이전 섹션에서처럼, 애플리케이션에는 NFT와 마켓플레이스의 두 가지 스마트 컨트랙트가 필요합니다. 이를 얻는 방법에는 사내 구현 또는 타사/SAAS 솔루션을 사용하는 두 가지 옵션이 있습니다. 두 옵션 모두 실행 가능하며 장단점이 다릅니다.

우리가 우리만의 컨트랙트를 만들고 싶다면, 우리가 완전히 통제하고 우리가 원하는 모든 것을 구현할 수 있습니다. 물론 명백한 단점은 그것을 구축하는 데 시간과 비용이 든다는 것입니다. 반면 타사 솔루션은 기능이 제한되어 쉽게 확장할 수 없는 경우가 많습니다. 또한 일반적으로 약간의 선불 비용 및/또는 사용료가 있습니다.

사내 NFT 컨트랙트 구현의 경우 몇 가지 리소스를 시작점으로 사용할 수 있습니다. 우선, 대부분의 표준을 구현 하는 Rust 라이브러리를 사용할 수 있습니다. 또 다른 옵션은 전체 컨트랙트를 처음부터 작성하는 것입니다. 이를 수행하는 방법에 대한 좋은 가이드는 이 링크에서 확인할 수 있습니다 .

표준 구현이 없기 때문에 자체 마켓플레이스 컨트랙트를 구현하는 것은 더 복잡합니다. 몇 가지 예시는 다음과 같습니다:

As for third-party solutions, the most complete one is Mintbase, which provides a full suite of components for NFTs integration - including contracts, indexer, API and a web client:

image

또 다른 옵션은 자체 NFT 컨트랙트를 출시하고, Paras(통합 문서)와 같은 타사 마켓플레이스 중 하나와 통합하는 것입니다.

image

외부 마켓플레이스의 주요 이점은, 이러한 마켓플레이스들이 일반적으로 자체 인덱서를 실행하고 API를 통해 수집된 데이터를 노출하므로 이러한 구성 요소를 구현할 필요가 없다는 사실입니다. 그러나 일반적으로 제공에 대한 대가가 있으므로 사용하기 전에 비용 편익 분석을 수행해야 합니다.

오프체인 스토리지

이전에 우리는 블록체인의 스토리지가 저렴하지 않기 때문에 대부분의 경우 일부 분산형 스토리지 솔루션을 사용해야 한다고 논의했습니다. 몇 가지 옵션을 사용할 수 있습니다.

  • IPFS - 블록체인 세계에서 널리 사용되는 최초의 분산 스토리지 솔루션 중 하나입니다. 그러나 데이터가 네트워크에 보존되도록 하려면 IPFS 노드를 유지해야 합니다.
  • Arweawe - 블록체인 기반 분산 스토리지입니다.
  • Filecoin - 또 다른 블록체인 기반 스토리지입니다.
  • nft.storage - IPFS 및 Filecoin 위에 구축된 무료 서비스입니다.

이러한 솔루션에 대한 보다 심층적인 개요는 다음 문서에서 확인할 수 있습니다. 일반적으로 "비장의 무기"는 없으므로 다양한 솔루션을 평가하고 가장 적합한 솔루션을 선택해야 합니다. 솔루션을 선택하는 동안 주요 관심사는 가용성 보장 및 비용입니다.

인덱서

이미 결정한 바와 같이 마켓플레이스 기능을 지원하려면 인덱싱 서비스가 필요합니다. 일반적으로 3가지 구성 요소로 구성됩니다.

  • 인덱서 - NEAR 네트워크에서 트랜잭션을 처리하고 추출된 데이터를 데이터베이스에 넣습니다.
  • 데이터베이스 - 추출된 데이터를 저장하기 위해 선택한 데이터베이스입니다.
  • 인덱서 API - 데이터베이스 위에 있는 API 계층입니다.
image

While any technology of choice can be used to implement Database and API, an indexer itself is can be implemented using both Rust and JavaScript. See this example written in Rust.

일반적으로 인덱서는 기본적으로 컨트랙트 실행 중에 작성된, 구조화된 로그 메시지인 이벤트에서 데이터를 추출하여 작동합니다.

The Graph는 처음부터 인덱서를 구축하지 않고 사용할 수 있는 대안입니다. 이는 생성 및 배포를 간소화하는 서비스형 인덱서 솔루션입니다. NEAR 인덱서를 만드는 방법에 대한 안내는 이 링크에서 확인할 수 있습니다.

테스트 자동화

코드의 테스트 자동화는 최신 소프트웨어 개발의 기둥 중 하나입니다. 그러나 dApp을 어떻게 테스트할까요?

스마트 컨트랙트는 순수 함수이며, 단위 테스트를 사용하여 쉽게 테스트할 수 있습니다. Guide on how to write them is available here, and some examples can be found here. Another important kind of tests that is supported by NEAR are E2E tests, they can be executed either deploying contract code to either the local network environment (more info here), or directly to testnet, more info here).

두 가지 유형의 테스트를 모두 해보는 것은 스마트 컨트랙트의 지속적인 품질을 보장하기 위해 똑같이 중요합니다. 특히 컨트랙트 업그레이드는 일반적으로 수행하기 쉽지 않기 때문입니다(DAO에서 업그레이드 자체는 커뮤니티 투표에 의해 관리될 수 있음을 기억하세요).

비기능적 문제

마지막으로 아키텍처에 대한 중요한 비기능적 문제를 다루겠습니다.

보안

전체 개발 과정에서 기억해야 할 가장 중요한 것은 보안, 특히 스마트 컨트랙트의 보안입니다. 그들의 코드는 공개되어 있고 업그레이드 절차가 간단하지 않기 때문에 보안 문제 및 논리적 악용에 대해 주의 깊게 감사해야 합니다.

보안을 유지해야 하는 또 다른 중요한 사항은 사용자의 개인 키입니다. 대부분의 경우 함수 호출 키만 클라이언트에서 직접 액세스해야 하며, 전체 액세스 키는 지갑에 보관해야 합니다. 그러나 경우에 따라 전체 액세스 키를 직접 사용해야 할 수도 있습니다(예: 서버 트랜잭션 서명 시나리오의 경우). 이러한 경우 보안이 침해되면 완전한 계정 탈취로 이어질 수 있으므로 안전한 위치에 보관하고 가장 민감한 비밀로 취급해야 합니다.

일반적으로 NEAR 메인넷에 어플리케이션을 배포하기 전에 전체 보안 감사를 수행하는 것이 좋습니다.

확장성 및 가용성

또 다른 관심사는 솔루션의 확장성과 가용성입니다. 기존 서버를 확장하는 방법은 많지만, 블록체인을 확장하고 항상 사용할 수 있도록 하려면 어떻게 해야 할까요?

블록체인은 분산되어 있기 때문에 설계상 높은 가용성을 제공하며, NEAR는 Proof-of-Stake 합의 및 샤딩을 사용하여 뛰어난 확장성을 제공합니다. 그러나 네트워크와 상호 작용하려면 RPC 노드가 필요합니다. NEAR는 네트워크에 대해 공개적으로 사용 가능한 노드(여기에 나열 됨)를 제공하지만, 이에 대한 성능 또는 가용성을 보장하지 않습니다. 따라서 아키텍처가 확장 가능하고 내결함성이 있는지 확인하려면 일반적으로 로드 밸런서 뒤에 자체 RPC 노드 클러스터를 유지 관리해야 합니다.

image

RPC 노드를 설정하는 방법에 대한 정보는 여기에서 볼 수 있습니다.

또한 전체 시스템의 가용성과 확장성을 보장하기 위해 사용된 모든 타사 서비스도 검토해야 합니다. 예를 들어 IPFS가 NFT의 스토리지로 사용되는 경우 피닝 노드와 IPFS 게이트웨이는 확장 가능하고 내결함성이 있어야 합니다.

비용

Web3 어플리케이션을 구축할 때 비용 계산이 Web2 애플리케이션과 다소 다르다는 점을 기억하는 것이 중요합니다. 추가 비용은 여러 범주로 나눌 수 있습니다.

  1. 스마트 컨트랙트 배포 비용. NEAR 테스트넷 또는 로컬 환경에 배포하는 동안 기본적으로 무료입니다. 그러나 메인넷에 배포할 때 개발자에게 스토리지 및 가스 비용이 청구됩니다. 컨트랙트 배포 트랜잭션의 가스 비용은 상대적으로 작습니다(작성 ​​당시 약 0.04$). 반면에 스토리지 비용은 상당할 수 있습니다. 예를 들어 150KB 컨트랙트(컴파일)의 비용은 약 20$입니다.
  2. 스마트 컨트랙트 사용 비용. Web3에서 사용자는 스마트 컨트랙트 호출에 대해 비용을 지불하므로 사용자가 높은 비용으로 인해 컨트랙트와 상호 작용하는 데 낙담하지 않도록 하려면 가능한 가장 낮은 비용이 발생하도록 최적화해야 합니다. 이것은 가스가 상대적으로 저렴하기 때문에 스토리지 비용에 특히 중요합니다.
  3. 더 나은 가용성을 위해 비공개로 호스팅되는 RPC 노드를 사용하려면 운영 비용도 고려해야 합니다. 여기에서 비용 내역을 확인할 수 있습니다. 대략적인 추정치는 매월 노드당 약 290$입니다(redundancy을 위해 최소 2개의 노드가 필요함을 기억하십시오).
  4. 비공개로 호스팅되는 인덱서의 비용(사용되는 경우). More information can be found here, a rough estimation for the costs is about 100$ per month.
  5. 타사 서비스 비용.
Was this page helpful?