Token Engineering 서현준

들어가며


쟁글에서는 블록체인 데이터를 분석하여 블록체인 관련 종사자 및 블록체인에 관심이 있는 사람들에게 의미 있는 데이터를 제공하기 위해 블록체인의 다양한 데이터를 분석하고 있습니다.

이번 글에서는 NFT 마켓 플레이스 중 세계 최대 거래소인 OpenSea의 거래 데이터를 분석하며, 각 메인넷별 NFT 거래 데이터 지표를 만들었던 경험들 중에서 OpenSea 초기 거래 프로토콜인 Wyvern Protocol의 거래 데이터를 분석하는 방법을 소개하겠습니다.

이번 글에서는 데이터 분석을 위한 기본 지식 설명과 Wyvern 프로토콜을 통한 거래 데이터 분석에 대해 설명하고자 합니다.

들어가기에 앞서, OpenSea가 현재 지원하는 메인넷과 거래 프로토콜의 종류를 살펴볼 예정입니다.

본 글에서 사용된 OpenSea 데이터 분석에 활용된 데이터는 Ethereum 기준으로 작성되었습니다.

OpenSea 마켓 플레이스에서 지원하는 메인넷


OpenSea는 초기 Ethereum 거래를 지원했으며, 다른 메인넷도 비슷한 시기에 추가되거나 시간이 지남에 따라 하나씩 메인넷 지원이 추가되었습니다. 현재는 Arbitrum, Avalanche, BNB Chain, Ethereum, Klaytn, Optimism, Polygon, Solana, Zora 등의 메인넷에서 초기에는 Wyvern Protocol, 현재는 Seaport Protocol을 통해 거래가 이루어지고 있습니다.

OpenSea 마켓 플레이스의 거래 프로토콜


OpenSea는 2018년 6월 12일(UTC+0) OpenSea Deployer를 통해 Wyvern Protocol을 출시하였으며, 2018년 6월 13일(UTC+0) 첫 거래가 시작되었습니다. 이후, 2022년 2월 18일(UTC+0) EIP712 서명을 통한 거래 데이터 투명성 확보 및 취약점 극복을 위해 새로운 버전의 Wyvern Protocol이 업데이트되었습니다.

그 후, NFT 거래가 활발해지면서 수수료 문제가 논란이 되었고, OpenSea는 가스비 최적화 작업을 통해 새로운 거래 프로토콜을 발표하게 되었습니다. Seaport Protocol은 바이트 코드 레벨에서의 가스비 최적화 처리로 가스비 절감을 통해 최적화가 이루어졌으며, 2022년 6월 11일(UTC+0) OpenSea Deployer를 통해 새로운 거래 프로토콜로 발표되었습니다. OpenSea의 새 거래 프로토콜인 Seaport는 2022년 6월 12일(UTC+0) 첫 거래가 시작되었습니다.

이후 다양한 기능 업데이트를 통해 현재(2023년 7월 31일(UTC+0)) 기준으로 Seaport 1.5 버전까지 출시되었습니다. 현재는 Seaport Protocol을 계속 향상시키면서 Seaport Protocol을 통해 거래가 이루어지고 있습니다.

표 1. OpenSea 프로토콜(Contract)별 거래 일자

Name Address Created by Tx Hash Created Date(UTC+0) Start Trade Date(UTC+0) End Trade Date(UTC+0)
OpenSea: Wyvern Exchange (v1) 0x7be8076f4ea4a4ad08075c2508e481d6c946d12b 0xebe6bd9d1da992b9a6f816564eafef42e9bf68d3876fae22556cc63da6fc0f66 2018-06-12 2018-06-13 2022-02-25
OpenSea: Wyvern Exchange2.3 (v2) 0x7f268357a8c2552623316e2562d90e642bb538e5 0xb387cc66173783ef9faef775d4b7eaaff3fdd47e765239d5ffb7633ec0be665b 2022-02-01 2022-02-18 2022-08-01
OpenSea: seaport1.1 (v3) 0x00000000006c3852cbef3e08e8df289169ede581 0x34a28a0111a238347fe30a6c91b00437f8438357427c5e759a2f7577afe65144 2022-06-11 2022-06-12 continue
OpenSea: seaport1.2 0x00000000000006c7676171937c444f6bde3d6282 0xadc7728fd231c4d6118ca2409d4fceef5be4028ef9049b0dffc2ae9c326e9f00 2023-01-31 2023-02-09 2023-02-21
OpenSea: seaport1.3 0x0000000000000ad24e80fd803c6ac37206a45f15 0xd3d4aec88ee9feedd880eca79642b0a1ecf1a678f1e89b07c760c1a667b7206c 2023-02-16 2023-02-16 2023-02-16
OpenSea: seaport1.4 0x00000000000001ad428e4906ae43d8f9852d0dd6 0x4f5eae3d221fe4a572d722a57c2fbfd252139e7580b7959d93eb2a8b05b666f6 2023-02-18 2023-02-21 continue
OpenSea: seaport1.5 (v4) 0x00000000000000adc04c56bf30ac9d3c0aaf14dc 0xa7f75a8b23c0f3150b7116aae930101f42996cb35e3e596a646156926350933a 2023-04-26 2023-04-27 continue

사전 배경 지식


본격적으로 Wyvern Protocol의 거래 데이터 분석에 앞서, 알아야 할 기본 지식을 몇 가지 설명하고자 합니다.

Smart Contract의 Function과 Event


블록체인 내에서 Ethereum과 같은 경우, Smart Contract라는 블록체인 내의 프로그램을 통해 특정 행위가 실행되고 기록됩니다. 이러한 행위에는 NFT 거래, 서명 등이 포함됩니다. Smart Contract는 블록체인 내에서 특정 주소에 상주하는 코드(기능) 및 데이터(상태)의 모음입니다. 이러한 Smart Contract는 크게 Function과 Event로 구성됩니다.

Function은 Smart Contract가 수행할 수 있는 특정 작업 또는 작업을 정의하는 코드입니다. 이는 기존 프로그래밍 언어의 메서드와 같다고 볼 수 있습니다. 입력을 받고, 데이터를 처리하고, 출력을 생성할 수 있습니다. 이러한 Smart Contract의 function은 블록체인 내에서 트랜잭션을 수행 시 Smart Contract의 특정 Function을 호출하게 되면 실행됩니다.

Event는 Smart Contract 내에서 발생하는 특정 사건의 발생 또는 변경 사항을 전달하고 기록하는 방법입니다.

요약하면 Smart Contract의 Function은 Smart Contract의 동작과 작업을 정의하고, Event는 Smart Contract 내 특정 사건의 발생에 대해 외부 관찰자에게 알리는 데 사용됩니다.

Event


Event 데이터를 활용하기 위해서는 크게 2가지를 알고 있어야 합니다.

첫째로, EVM 계열의 Event Log의 형태를 알고 있어야 합니다. Event Log의 데이터를 통해 OpenSea의 Smart Contract를 사용하여 이루어진 거래 데이터만을 도출할 수 있습니다.

둘째로, NFT 거래를 위해 알아야 하는 기본적인 것으로 거래 통화 수단이 되는 ERC20과 거래의 대상이 되는 NFT의 종류인 ERC721, ERC1155의 기본 Event 종류를 알고 있어야 합니다.

셋째로, Wyvern 프로토콜의 주요 Event 형태를 파악해야 합니다.

Event Log

Transaction Receipt 데이터의 Logs 데이터의 형태를 보면 기본적으로 아래 표와 같은 데이터를 포함하고 있습니다. 각 데이터의 의미는 아래와 같습니다.

표 2. ethereum logs의 필드 설명

필드 설명
contract address wyvern, seaport 등의 protocol address, nft address, token address 등
topic0 Event Name의 hex signature
topic1 indexed param
topic2 indexed param
topic3 indexed param
data indexed가 아닌 param을 하나로 합친 data
index 해당 event가 발생한 tx내에서 event의 index
block hash 해당 event가 발생한 tx가 담긴 block의 hash
block number 해당 event가 발생한 tx가 담긴 block의 number
block time 해당 event가 발생한 tx가 담긴 block의 time
tx hash 해당 event가 발생한 tx의 hash
tx index 해당 event가 담긴 block내에서 tx의 index
tx from 해당 event가 담긴 block내에서 tx의 from address
tx to 해당 event가 담긴 block내에서 tx의 to address

ERC20

ERC20의 Smart Contract를 살펴보면 Transfer와 Approval Event로 구성되어 있습니다.

Transfer

특징: indexed 필드는 from, to

/**
	MUST trigger when tokens are transferred, including zero value transfers.

	A token contract which creates new tokens SHOULD trigger a Transfer event with the _from address set to 0x0 when tokens are created.
*/
event Transfer(
  address indexed from,
  address indexed to,
  uint256 value
);

Approval

특징: indexed 필드는 owner, spender

/**
	MUST trigger on any successful call to approve(address _spender, uint256 _value).
*/
event Approval(
  address indexed owner,
  address indexed spender,
  uint256 value
);

ERC721

ERC721의 Smart Contract를 살펴보면 Transfer와 Approval, ApprovalForAll Event로 구성되어 있습니다.

Transfer

특징: indexed 필드는 _from, _to, _tokenId

/// @dev This emits when ownership of any NFT changes by any mechanism.
///  This event emits when NFTs are created (`from` == 0) and destroyed
///  (`to` == 0). Exception: during contract creation, any number of NFTs
///  may be created and assigned without emitting Transfer. At the time of
///  any transfer, the approved address for that NFT (if any) is reset to none.
event Transfer(
  address indexed _from,
  address indexed _to,
  uint256 indexed _tokenId
);

Approval

특징: indexed 필드는 _owner, _approved, _tokenId

/// @dev This emits when the approved address for an NFT is changed or
///  reaffirmed. The zero address indicates there is no approved address.
///  When a Transfer event emits, this also indicates that the approved
///  address for that NFT (if any) is reset to none.
event Approval(
  address indexed _owner,
  address indexed _approved,
  uint256 indexed _tokenId
);

특징: indexed 필드는 _owner, _operator

ApprovalForAll

/// @dev This emits when an operator is enabled or disabled for an owner.
///  The operator can manage all NFTs of the owner.
event ApprovalForAll(
	address indexed _owner,
	address indexed _operator,
	bool _approved
);

ERC1155

ERC1155의 Smart Contract를 살펴보면 TransferSingle과 TransferBatch, ApprovalForAll, URI Event로 구성되어 있습니다.

TransferSingle

특징: indexed 필드는 _operator, _from, _to

/**
	@dev Either `TransferSingle` or `TransferBatch` MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see "Safe Transfer Rules" section of the standard).
	The `_operator` argument MUST be the address of an account/contract that is approved to make the transfer (SHOULD be msg.sender).
	The `_from` argument MUST be the address of the holder whose balance is decreased.
	The `_to` argument MUST be the address of the recipient whose balance is increased.
	The `_id` argument MUST be the token type being transferred.
	The `_value` argument MUST be the number of tokens the holder balance is decreased by and match what the recipient balance is increased by.
	When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address).
	When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address).        
*/
event TransferSingle(
	address indexed _operator,
	address indexed _from,
	address indexed _to,
	uint256 _id,
	uint256 _value
);

TransferBatch

특징: indexed 필드는 _operator, _from, _to

/**
	@dev Either `TransferSingle` or `TransferBatch` MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see "Safe Transfer Rules" section of the standard).      
	The `_operator` argument MUST be the address of an account/contract that is approved to make the transfer (SHOULD be msg.sender).
	The `_from` argument MUST be the address of the holder whose balance is decreased.
	The `_to` argument MUST be the address of the recipient whose balance is increased.
	The `_ids` argument MUST be the list of tokens being transferred.
	The `_values` argument MUST be the list of number of tokens (matching the list and order of tokens specified in _ids) the holder balance is decreased by and match what the recipient balance is increased by.
	When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address).
	When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address).                
*/
event TransferBatch(
	address indexed _operator,
	address indexed _from,
	address indexed _to,
	uint256[] _ids,
	uint256[] _values
);

ApprovalForAll

특징: indexed 필드는 _owner, _operator

/**
	@dev MUST emit when approval for a second party/operator address to manage all tokens for an owner address is enabled or disabled (absence of an event assumes disabled).        
*/
event ApprovalForAll(
	address indexed _owner,
	address indexed _operator,
	bool _approved
);

URI

특징: indexed 필드는 _id

/**
	@dev MUST emit when the URI is updated for a token ID.
	URIs are defined in RFC 3986.
	The URI MUST point to a JSON file that conforms to the "ERC-1155 Metadata URI JSON Schema".
*/
event URI(
	string _value,
	uint256 indexed _id
);

Wyvern Protocol

Wyvern Protocol의 Smart Contract를 살펴보면 많은 이벤트로 구성되어 있습니다. 그 중 거래 내역을 볼 수 있는 OrdersMatched에 집중하겠습니다.

OrdersMatched

  • OrdersMatched란 거래가 수행된 내역, 즉 영수증을 의미합니다. 이를 통해 거래에 대한 히스토리를 파악할 수 있습니다.
  • 특징: indexed 필드는 maker, taker, metadata
/* Log match event. */
emit OrdersMatched(
	buyHash,
	sellHash,
	sell.feeRecipient != address(0) ? sell.maker : buy.maker,
	sell.feeRecipient != address(0) ? buy.maker : sell.maker,
	price,
	metadata
);

event OrdersMatched(
	bytes32 buyHash,
	bytes32 sellHash,
	address indexed maker,
	address indexed taker,
	uint price,
	bytes32 indexed metadata
);

본격적인 Wyvern Protocol의 거래 데이터 수집, 분석, 적재 방법


본격적으로 Wyvern Protocol의 거래 데이터를 수집, 분석, 적재하는 과정을 살펴보겠습니다. NFT 거래 데이터를 수집하기 위해서는 사전에 block, transaction, log 데이터가 수집되어 있어야 합니다. 해당 데이터들과 아래와 같은 수집 과정들을 살펴보고자 한다면 Dune에서 실제 Ethereum 데이터를 통해 확인할 수 있습니다.

Wyvern Protocol의 거래 데이터 수집


Wyvern Protocol의 거래 데이터를 수집하기 앞서, Ethereum의 Log 데이터가 갖춰져야 합니다. Log 데이터를 토대로 특정 주기(본 글에서는 일자)별로 Wyvern Protocol의 거래 데이터를 수집합니다.

  1. 특정 기간 내에 Contract Address(이하 CA)가 Wyvern Protocol의 CA이면서, topic0이 OrdersMatched인(topic0은 event name의 hex값이므로) tx_hash를 group by 하여, distinct한 tx_hash를 추출합니다.
    • 기간은 시간 단위로 스케줄링 할 수도 있고, 하루 단위로 스케줄링 할 수 있습니다. Wyvern 버전에 따라 각 CA를 통해 거래된 기간 내에 조회를 해야 합니다.
    • CA는 Wyvern Protocol의 버전에 따라 거래된 기간과 매치하여 설정합니다.
    • topic0는 Wyvern Protocol에서는 OrdersMatched로 고정합니다. 단, hex signature이므로, 본 글의 하단에 Event Name Hex Signature를 참고하시길 바랍니다.

    ex) query

     SELECT tx_hash FROM ethereum.logs
     WHERE block_time >= '2022-03-01 00:00:00' AND block_time < '2022-03-01 24:00:00'
     		AND contract_address = '0x7f268357a8c2552623316e2562d90e642bb538e5'
     		AND topic1 = '0xc4109843e0b7d514e4c093114b863f8e7d8d9a458c372cd51bfe526b588006c9'
     GROUP BY tx_hash;
    
  2. 1번에서 쿼리 결과로 나온 tx_hash의 값을 반복하며 해당 tx_hash에 포함된 Logs 데이터를 가져와 데이터 분석 및 적재 단계로 넘어갑니다.

    ex) query

     SELECT * FROM ethereum.logs WHERE block_time >= '2022-03-01 00:00:00' AND block_time < '2022-03-01 24:00:00' AND tx_hash = '0x3de1b78d00e5afcffc1999ff94f0bc8934324620d02fa15bac018c78648b7850' ORDER BY index;
    

Wyvern Protocol의 거래 데이터 분석 및 적재


NFT 거래 데이터를 저장하기 위한 테이블을 모델링하고, 이 데이터를 채우기 위한 로직을 설계해야 합니다. NFT 거래 데이터를 저장하기 위한 테이블은 dune의 초기 nft_trades 테이블을 샘플로 사용하여 설명하겠습니다.

표 3. nft_trades 테이블 sample

id field type 설명
1 block_time timestamp 해당 거래의 블록 생성 시간
2 tx_hash bytea 해당 거래의 tx hash
3 block_number int4 해당 거래의 block 번호
4 evt_index int4 해당 거래의 tx 내의 evt index
5 tx_from bytea 해당 거래의 tx의 from address
6 tx_to bytea 해당 거래의 tx의 to address
7 trace_address _int4 해당 거래의 trace의 index
8 seller bytea nft item의 판매자
9 buyer bytea nft item의 구매자
10 nft_token_id text nft token의 id
11 erc_standard text ERC721, ERC1155
12 nft_contract_address bytea nft token의 CA
13 nft_project_name text nft project의 이름
14 number_of_items int4 거래된 nft item 개수
15 trade_type text Single Item Trade, Bundle Trade
16 nft_token_ids_array _text Bundle 거래인 경우 nft token의 id 리스트
17 senders_array _bytea Bundle 거래인 경우 nft token의 sender 리스트
18 recipients_array _bytea Bundle 거래인 경우 nft token의 receipient 리스트
19 erc_types_array _text Bundle 거래인 경우 nft token의 erc types 리스트
20 nft_contract_addresses_array _bytea Bundle 거래인 경우 nft token의 nft CA 리스트
21 erc_values_array _numeric Bundle 거래인 경우 nft token의 erc value 리스트
22 original_currency text nft item을 구매한 currency(ERC20)
23 original_currency_contract bytea nft item을 구매한 original currency(ERC20)의 CA
24 currency_contract bytea nft item을 구매한 currency(ERC20)의 CA
25 platform text OpenSea
26 evt_type text Trade
27 category text Buy, Sell
28 exchange_contract_address bytea OpenSea 거래 프로토콜의 CA(여기서는 Wyvern의 CA)
29 platform_version text 거래 protocol 버전
30 original_amount_raw numeric(54, 18) nft item을 구매한 currency 토큰의 양
31 original_amount numeric(54, 18) nft item을 구매한 currency 토큰을 해당 토큰의 decimals로 나눈 값
32 usd_amount numeric(54, 18) nft item의 usd 가격
33 trade_id int4 해당 거래의 trade id

기본 메커니즘


NFT 데이터 분석 및 적재는 Log 데이터에서 topic0(Event Name)을 기반으로 합니다. Wyvern에서는 Transfer, TransferSingle, OrdersMatched Event를 확인해야 합니다. Wyvern CA에 대한 Log들을 분석하면 ERC721 거래에 대한 TransferBatch Event는 사용되지 않는 것을 볼 수 있습니다. 따라서 Transfer, TransferSingle, OrdersMatched Event를 기반으로 위 테이블의 데이터가 확보되면 하나의 거래 데이터를 생성하여 테이블에 적재합니다.

외부 테이블 참조(blocks, transactions, logs)

Transfer

  • Transfer 이벤트는 ERC20, ERC721 두 개에 모두 있기 때문에 구분할 수 있어야 합니다. Topic이 4개까지 있으면 ERC721, 3개면 ERC20으로 분류합니다.
  • Topic1, Topic2, Topic3 다 비어있거나, 다 채워져 있으면 ERC721 Token으로 분류합니다.
    • ERC721 CA 같은 경우에는 공식적인 형식을 지키지 않고 event 구현 시 indexed를 빠뜨리고 구현한 케이스들이 존재합니다.
  • 그렇지 않으면 ERC20 Token으로 분류합니다. ERC20이 보편적으로는 NFT item을 구매할 때 사용한 currency로 사용 되나, 예외 케이스로 ERC20 자체가 거래 되는 경우도 있습니다.

Transfer Event를 통한 data 추출 이후 작업

  • Transfer Event를 통한 데이터 입력이 끝난 후 erc_standard 필드를 검사합니다. 만약 ERC721이 아니라면(즉, ERC20), tempData에 현재 데이터를 담아두어 아래에서 활용할 수 있도록 합니다.
if nftTrade.ErcStandard != "erc721" {
	tempData = append(tempData, data)
}

TransferSingle

OrdersMatched

  • OrersMatched Event를 만나면 tempData(Transfer Event에서 ERC721이 아니어서 저장해둔 data)가 비어있지 않다면 아래 로직을 수행합니다.
    • ERC20 Transfer 사후 처리
      • erc_standard 가 ERC721 or ERC1155 이면 tempData로 currency 관련된 정보를 추출합니다.
  • OrdersMatched
    • OrdersMatched 건마다 bulk count를 증가시킵니다.
    • 한 Tx hash 내에 여러 개의 OrdersMatched가 있을 수 있습니다.
  • 현재 TX Hash에 대한 로직이 모두 처리되었을 때 bulk count가 1보다 크면 현재 Tx hash의 NFT 거래 데이터의 trade type을 모두 “Bundle Trade”로 변경합니다.
  • wyvern에서는 bulk 거래는 없고, 모두 bundle로 처리됩니다.

현재 거래건(TX Hash)에 대한 데이터가 모두 채워지면 nft 거래 데이터를 nft_trades 테이블에 저장합니다.

전체적으로 위의 수집, 분석, 적재하는 일련의 과정을 TX Hash 기준으로 반복하여, OpenSea Wyvern Protocol을 통해 이루어진 NFT 거래 데이터를 수집할 수 있습니다.

마치며


OpenSea의 Wyvern Protocol을 통한 거래 데이터 분석을 통해 OpenSea의 거래량, Top NFT, Top Trader 등의 지표들을 부가적으로 산출할 수 있었고, 이를 통해 쟁글의 애널리틱스에 다양한 지표들에 활용할 수 있었다.

쟁글의 백엔드 개발팀은 높은 블록체인 이해도를 기반으로 블록체인 데이터에 대한 다양한 리서치를 통해 이를 수집, 분석, 가공, 적재하여 다양한 서비스에 활용하고 있습니다.

쟁글의 백엔드 개발팀은 블록체인 도메인에서 블록체인 데이터의 분석 및 처리를 수행할 수 있는 경험을 가지고 있으며, 일반적인 백엔드 개발 기술도 숙련되어 있습니다. 이러한 경험 덕분에 쟁글의 백엔드 개발팀은 지속적으로 높은 수준의 목표를 달성하고 있습니다.

참고


Trade Type

Event Name Hex Signature

분류 Event Name Hex Signature
ERC20,ERC1155 Approval(address,address,uint256) 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925
ERC20,ERC721 Transfer(address,address,uint256) 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
ERC1155 TransferSingle(address,address,address,uint256,uint256) 0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62
ERC1155 TransferBatch(address,address,address,uint256[],uint256[]) 0x4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb
ERC721,ERC1155 ApprovalForAll(address,address,bool) 0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31
ERC1155 URI(string,uint256) 0x6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b
Wyvern OrdersMatched(bytes32,bytes32,address,address,uint256,bytes32) 0xc4109843e0b7d514e4c093114b863f8e7d8d9a458c372cd51bfe526b588006c9

Reference


Ethereum 공식

ERC20 Token Standard: https://eips.ethereum.org/EIPS/eip-20

ERC721 NFT Standard: https://eips.ethereum.org/EIPS/eip-721

ERC1155 Multi Token Standard: https://eips.ethereum.org/EIPS/eip-1155

Etherscan: https://etherscan.io/

dune: https://dune.com/browse/dashboards

OpenSea 공식

OpenSea Docs v1(wyvern): https://docs.opensea.io/

OpenSea Docs v2(seaport): https://docs.opensea.io/v2.0/

OpenSea Github: https://github.com/ProjectOpenSea/seaport

OpenSea Blog: https://opensea.io/blog/

OpenSea ERC1155 거래 지원: https://opensea.io/blog/announcements/erc1155-marketplace/

OpenSea Bundles: https://opensea.io/blog/announcements/introducing-bundles/

OpenSea Wyvern V1으로 Market 시작: https://opensea.io/blog/announcements/bid-on-your-favorite-crypto-collectibles/

OpenSea Wyvern V2 업그레이드: https://opensea.io/blog/announcements/announcing-a-contract-upgrade/

OpenSea Wyvern 2.3 Protocol: https://opensea.io/blog/developers/wyvern-2-3-developer-upgrade-guide/

OpenSea Seaport Protocol Migration: https://opensea.io/blog/announcements/launching-seaport-saving-the-community-millions-in-fees/

OpenSea Seaport Protocol: https://opensea.io/blog/announcements/introducing-seaport-protocol/