LoginSignup
9
3

More than 1 year has passed since last update.

RLE形式(Run Length Encoding)のフルオンチェーンNFTのコントラクト解説

Posted at

BlockBaseエンジニアのぽんたです。

誰でもフルオンチェーンNFTを作れるサービスをリリースしたところ、反響がありました。

この記事では、そのコントラクトの一部を解説しようと思います。
githubはこちらです。

Nounsのピクセルアートの仕組み

このコントラクトはNounsDAOのコントラクトを参考に(ほぼコピーして)作っています。
NounsDAOについての解説はこちらの記事が詳しいのでオススメです!
https://ethereumnavi.com/2021/11/27/nouns-dao/

参考

RLE (Run Length Encoding) について

NounsではRun Length Encoding(連長圧縮)という手法を採用してオンチェーンに書き込むピクセルアートのデータ量を圧縮しています。Wikipediaからの引用ですが、

連長圧縮では、ある連続したデータを、そのデータ一つ分と連続した長さで表現することで圧縮している。例えば、「A A A A A B B B B B B B B B A A A」は「A 5 B 9 A 3」と表せる。

ということです。Nounsは32×32のピクセルアートで、左上から数えて1色目が何マス続いて、2色目が何マス続いて、3色目が何マス続いたあとにまた1色目が何マス続いて... というようなデータと、1色目は黄色、2色目は青色という情報のカラーパレットをブロックチェーン上に書き込み、プログラム上で画像を生成しています。

コントラクトを読み解く

まずNFTのコントラクトはこちらです。
NounsToken.sol

NounsToken.sol
function tokenURI(uint256 tokenId) public view override returns (string memory) {
    require(_exists(tokenId), 'NounsToken: URI query for nonexistent token');
    return descriptor.tokenURI(tokenId, seeds[tokenId]);
}

seedsにはパーツごとにRLEエンコードしたピクセルアートの情報が入っています。

INounsSeeder.sol
struct Seed {
    uint48 background;
    uint48 body;
    uint48 accessory;
    uint48 head;
    uint48 glasses;
}

これをNounsDescriptor.solとNFTDescriptor.solでレンダリングしています。

https://github.com/nounsDAO/nouns-monorepo/blob/master/packages/nouns-contracts/contracts/libs/NFTDescriptor.sol
↑ここではフルオンチェーンあるあるのbase64にエンコードしてmetadataを返しています。

一番重要なのがこの
MultiPartRLEToSVG.sol というライブラリです。

_generateSVGRectsという関数にパーツの情報と背景色とカラーパレットを渡すと、SVGのを生成してstringで返してくれます。heightは10で固定、widthとx,y,fill(色)が可変になっています。

MultiPartRLEToSVG.sol
function _getChunk(uint256 cursor, string[16] memory buffer) private pure returns (string memory) {
    string memory chunk;
    for (uint256 i = 0; i < cursor; i += 4) {
        chunk = string(
            abi.encodePacked(
                chunk,
                '<rect width="', buffer[i], '" height="10" x="', buffer[i + 1], '" y="', buffer[i + 2], '" fill="#', buffer[i + 3], '" />'
            )
        );
    }
    return chunk;
}

Seedはどうやって作るのか

seedを作っているのはここです!

このテストのように32×32の透過pngを引数に入れて関数を実行すると、rleでエンコードされた値が返ってきます。
https://github.com/nounsDAO/nouns-monorepo/blob/04c96bd35e9dcebd983db37dfd59248b0c90284a/packages/nouns-sdk/test/png-collection-encoder.test.ts#L24

以上です!

9
3
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
3