//tips
//smart contract
Contractを改修し、mintはownerアドレスのみにされるものとする。そしてテストネットワークで売買を実施していく。
nakinft-testを作成。
constructor() public ERC721("artCollectible", "ARTC") {}
ここを変更し、private onlyOwnerをつけようかと思ったがやりすぎのよう。つけるとしたらpublic onlyOwnerとなる。これは継承しているOwnable.solのmodifierを使用。
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
privateのみで十分なよう。publicは用途は幅広いが脆弱なため注意して使用。
claimItem関数内できちんとownerのアドレスがtokenidと紐付けてセットされているかを確認。
ベースとなるmappingは全てERC721に記載されている。
// Mapping from token ID to owner address
mapping(uint256 => address) private _owners;
// Mapping owner address to token count
mapping(address => uint256) private _balances;
// Mapping from token ID to approved address
mapping(uint256 => address) private _tokenApprovals;
実行されている_safemintはコントラクト宛てではなく個人アドレスであることを確認して、_mintを実行。_mintは宛先が0アドレスでなく、tokenIdも既に存在していることを確認してから送信先のtoken量の増加 _balances[to] += 1;とアドレス設定_owners[tokenId] = to;を行なっている。
function _safeMint(
address to,
uint256 tokenId,
bytes memory _data
) internal virtual {
_mint(to, tokenId);
require(
_checkOnERC721Received(address(0), to, tokenId, _data),
"ERC721: transfer to non ERC721Receiver implementer"
);
}
function _mint(address to, uint256 tokenId) internal virtual {
require(to != address(0), "ERC721: mint to the zero address");
require(!_exists(tokenId), "ERC721: token already minted");
_beforeTokenTransfer(address(0), to, tokenId);
_balances[to] += 1;
_owners[tokenId] = to;
emit Transfer(address(0), to, tokenId);
}
この際に_setTokenURI(newItemId, _tokenURI);にてipfsのurlをtokenidに紐づけて格納している。
Migrationの中身については特に変更しなくて良さそう。
https://trufflesuite.com/docs/truffle/getting-started/running-migrations/
https://qiita.com/blueplanet/items/e3f5590c9711df4d4845
また、シンボル設定の際のERC721のconstructor設定の確認。 constructor() public ERC721("nakiCollectible", "NKC") {}は下記の記述を継承して作成したもの。
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
.gitignoreを作成して、passの情報を含む.envと重すぎるnode_modulesをgitに上げる対象から外す。
Pinataにて直接jsonをアップロードできるかも確認しておく。先まではjsにてそちらを実行していたが、逆に難しくしている。もっと単純化して良い。
npx turffle console —network rinkeby
migrate
const art =await NakiCollectible.deployed()
undeifined
await art.claimItem(‘IPFSURL’)
このURLが下記の_tokenURIにあたる。
function claimItem(string memory _tokenURI) private returns (uint256) {
_tokenIds.increment();
uint256 newItemId = _tokenIds.current();
//only owner can mint
_safeMint(msg.sender, newItemId);
_setTokenURI(newItemId, _tokenURI);
return newItemId;
}
その上でオーナーを確認。自分のmetamaskのURLになっている。
await art.ownerOf(1)
その後にopenseaのテストネット対応サイトにてアップロードされているかの確認。
OpenseaテストネットURL+コントラクトアドレス+tokenidで確認できる。
ganacheにtruffleconfigを読み込ませテスト環境を設定していく。
npx truffle console
migrate
let art = await NakiCollectible.deployed();
Artのみ入力すると実行できる関数一覧が表示される。
art.address
これはコントラクトアドレスを表す。
ganacheのtransactionページにあるcontract creationの部分から確認できる。created contract addressが該当部分となる。
このコントラクトを呼んでいるのがfromのアドレスでそれがaccountページの一番上のアカウントと同じことが確認可能。
その後にdeploy後にmigrationを実行しているのでganacheにはcontact callというトランザクションが発生している。
art.name()とすると'nakiCollectible’が確認可能。
このコンタクトcreationする際にmigrationをすることが必要なのでこれはセットと考えてよさそう。2回目以降は変更していなければ接続のみで良さそうなので、そちらもどうなるか後で確認してみる。
パワポでtest1画像を簡単に作り、pngで保存、それをpinataにアップロードして画像のハッシュを取得。
pinataの画像読み込みが遅いので少し時間を置いてみる。
Pinata上にて画像のハッシュ情報は記載されているのでそちらをもとにmetadatatest.jsonをデスクトップのテキストエディタにて作成し、アップロードを試す。
きちんと取り込み内容のjsonを表示させることができた。
infuraのrinkbyエンドポイントを取得。
今度は開発環境ではなくテストネットでrinkbyのethを使用してデプロイを行う。
npx truffle console —network rinkeby
migrate
先に作成したコンパイルデータがbuildフォルダに入っていたので削除。
再度トライ。
npx truffle console —network rinkeby
migrate
const art =await NakiCollectible.deployed()
await art.claimItem(‘https://ipfs.io/ipfs/QmXYfhz3uup6Hd4PnyYDhR2QCvXZU7J56Z’)
Uncaught TypeError: art.claimItem is not a functionというエラーが発生なぜだ。
Privateにしているからだと思い至る。public onlyOwnerが正解か。再度トライ。
npx truffle console
migrate
let art = await NakiCollectible.deployed();
開発環境でも問題なし。
再度rinkebyネットワークでトライ。問題なくデプロイできた。
art.addressでコントラクトのアドレスを取得。
await art.claimItem('https://ipfs.io/ipfs/QmdL7J4XmDtjehxqedAy2FymkKe9')
無事に連続しての生成を行うことができることも確認。
一旦接続を切り、既にデプロイ済みのコントラクトにつなげる方法も確認する。
Abiを用いることになるかと思うが単純にweb3.eth.の流れでいけるのか。
const CryptoZombies = artifacts.require("CryptoZombies");
const contractInstance = await CryptoZombies.new();
const result = await contractInstance.createRandomZombie(zombieNames[0], {from: alice});
web3.jsは簡単にコントラクトを作るための web3.eth.Contract というファンクションがあるがこれを接続の際に使用するか。
どうやらjsで実行するしかないよう。
var abi = /* abi as generated by the compiler */;
var ClientReceipt = web3.eth.contract(abi);
var clientReceipt = ClientReceipt.at("0x1234...ab67" /* address */);
https://web3js.readthedocs.io/en/v1.2.11/web3-eth-contract.html
https://qiita.com/zaburo/items/35757fcc688942d7b5f4
https://blog.openreplay.com/interacting-with-smart-contracts-using-web3
https://docs.moonbeam.network/builders/build/eth-api/libraries/web3js/