PlayTrain
面ではなく、線で考えてみた。
NFT の誕生によって、さまざまなコレクションが生まれ、オンラインで目に見えるものになった。そこでは分散が思い描かれ、点として存在していた個々の存在が、NFT を通じて面になる。
今回は、NFT の領域で個人のアイデンティティの象徴である ENS を使い、一つのコレクションを線として構想した。
tsh.eth が先頭を走る列車に、どうぞ乗ってほしい。
midorikanemitsu.onigiriman1998.yujiym.pon24.haukun.maishumai.caicaikiki.borddy.mayuzou.eotel.june29.yuhei4on6.hiraiken.hasaqui.themassage.gin-graphic.daumkuchen.niinomi.uminonaka.noriakinft.royalmilktea.rugstore.ara721.sanjrow.takawo.hnmhdk.miyakodub.kumaartcollective.bouze.proofofx.tsh.eth

列車への乗り方
新しい乗車は、いまは受け付けていない。乗りたい人は、連絡してほしい。
乗車の状況を確かめる
OpenSea
Technical Note
このプロジェクトでは、Ethereum Mainnet 上の ENS(Ethereum Name Service)と、その NameWrapper を使っている。ENS は ETH のウォレットアドレスを、人が読みやすい形にする。さまざまなレコードを結びつけることもでき、自分のアイデンティティを表せる。
さらに ENS には、URL のサブドメインにあたる「Subname」というものがある。このプロジェクトでは、この Subname を重ねていくことで「電車ごっこ」をしている。
Subname は NameWrapper 上にすでにあるノードからしか生成されず、NFT として配られるときには、そのノードの保有者に送られる。そのため参加者は、あらかじめ自分の ENS を wrap しておく必要がある。

Contract
Etherscan で検証済みのソース。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import "./INameWrapper.sol";
import "./ENS.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol";
import "https://github.com/ensdomains/name-wrapper/blob/master/contracts/BytesUtil.sol";
contract PlayTrain is Ownable, ERC1155Holder {
using BytesUtils for bytes;
INameWrapper nameWrapper;
uint256 public index;
address public resolver;
bool public isMintable;
mapping(bytes32 => bool) public isMinted;
mapping(uint256 => bytes32) public indexToNode;
mapping(uint256 => address) public indexToOwner;
function setEnsData(address _nameWrapper, address _resolver, bytes32 _startNode) external onlyOwner {
nameWrapper = INameWrapper(_nameWrapper);
resolver = _resolver;
indexToNode[0] = _startNode;
}
function getOnTheTrain(bytes32 yourNode, string memory label) public {
require(isMintable, "PlayTrain: not mintable");
require(!isMinted[yourNode], "PlayTrain: Already minted");
bytes memory name = nameWrapper.names(yourNode);
(bytes32 labelhash, ) = name.readLabel(0);
require(labelhash == keccak256(bytes(label)), "PlayTrain: label is not correct");
nameWrapper.setSubnodeRecord(
indexToNode[index],
label,
address(this),
resolver,
0,
0,
0
);
bytes32 nextParentNode = _makeNode(indexToNode[index], labelhash);
(address owner, ,) = nameWrapper.getData(uint256(yourNode));
uint256 nextIndex = ++index;
indexToOwner[nextIndex] = owner;
indexToNode[nextIndex] = nextParentNode;
isMinted[yourNode] = true;
if(index > 2){
uint256 tokenid = uint256(indexToNode[index - 2]);
nameWrapper.safeTransferFrom(address(this), indexToOwner[index - 2], tokenid, 1, "");
}
}
function setMintable(bool _isMintable) external onlyOwner {
isMintable = _isMintable;
}
function _makeNode(bytes32 node, bytes32 labelhash) private pure returns (bytes32) {
return keccak256(abi.encodePacked(node, labelhash));
}
function getIndex() external view returns(uint256) {
return index;
}
function getNode(uint256 _index) external view returns(bytes32) {
return indexToNode[_index];
}
function transfer(address from, address to, uint256 id) external onlyOwner {
nameWrapper.safeTransferFrom(from, to, id, 1, "");
}
function onERC1155Received(
address operator,
address from,
uint256 id,
uint256 value,
bytes memory data
) public override(ERC1155Holder) returns(bytes4) {
return ERC1155Holder.onERC1155Received(operator, from, id, value, data);
}
}
Read / Write
Ethereum mainnet の契約を直接読み、自分のウォレットから呼び出せる。読むだけならウォレットは要らない。
PlayTrain0x77b01FeB029abA23FD3FCfD448B942FDBd437464
Exhibitions
Proof of X - Blockchain As A New Medium For ArtTHE FACE DAIKANYAMA、東京2023-06-17 – 2023-06-25