NFTスマート・コントラクトの作成とデプロイ
この項では、NFT Marketplaceの設定に必要なNFTスマート・コントラクトを作成してデプロイする方法を学習します。
ブロックチェーン・アプリケーション・ビルダーを使用して、NFTの最小化、所有および転送を管理するスマート・コントラクトを生成します。このソリューションのコア・イネーブラは、Oracle Blockchain Platformを使用してNFTをミントして転送する機能です。
最初にNFT仕様ファイルを作成し、スマート・コントラクトをOracle Blockchain Platformインスタンスにデプロイします。その後、スマート契約をテストできます。
ブロックチェーン・アプリケーション・ビルダーのインストール
Oracle Blockchain Platformインスタンスをプロビジョニングしたら、次のステップを実行します:
- Oracle Blockchain Platformコンソールで、「開発者ツール」タブを開き、「ブロックチェーン・アプリケーション・ビルダー」ペインを選択します。
- 「ダウンロード」セクションで、コマンドライン・インタフェース(CLI)ツール・アーカイブまたはVisual Studio (VS)コード拡張をダウンロードし、ローカルに設定します。
サンプルNFT仕様ファイルのカスタマイズ
サンプルNFT仕様ファイルは、ブロックチェーン・アプリケーション・ビルダーに含まれています。次の例に示すように、これを使用してニーズに合わせて調整できます。
assets:
- name: ArtCollection
type: token
symbol: ART #mandatory
standard: erc721+
anatomy:
type: nonfungible
unit: whole
behavior:
- indivisible # mandatory
- singleton # mandatory
- mintable: # mandatory
max_min_quantity: 20000
- transferable
- burnable
- roles:
minter_role_name: minter
properties:
- name: price
type: number
- name: on_sale_flag
type: boolean
metadata:
- name: painting_name
type: string
- name: description
type: string
- name: image
type: string
- name: painter_name
type: string
customMethods:
- executeQuery
- "createAccountByConsumers(org_id: string, user_id: string, token_type: string)" # Create accounts for consumers while signing up
- "sell(token_id: string, selling_price: number)" # Post the token for selling in the marketplace
- "buyWithTokens(from_org_id: string, from_user_id: string, to_org_id: string, to_user_id: string, nonfungible_token_id: string, fungible_token_id: string, amount_paid: number)" # Buy the NFT after paying the using FT Tokens
- "buyWithDirectPayment(from_org_id: string, from_user_id: string, to_org_id: string, to_user_id: string, nonfungible_token_id: string, amount_paid: number)" # Buy the NFT after paying the amount using payment gateway
NFTチェーンコードでこの仕様を拡張するカスタム・プロパティおよびメソッドを追加できます。ブロックチェーン・アプリケーション・ビルダーによって生成されるNFTチェーンコードは、ERC-721
標準に基づいています。
Visual Studio Code拡張機能を使用してチェーンコード(スマート・コントラクト)を生成するには、次のステップを実行します。
- 「チェーンコード」セクションで、「+」アイコンをクリックします。「チェーンコード詳細」ペインが開きます。
- チェーンコード・プロジェクトの生成に必要なフィールドに入力します。
- チェーンコード・プロジェクトの名前を入力します。
- チェーンコード・メソッドを生成する言語として、
TypeScript
またはGo
を選択します。 - 前に作成した入力仕様ファイルを選択します。
- プロジェクトを生成する場所を入力します。
- 「作成」をクリックします。
UIの次のスクリーンショットは、「チェーンコードの作成」ウィンドウを示しています。

図blockchain_chaincode_details.pngの説明
src
ディレクトリの下にあるファイルを調べることで、モデルおよびコントローラの実装を確認できます。
- モデル・ファイルには、トークン、アカウントなどを表す生成されたすべてのデータ構造が含まれます。
- コントローラ・ファイルには、生成されたすべてのNFTライフサイクル・メソッドと、仕様に基づく必要な検証ロジックを持つサポート機能が含まれます。
/**
*
* BDB sql rich queries can be executed in OBP CS/EE.
* This method can be invoked only when connected to remote OBP CS/EE network.
*
*/
@Validator(yup.string())
public async executeQuery(query: string) {
const result = await this.query(query);
return result;
}
@Validator(yup.string(), yup.string(), yup.string())
public async createAccountByConsumers(org_id: string, user_id: string, token_type: string) {
//await this.Ctx.ERC721Auth.checkAuthorization('ERC721ACCOUNT.createAccount', 'TOKEN');
return await this.Ctx.ERC721Account.createAccount(org_id, user_id, token_type);
}
@Validator(yup.string(), yup.number())
public async sell (token_id: string, selling_price: number) {
try {
const token = await this.Ctx.ERC721Token.get(token_id);
const t = new ArtCollection(token)
t.price = selling_price;
t.on_sale_flag = true;
//console.log(token);
await this.Ctx.ERC721Token.update(t);
return `Token ID : '${token_id}' has been posted for selling in the marketplace'`;
} catch(error) {
throw new Error(error.message);
}
}
@Validator(yup.string(), yup.string(), yup.string(), yup.string(), yup.string(), yup.string(), yup.number())
public async buyWithTokens(from_org_id: string, from_user_id: string, to_org_id: string, to_user_id: string, nonfungible_token_id: string, fungible_token_id: string, amount_paid: number) {
try {
const token = await this.Ctx.ERC721Token.get(nonfungible_token_id);
const t = new ArtCollection(token);
const oChainUtil = new OChainUtils(this.Ctx.Stub);
var msg = `Token ID : '${nonfungible_token_id}' had not been transferred'`;
if (t.on_sale_flag==true) {
if(t.price == amount_paid) {
// @ts-ignore
await oChainUtil.invokeChaincode("LoyaltyToken7", "transferTokens", [fungible_token_id, from_org_id, from_user_id, amount_paid], "marketplace");
const from_account_id = await this.Ctx.ERC721Account.generateAccountId(from_org_id, from_user_id);
const to_account_id = await this.Ctx.ERC721Account.generateAccountId(to_org_id, to_user_id);
await this.Ctx.ERC721Token.transferFrom(from_account_id, to_account_id, t);
msg = `Token ID : '${nonfungible_token_id}' has been successfully transferred to UserID : '${to_user_id}'`;
}
}
else {
msg = `Token ID : '${nonfungible_token_id}' has not been transferred to UserID : '${to_user_id}' as the amount was not fully paid'`;
}
return msg;
} catch(error)
{
throw new Error(error.message);
}
}
@Validator(yup.string(), yup.string(), yup.string(), yup.string(), yup.string(), yup.number())
public async buyWithDirectPayment(from_org_id: string, from_user_id: string, to_org_id: string, to_user_id: string, nonfungible_token_id: string, amount_paid: number) {
try {
const token = await this.Ctx.ERC721Token.get(nonfungible_token_id);
const t = new ArtCollection(token);
var msg = `Token ID : '${nonfungible_token_id}' had not been transferred'`;
if (t.on_sale_flag==true) {
if(t.price == amount_paid) {
const from_account_id = await this.Ctx.ERC721Account.generateAccountId(from_org_id, from_user_id);
const to_account_id = await this.Ctx.ERC721Account.generateAccountId(to_org_id, to_user_id);
await this.Ctx.ERC721Token.transferFrom(from_account_id, to_account_id, t);
msg = `Token ID : '${nonfungible_token_id}' has been successfully transferred to UserID : '${to_user_id}'`;
}
}
else {
msg = `Token ID : '${nonfungible_token_id}' has not been transferred to UserID : '${to_user_id}' as the amount was not fully paid'`;
}
return msg;
} catch(error) {
throw new Error(error.message);
}
}
}
Smart Contractのデプロイ
チェーンコード・プロジェクトを作成した後は、ローカルにデプロイできます。
「チェーンコードの詳細」ペインで、「デプロイ」を選択してデプロイメント・ウィザードを開きます。ブロックチェーン・アプリケーション・ビルダーには、Dockerコンテナで実行されるローカル・ブロックチェーン・ネットワークがあり、テスト目的で使用できます。
ターゲット環境のリストから接続プロファイルを選択して、チェーンコードをOracle Blockchain Platformインスタンスにデプロイすることもできます。生成されたNFTチェーンコードには初期化のためにorgId
およびuserId
パラメータが必要であるため、初期化パラメータを完了して保存する必要もあります。orgId
およびuserId
パラメータを使用して、トークン管理者権限を持つユーザーを指定します。
Smart Contractのテスト
チェーンコードがデプロイされると、Oracle Blockchain Platformによって、トークン初期化、アカウントおよびロール管理、およびNFTライフサイクル・メソッド(作成、転送、書込み)用のREST APIが自動的に公開されます。
ブロックチェーン・アプリケーション・ビルダーの「チェーンコード詳細」ペインで「実行」を選択するか、PostmanなどのREST APIクライアントを使用してテストできます。
UIの次のスクリーンショットは、「チェーンコードの作成」ウィンドウの「実行」タブを示しています。

図blockchain_chaincode_execute.pngの説明
REST APIを使用してOracle Blockchain Platformスマート・コントラクト・メソッドを起動するには、POST
メソッドを使用し、2つの部分を連結したURLを指定します。最初の部分は、Oracle Blockchain PlatformのRESTプロキシ・エンドポイントです。このエンドポイントは、Oracle Blockchain Platformコンソールの「ノード」タブから取得できます。
2番目の部分は、Transaction APIを使用してトランザクションを起動する特定のURIです。POST
リクエストを送信するには、ドキュメンテーションを参照してください。2つの部分は、ここに示すような完全なURLを形成します。
https://oabcs1-iad.blockchain.ocp.oraclecloud.com:7443/restproxy/api/v2/channels/{channelName}/transactions
{channelName}
を、チェーンコードのデプロイ時に指定したチャネルの名前(marketplaceなど)に置き換えます。APIリクエストを作成する際は、次のステップを実行します。
REST_Client
ロールにマップされるuserid and password
を指定したBasic Auth
を使用するように認可を設定します。OAuth2
トークンを使用することもできます。詳細は、REST APIガイドのOAuth 2.0アクセス・トークン・ベース認証の使用を参照してください。Content-Type
ヘッダーをapplication/json
に設定します。- リクエストの本文に、チェーンコード名と
create<TokenName>Token
メソッド、必要な引数を含む、トランザクション呼出しに必要なパラメータを含めます。
yaml
テンプレートから生成されたチェーンコードに基づいて、次のテキストはサンプル・リクエスト本文と関連するレスポンスを示しています。
要求
{
"chaincode": "{{NFTChaincode}}",
"args": [
"createArtCollectionToken",
"{\"token_id\":\"{{NFTTokenID}}\",\"token_uri\":\"https://ipfs.io/ipfs/QmV68aiT7xw2WX8pmDbeTWpGP2or35NUFan9RagymsLpgV?filename=ArtCollection_NFT1.json\",\"metadata\":{\"painting_name\":\"Oracle - Red Bull Partnership\",\"image\":\"https://ipfs.io/ipfs/QmVap6Gkh3Cp9DiLLWvkvJHpuXpFmYB2GzU1caM57gNcAa?filename=Oracle_RedBull_NFT1.jpeg\",\"painter\":\"Alex\"},\"price\":200,\"on_sale_flag\":false}"
],
"timeout": 0,
"sync": true
}
応答
{
"returnCode": "Success",
"error": "",
"result": {
"txid": "c999922f04c3011bf25ca43624e4bb23e8900634f8e23a1648170a90274a9733",
"payload": {
"metadata": {
"painter": "Alex",
"painting_name": "Oracle - Red Bull Partnership",
"image": "https://ipfs.io/ipfs/QmVap6Gkh3Cp9DiLLWvkvJHpuXpFmYB2GzU1caM57gNcAa?filename=Oracle_RedBull_NFT1.jpeg"
},
"assetType": "otoken",
"created_by": "oaccount~eadf1b0ae857164f8681d1742b6328089a7d33ebec76d8248cb909da7a84f42a",
"creation_date": "2022-04-28T12:08:38.000Z",
"owner": "oaccount~eadf1b0ae857164f8681d1742b6328089a7d33ebec76d8248cb909da7a84f42a",
"uri": "https://ipfs.io/ipfs/QmV68aiT7xw2WX8pmDbeTWpGP2or35NUFan9RagymsLpgV?filename=ArtCollection_NFT1.json",
"is_burned": false,
"token_id": "NFT17",
"token_name": "artcollection",
"symbol": "ART",
"token_standard": "erc721+",
"token_type": "nonfungible",
"token_unit": "whole",
"behaviors": [
"indivisible",
"singleton",
"mintable",
"transferable",
"burnable",
"roles"
],
"roles": {
"minter_role_name": "minter"
},
"mintable": {
"max_mint_quantity": 20000
},
"token_uri": "https://ipfs.io/ipfs/QmV68aiT7xw2WX8pmDbeTWpGP2or35NUFan9RagymsLpgV?filename=ArtCollection_NFT1.json",
"price": 200,
"on_sale_flag": false
},
Golang
またはTypeScript
メソッド、Platform REST API
など、NFTチェーンコードの管理に使用できるメソッドの詳細は、「さらに探索」の項を参照してください。
APIは、Oracle Content Management WebフックとVisual Builder Cloud Service (VBCS)上に構築されたWebアプリケーションから直接コールすることも、外部でホストされているマーケットプレイスWebアプリケーションで使用するためにAPIゲートウェイを再マップしてラップすることもできます。NFTを作成(最小)する場合、指定する必要があるパラメータの1つはtoken_uri
で、デジタル・オブジェクトを表すJSON
ファイルを指すIPFS URI
であることに注意してください。
https://ipfs.io/ipfs/QmV68aiT7xw2WX8pmDbeTWpGP2or35NUFan9RagymsLpgV?filename=ArtCollection_NFT1.json
次の手順では、IPFSデスクトップを使用してトークンURIを生成する例について説明します。
IPFS
にイメージ・ファイルをアップロードし、イメージのURIを保存します。- イメージURIと関連メタデータ・フィールドを含む
JSON
ファイルを作成してアップロードします。 - ...の
JSON
ファイルへのリンクを共有してコピーします。「詳細」リスト。
{
"painting_name": "Oracle - Red Bull Partnership",
"description": "Cloud Partnership",
"image": "https://ipfs.io/ipfs/QmVap6Gkh3Cp9DiLLWvkvJHpuXpFmYB2GzU1caM57gNcAa?filename=Oracle_RedBull.jpeg",
"painter_name": "Alex"
}
token_uri
パラメータのJSON
ファイルを指すURIを使用します。
create<Token-Name>Token
メソッドに渡される属性に、関連するメタデータを含めることもできます。これにより、Oracle Blockchain Platform元帳でメタデータを保持して簡単に取得できます。
Oracle Content Management (OCM)を使用して作成されたNFTの場合、OCM Webフックを使用してAPIゲートウェイを使用してOracle Functionsをコールし、アーキテクチャ図に示すように、REST APIの呼出しをOracle Functionsに配置します。また、ブロックチェーンREST APIは、マーケットプレイスのWebアプリケーションから直接呼び出すことも、APIゲートウェイ・マッピングを使用してユーザー生成のコンテンツをサポートすることもできます。Marketplace取引機能では、支払を処理するためのカスタム・メソッドを起動してから、buyWithTokens
やbuyWithDirectPayment
サンプル・メソッドなどのNFT所有権の転送をトリガーできます。