メタバース アプリケーション開発例 - イーサリアムのスマート コントラクトと Decentraland の 3D フロントエンド インタラクティブ コンポーネント

1. メタバースコアテクノロジー

Tencent は最近、Quanzhen Internet に関するホワイト ペーパーを発表しました。彼らは違いを強調しましたが全真互联元宇宙絶望的にそれは現実離れしているように思えます。コア テクノロジーの観点から見ると、実際には元宇宙Web3.0これは全真互联同じもので、どちらもフロントエンド テクノロジーとバックエンド テクノロジーの開発の産物です。

  • フロントエンドインタラクティブ技術( を含む软件渲染技术)の発展により硬件交互设备、インターネットは PC でのみ PGC を閲覧できる Web1.0 から、携帯電話でも UGC を閲覧できる Web2.0 に発展しました。現在、さまざまなスマートウェアラブルデバイス上で人間の異なる感覚で三次元コンテンツを操作できるWeb3.0、それがメタバースが開発されています。
  • コンテンツの種類と規模が増加すると、バックエンド コンピューティング、ストレージ、ネットワーク処理能力の強化が必然的に必要になります。云计算全栈软硬件技术継続的な進化はWeb1.0、2.0、3.0と変化を支えますが、メタバースである3.0になると、智能合约社会形態の変化(NFT・非同種化など)に合わせてバックエンドに別の技術が追加されます。デジタル資産、デジタル通貨など)、スマートコントラクトはもちろん必ずしもブロックチェーンに接続されているわけではありませんが、ブロックチェーンは確かにそれを実装する効果的な方法です。

Tencent の Quanzhen Internet は確かに意図的にスマートコントラクトを避けてきましたが、これは驚くべきことではありません。Tencent ほど賢い人は真実を知っているので、そのような危険なものには触れられません。これが、国内のメタバーススタートアップのほとんどが集中している理由です。フロントエンド技術のため、そして、Tencent 自体は商業的に Web2.0 の既得権益であり、自社を含むこれらの中央インターネット プラットフォームを削除することを望まないのは明らかです。

完全なメタバース アプリケーション開発を技術的に実装するために、この記事では実験用のプラットフォームとしてDecentralandを選択します。

2. メタバースの例と応用例

この例のビジネス モデルの詳細については、前の記事を参照してください。この記事は実際の開発過程を技術的な観点から検証したものを記録するものです。

Decentraland は、イーサリアムブロックチェーンに基づく分散型仮想現実プラットフォームですメタバースの定義に高度に準拠した仮想世界であり、この世界のメンバーはその上で他の人のコンテンツやアプリケーションを土地作成し内容应用使用したり、自分のコンテンツやアプリケーションを使用したりすることができますDecentraland の土地はイーサリアム スマート コントラクトによって維持される一種の NFT であり、内部の空間は 3D であり、ユーザーはその中を歩き回ることができ、土地の総数には制限があります。土地は分割されており、座標によって区画が識別され、これらの区画はこの世界のメンバーによって永続的に保持され、ディセントラランドの公式暗号化デジタル通貨であるMANA (マナ通貨)で取引することができます。ユーザーは自分の土地を完全に制御し、既製またはカスタムの 3D フロントエンド コンポーネントを使用して、静的な 3D シーンやインタラクティブなゲームやアプリケーションを作成できます。体验赚钱Parcel

この記事で実装するのは、カスタム 3D インタラクティブ フロントエンド コンポーネント (Decentraland で呼ばれるSmart Item) で、これにはイーサリアム スマート コントラクトによって維持されるインタラクティブな広告コンテンツが含まれます。この契約は 4 者間契約であり、参加者は组件运营者土地所有者广告发布者、です消费者契約全体が機能するプロセスは次のとおりです。

  • コンポーネント オペレーターはコンポーネントを次Decentraland Builderの場所に公開します。
  • 広告発行者はコンポーネントに広告を発行します。
  • 土地所有者は、Decentraland Builder で自分の土地の建物にコンポーネントを組み立てます
  • 消費者がこの建物に来て広告をクリックすると、広告主は合意金額に応じて土地所有者とモジュール運営者にMANAを支払う
  • 消費者が広告を開くと購入が発生し、広告主は合意金額に応じて消費者にMANAを支払います。

3. イーサリアムでのスマートコントラクト開発

3.1. World Wide Web のアクセシビリティ

まず、プロキシまたはその他の手段を使用してワールドワイド ネットワークにアクセスします。

3.2. イーサリアムウォレットの初期化

  • 暗号通貨ウォレットMetaMaskchrome应用商店をインストールし、プロンプトに従ってデフォルトのアカウントを作成します。chrome插件形式
  • chrome の右上隅でMetaMask插件界面、デフォルトのアカウントの名前を「Component Operator」に変更します。
  • 先に進み、「Landowner」、「Advertiser」、「Consumer」という名前の 3 つのアカウントを作成します。
  • 現在のチェーンを から に以太坊Ethereum主网络切り替えますRopsten测试网络注: このテスト ネットワークは、2022 年の第 4 四半期の終わりまでのみ使用できます。イーサリアムでの「マージ」が完了すると、このテスト ネットワークはオフラインになり、テストは新しいネットワークに切り替える必要があります。ただし、Decentraland はこの新しいネットワークをまだサポートしていませんSepolia test network。テスト ネットワーク。
  • Ropsten テストネットワークの無料トークン取得ページを開き、アカウントを「コンポーネント事業者」「広告発行者」「消費者」の順に切り替えて、これら 3 つのアカウントのいずれかにそれぞれリチャージします以太币。 MetaMask パネル 確かに。これらのイーサは、イーサリアム上でトランザクションを実行するコストをカバーするために使用されます。「Sepoliaテストネットワーク」を利用する場合、無料でページを取得するにはSepoliaのトークンを使用する必要がありますが、トークンが届くまでに2時間程度かかります。
  • Ropster で Decentraland の MANA テスト トークンの無料取得ページを開き、「広告主」アカウントの MANA トークンをリチャージします。転送は MetaMask パネルで確認する必要があります。これらの MANA は、4 者間契約が取引を実行するときに使用する通貨です。

3.3. 4者間契約の開発

以太坊智能合约開発に使用される言語はSolidityです。Solidity を使用すると、C++ を使用してシステム ソフトウェアを作成したり、メモリのきめ細かい計画を作成したり、コードを極端に洗練したりすることを思い出します。これは、コントラクトをチェーン上に保存し、チェーン上で実行する必要があるためで、コードサイズと実行メモリが大きくなるほど、より多くのリソースが消費され、より多くのお金が支払われます。削除できるものはすべてクリーンにし、コメントはなく、変数名もできるだけ短くする必要があります。この記事のコード コメントはロジックを説明するためのものであり、実際の運用時にはコメントを削除し、変数名を短縮する必要があります。

受託開発ツールはRemixです。Remix はローカルにデプロイできますが、検証プロセスではSaaS バージョンを直接使用します。Remix を開き、ようこそインターフェイスをスキップし、開発インターフェイスに入り、左側の を選択して、File explorerフォルダーcontractsの下に新しい Solidity プログラム ファイルを作成し、名前を付けますdmall.sol(この例ではコントラクトの名前は ですDMall)。次のコードをコピーします。ファイルの真ん中:

//SPDX-License-Identifier: UNLICENSED

pragma solidity >=0.7.0 <0.9.0;

// 声明MANAToken的接口,用于DMall合约中调用
interface MANAToken {
    
    
    // 广告所有者必须在发布广告之前,调用MANAToken的这个接口,允许DMall从他的MANA账户里划转代币到其他账户,其中_sender参数为DMall部署后的地址,_value参数为允许划转的MANA代币数量的上限
    function approve(address _sender, uint256 _value) external returns (bool);
    // DMall合约会调用这个接口,将MANA代币从广告所有者转账到其他三个账户,_from是广告所有者,_to是其他三个账户,_value是转账金额
    function transferFrom(address _from, address _to, uint256 _value) external returns (bool);
}

contract DMall {
    
    
    // 广告的状态枚举,广告所有者首次调用uptAd接口创建接口后为Created,组件运营者调用apprAd接口同意后变为Approved,广告所有者再次调用uptAd接口后为Updated,此时还需要组件运营者调用apprAd接口。只有Approved状态的广告可以被看到和购买。Undefined是初始状态,无意义,Invalid是广告因为其他原因(如广告发布者没给MANA)失效。
    enum AdState {
    
     Undefined, Created, Approved, Updated, Invalid } 
    // 广告点击记录的状态,Undefined是初始状态,无意义,Clicked表示消费者点击过了(即调用clickAd),Bought表示消费者买过了(即调用buyAd)。
    enum ClickState {
    
     Undefined, Clicked, Bought } 
    // 在链上存储的一条广告的数据结构
    struct Ad {
    
    
        // 广告点击时,广告发布者给土地所有者的MANA数量
        uint m2L;
        // 广告点击时,广告发布者给组件运营者的MANA数量
        uint m2O;
        // 广告被购买时,广告发布者给消费者的MANA数量
        uint m2C;
        // 广告的状态
        AdState state;
        // 广告的点击记录数据集合,第一个地址是土地所有者的地址,第二个地址是消费者的地址,最终里面存的数据是一条点击数据的状态
        mapping(address => mapping(address => ClickState)) clicks;
    }
    // MANAToken合约的地址
    MANAToken manaToken;
    // 广告数据集合,第一个地址是广告发布者的地址,第二个整数是广告ID,数据是上面的Ad结构体
    mapping(address => mapping(uint => Ad)) public ads;
    // 合约运营者,就是组件运营者的地址
    address public op;

    // 合约构造函数,用调用者的地址初始化合约运营者地址,用输入的MANAToken合约地址初始化对应数据,由所在的链是生产链还是测试链决定
    constructor(address _manaToken) {
    
    
        op = msg.sender;
        manaToken = MANAToken(_manaToken);
    }
    
    // 因为链上的操作都是异步的,需要存在链上才算成功,以下事件是对应接口调用成功后的回调,可在前端应用程序中实现

    // 广告创建成功后的事件(uptAd接口首次调用后的事件)
    event AdCrted(address merchant, uint adId, uint m2L, uint m2O, uint m2C);
    // 广告更新成功后的事件(uptAd接口再次调用后的事件)
    event AdUpted(address merchant, uint adId, uint oM2L, uint oM2O, uint oM2C, uint m2L, uint m2O, uint m2C);
    // 广告批准成功后的事件(apprAd接口调用后的事件)
    event AdAppred(address merchant, uint adId);
    // 广告点击后的事件(clickAd接口调用后的事件)
    event AdClicked(address merchant, uint adId, address landowner, address consumer);
    // 广告失效事件(clickAd接口或buyAd接口中发生失败后的事件)
    event AdInvalid(address merchant, uint adId);
    // 广告被购买事件(buyAd接口调用后的事件)
    event AdBought(address merchant, uint adId, address landowner, address consumer);

    // 创建或更新广告,由广告发布者调用,_adId是广告的ID,_m2L是广告发布者愿意给土地所有者的MANA数量,_m2O是广告发布者愿意给组件运营者的MANA数量,_m2C是广告发布者愿意给消费者的MANA数量
    function uptAd(uint _adId, uint _m2L, uint _m2O, uint _m2C) public {
    
    
        // 初始化一个Ad对象
        Ad storage ad = ads[msg.sender][_adId];
        if (ad.state == AdState.Undefined) {
    
    
            // 如果这是个新广告,则设置参数,并触发AdCrted
            ad.state = AdState.Created;
            ad.m2L = _m2L;
            ad.m2O = _m2O;
            ad.m2C = _m2C;
            emit AdCrted(msg.sender, _adId, _m2L, _m2O, _m2C);
        }
        else {
    
    
            // 如果不是新广告,则记录当前参数,设置新参数,并触发AdUpted
            ad.state = AdState.Updated;
            uint oM2L = ad.m2L;
            uint oM2O = ad.m2O;
            uint oM2C = ad.m2C;
            ad.m2L = _m2L;
            ad.m2O = _m2O;
            ad.m2C = _m2C;
            emit AdUpted(msg.sender, _adId, oM2L, oM2O, oM2C, _m2L, _m2O, _m2C);
        }
    }
    // 批准广告,由组件运营者调用, _merchant是广告发布者地址,_adId是广告的ID
    function apprAd(address _merchant, uint _adId) public {
    
    
        // 要求只能是组件所有者调用
        require(msg.sender == op, "Only DMall operator can approve the deployment of Ad");
        // 要求广告不是初始状态和批准过的状态
        require(ads[_merchant][_adId].state != AdState.Undefined && ads[_merchant][_adId].state != AdState.Approved , "The ad of merchant with the ID does not exist or has been approved");
        // 设置广告状态
        ads[_merchant][_adId].state = AdState.Approved;
        // 触发AdAppred事件
        emit AdAppred(_merchant, _adId);
    }

    // 点击广告,由消费者调用,_merchant是广告发布者地址,_adId是广告的ID,_landowner是广告所在土地的土地所有者
    function clickAd(address _merchant, uint _adId, address _landowner) public {
    
    
        // 需要广告是Approved的
        require(ads[_merchant][_adId].state == AdState.Approved, "The ad of merchant with the ID has not been approved");
        // 需要广告不是已被此消费者点击状态
        require(ads[_merchant][_adId].clicks[_landowner][msg.sender] != ClickState.Clicked, "The clicking had been paid but does not lead to buying yet");
        // 广告发布者按约定给土地所有者和组件运营者转账
        if (manaToken.transferFrom(_merchant, _landowner, ads[_merchant][_adId].m2L) && manaToken.transferFrom(_merchant, op, ads[_merchant][_adId].m2O) ) {
    
    
            // 如果转账成功,则标记点击状态,触发AdClicked
            ads[_merchant][_adId].clicks[_landowner][msg.sender] = ClickState.Clicked;
            emit AdClicked(_merchant, _adId, _landowner, msg.sender);
        }
        else {
    
    
            // 转账失败,则标记广告失效,触发AdInvalid
            ads[_merchant][_adId].state = AdState.Invalid;
            emit AdInvalid(_merchant, _adId);
        }
    }

    // 购买广告商品,由消费者调用,_merchant是广告发布者地址,_adId是广告的ID,_landowner是广告所在土地的土地所有者
    function buyAd(address _merchant, uint _adId, address _landowner) public {
    
    
        // 需要消费者点击过此广告
        require(ads[_merchant][_adId].clicks[_landowner][msg.sender] == ClickState.Clicked, "The consumer does not click the ad or has bought");
        // 广告发布者转账给消费者
        if (manaToken.transferFrom(_merchant, msg.sender, ads[_merchant][_adId].m2C)) {
    
    
            // 转账成功,则将广告点击记录标记为Bought,并触发AdBought
            ads[_merchant][_adId].clicks[_landowner][msg.sender] = ClickState.Bought;
            emit AdBought(_merchant, _adId, _landowner, msg.sender);
        }
        else {
    
    
            // 转账失败,则标记广告失效,触发AdInvalid
            ads[_merchant][_adId].state = AdState.Invalid;
            emit AdInvalid(_merchant, _adId);
        }        
    }
}

3.4. DMall スマート コントラクトを手動で実行する

  • Chrome の右上隅にある MetaMask プラグインのパネルで、必ず「Ropsten Test Network」チェーンと「Component Operator」アカウントに切り替えてください。
  • Remix の左側にあるボタンを選択してSolidity CompilerクリックしますCompile dmall.sol
  • ENEIRONMENT選んでくださいInjected Provide - MetamaskCONTRACT選んでくださいDMall
  • Decentraland のスマート コントラクト アドレス ページ、Ropsten ネットワークの MANAToken アドレスを見つけます。0x2a8fd99c19271f4f04b1b7b9c4f7cf264b626edb
  • ボタンの後の入力ボックスに上記のアドレスを入力しDeploy、「デプロイ」ボタンをクリックして、「MetaMask」パネルがポップアップするまで待ち、确认クリックして DMall コントラクトのデプロイを完了します。
  • CONTRACT を再度選択し、ボタンの後の入力ボックスに以前の MANAToken アドレスを入力してから、At​​ Address ボタンをクリックし、MetaMask パネルで確認のポップアップが表示されるのを待ち、クリックして Remix 上で MANAToken コントラクトの表示を完了しますMANATokenAt Addressこれは私たちがデプロイしたものではなく、単にインターフェイスを呼び出すためのものです
  • MetaMask パネルで、広告主アカウントに切り替えます。
  • 次に、契約のアドレスを見つけDeployed Contractsてコピーし、契約を開いてインターフェイスを開き、上でコピーした DMALL アドレスを入力し、100000 などの大きな数値を入力します。ボタンをクリックし、MetaMask パネルでポップアップ確認が表示されるのを待ち、クリックして DMALL 契約に対する広告主の承認を完了します。DMALLMANATOKENapprove_sender_valuetransact
  • DMALL コントラクトのインターフェースを開きuptAd_adId=1、_m2L=11、_m2O=12、_m2C=13 と入力し、transactボタンをクリックして、MetaMask パネルのポップアップ確認を待ち、クリックして広告の作成を完了します。
  • MetaMask パネルで、広告主のアドレスをコピーし、コンポーネント オペレーターのアカウントに切り替えます。
  • DMALL コントラクトのインターフェースを開きapprAd_merchant先ほどコピーしたアドレス_adId(1)を入力しtransact、ボタンをクリックして、MetaMask パネルに確認がポップアップ表示されるのを待ち、クリックして広告の承認を完了します。
  • MetaMask パネルで、コンシューマー アカウントに切り替えます。
  • DMALL 契約のインターフェイスを開きclickAd_merchant広告主の住所、_adId1、_landowner土地所有者の住所を入力し、transactボタンをクリックし、MetaMask パネルに確認のポップアップが表示されるまで待ち、クリックして広告のクリックを完了します
  • 現時点では、MetaMask パネルのアカウント詳細ページからイーサリアムと MANA コインのアカウントの変更を確認できます。
  • DMALL 契約のインターフェースを開きbuyAd_merchant広告主の住所、_adId1、_landowner土地所有者の住所を入力し、transactボタンをクリックし、MetaMask パネルにポップアップ確認が表示されるまで待ち、クリックして広告の購入を完了します。
  • 現時点では、MetaMask パネルのアカウント詳細ページから Ether と MANA のアカウント変更を確認できます。

3.5. Python が DMall スマート コントラクトを呼び出す

  • コードで呼び出すことができる Ethereum API インターフェイス アドレスを作成する
    • infuraページユーザー登録してログインし、右上隅のDashboardEnterを選択します
    • CREATE NEW KEY右上隅のボタンを選択します
    • ネットワーク選択Web3 API
    • 次にEthereumMAINNETから に切り替えますRopstenが、Ropsten は消えています。次の形式でキーを置き換えるか、直接使用できます: https://ropsten.infura.io/v3/dd4cc999659f448d905400a4e8fb4e9d
  • PyCharmをインストールする
  • コントラクトインターフェースファイルを作成する
    • PyCharmでワークスペースを作成し、そこにcontract_abi.pyファイルを追加します
    • Remix の左側で、 を選択しSolidity Compiler、CONTRACT を選択して DMALL を選択し、以下をクリックしますABI复制按钮
    • Contract_abi.py に「 」と入力しdmall_abi = """"""、上でコピーした内容を 6 つのセミコロンの中間に貼り付けます。
    • MANAToken のコード ページContract ABIセクションの右上隅をクリックします。Copy ABI to clipboard
    • Contract_abi.py に新しい行を入力しmanatoken_abi = """"""、上でコピーした内容を 6 つのセミコロンの中間に貼り付けます。
  • MetaMask パネルで、広告主の秘密キーをエクスポートします。
  • PyCharm で、プロジェクトの Web3 パッケージ (pip install web3) をインストールし、dmalltest.py を作成し、次のコードを貼り付け、コメントに従ってコントラクトのインターフェースの一部をデバッグおよび検証します。
import time
from web3 import Web3, HTTPProvider
from web3.logs import IGNORE
import contract_abi

# DMall合约的地址,从Remix中获得,输入单引号之间
dmall_address = Web3.toChecksumAddress('')
# MANAToken合约的地址
manatoken_address = Web3.toChecksumAddress('0x2a8fd99c19271f4f04b1b7b9c4f7cf264b626edb')

# 广告发布者的Private Key,将前文导出的值输入单引号之间
merchant_private_key = ''
# 广告发布者的账号地址,从MetaMask面板中获得,输入单引号之间
merchant_address = ''
# 土地所有者的账号地址,从MetaMask面板中获得,输入单引号之间
landowner_address = ''
# 消费者的账号地址,从MetaMask面板中获得,输入单引号之间
consumer_address = ''

# 以太坊API地址,将前文infura获取的https地址输入单引号之间
w3 = Web3(HTTPProvider(''))

# 初始化DMall和MANAToken合约的接口和事件
dmall_contract = w3.eth.contract(address=dmall_address, abi=contract_abi.dmall_abi)
manatoken_contract = w3.eth.contract(address=manatoken_address, abi=contract_abi.manatoken_abi)

# 广告所有者在MANAToken合约上批准DMall合约对其账户的MANA进行操作
def m_appr_dmall(dmall, amount):
    nonce = w3.eth.getTransactionCount(merchant_address)
    # 创建MANAToken上的一个交易,内容就是执行approve接口
    txn_dict = manatoken_contract.functions.approve(dmall, amount).buildTransaction({
    
    
        'chainId': 3,
        'gas': 140000,
        'gasPrice': w3.toWei('40', 'gwei'),
        'nonce': nonce,
    })
    # 用广告所有者的Private Key给上述交易签名
    signed_txn = w3.eth.account.signTransaction(txn_dict, private_key=merchant_private_key)
    # 执行交易
    result = w3.eth.sendRawTransaction(signed_txn.rawTransaction)
    # 轮询等待交易成功
    tx_receipt = None
    count = 0
    while tx_receipt is None and (count < 30):
        time.sleep(10)
        try:
            tx_receipt = w3.eth.get_transaction_receipt(result)
            print(tx_receipt)
        except Exception as e:
            print('error: ', e)

    if tx_receipt is None:
        return {
    
    'status': 'failed', 'error': 'timeout'}

    # 处理异步返回的事件
    processed_receipt = manatoken_contract.events.Approval().processReceipt(tx_receipt, errors=IGNORE)
    print(processed_receipt)

    return {
    
    'status': 'added', 'processed_receipt': processed_receipt}


# 广告所有者发布广告
def m_pub_ad(ad_id, m_2_l, m_2_o, m_2_c):
    nonce = w3.eth.getTransactionCount(merchant_address)
    # 创建DMall上的一个交易,内容就是执行创建广告的接口
    txn_dict = dmall_contract.functions.uptAd(ad_id, m_2_l, m_2_o, m_2_c).buildTransaction({
    
    
        'chainId': 3,
        'gas': 140000,
        'gasPrice': w3.toWei('40', 'gwei'),
        'nonce': nonce,
    })
    # 用广告所有者的Private Key给上述交易签名
    signed_txn = w3.eth.account.signTransaction(txn_dict, private_key=merchant_private_key)
    # 执行交易
    result = w3.eth.sendRawTransaction(signed_txn.rawTransaction)
    # 轮询等待交易成功
    tx_receipt = None
    count = 0
    while tx_receipt is None and (count < 30):
        time.sleep(10)
        try:
            tx_receipt = w3.eth.get_transaction_receipt(result)
            print(tx_receipt)
        except Exception as e:
            print('error: ', e)

    if tx_receipt is None:
        return {
    
    'status': 'failed', 'error': 'timeout'}

    # 处理异步返回的事件
    processed_receipt = dmall_contract.events.AdCrted().processReceipt(tx_receipt)
    print(processed_receipt)

    return {
    
    'status': 'added', 'processed_receipt': processed_receipt}


if __name__ == "__main__":
    # 可分别打开以下两行注释符号,执行对应函数,验证合约执行情况
    m_appr_dmall(dmall_address, 100)
    #m_pub_ad(2, 21, 22, 23)

4. ディセントラランドでのスマートアイテム開発

DecentralandはBuilder (ログインにはイーサリアムメインネットワークを使用する必要があります)を利用して構築されておりScene、Sceneが実際のLand環境にデプロイされて建物となります。シーンを構築するコンポーネントには、共通コンポーネントとスマート アイテムの2 種類があり、スマート アイテムはユーザーの操作に応答してコードを実行できるコンポーネントです。Github から既存のスマート アイテム コードを取得し、コードを変更して、コントラクトの実行を確認できます。

git clone [email protected]:decentraland/smart-items.git

既存のスマート アイテムを選択し、item.tsそのソース コードのspawn関数に次のコードを追加してスマート コントラクトを呼び出すことができます。

    ent.addComponent(
      new OnPointerDown(
        async function () {
    
    
            const provider = await getProvider()
            const requestManager = new RequestManager(provider)
            const factory = new ContractFactory(requestManager, abi)
            // 需将从Remix中获取的DMall合约地址,输入双引号之间
            const contract = (await factory.at(
              ""
            )) as any
            const address = await getUserAccount()
            log(address)
        
            const res = await contract.clickAd(
              // 需将从MetaMask中获取的广告发布者账号地址,输入双引号之间
              "",
              0,
              // 需将从MetaMask中获取的土地所有者账号地址,输入双引号之间
              "",
			  {
    
    
				from: address,
			  }
            )
            log(res)
            // 打开外部的商品购买链接
            openExternalURL("https://item.jd.com/10045659650093.html")
        },
        {
    
    
          button: ActionButton.PRIMARY,
          hoverText: locationString,
        }
      )
    )

次に、検証のためにスマート アイテムをビルダーにアップロードし、次のように使用できます。

  • Node.jsをインストールする
  • ディセントラランドをインストールする
npm install -g decentraland
  • 対応するスマート アイテムのソース コード フォルダーに移動し、対話型検証のためにローカルで起動します。
dcl install
dcl start
  • パッケージ化して Builder にアップロードして使用することもできます
dcl pack

おすすめ

転載: blog.csdn.net/cloudguru/article/details/127121638