avatar of 发明者量化-小小梦 发明者量化-小小梦
フォロー ダイレクトメッセージ
4
フォロー
1271
フォロワー

FMZを使用してEthereumベースのWeb3開発を簡単に開始する

作成日:: 2023-03-28 13:32:48, 更新日:: 2024-11-11 22:28:24
comments   0
hits   3837

[TOC]

FMZを使用してEthereumベースのWeb3開発を簡単に開始する

EtherEaseWithFMZ チュートリアル

FMZを使用してEthereumベースのWeb3開発を簡単に開始する

Ethereum は、ブロックチェーン テクノロジーに基づくスマート コントラクト プラットフォームであり、スマート コントラクトを分散的に作成および展開する方法を提供します。スマートコントラクトは、ブロックチェーン上で自動的に実行され、第三者を信頼することなくさまざまなビジネスロジックを実装できる特別なコンピュータプログラムです。

Inventor Quantitative Trading Platform (FMZ.COM) は、開発者が Ethereum ブロックチェーンとそのエコシステムと簡単にやり取りできるようにする、使いやすい API を提供します。分散型取引所(DEX)へのアクセス、オンチェーンデータの取得、トランザクションの送信などの機能を実現します。

このチュートリアルの例では、JavaScript言語記述、テスト環境の使用イーサリアム メインネットGoerli テストネット。チュートリアルで使用されている API インターフェースや、関連する説明、コード例を FMZ プラットフォームの API ドキュメントで確認することもできます。


FMZを使い始める

FMZ 定量取引プラットフォームの使い方を学ぶ前に、いくつかの基本的な概念を理解しておく必要があります。

1. FMZ定量取引プラットフォームのアーキテクチャ

FMZ定量取引プラットフォームの公式サイト(https://www.fmz.com)に登録してログインすると、プラットフォームのさまざまな機能を使用できます。 FMZ ウェブサイトはシステム全体の管理側であり、ユーザーが作成したプログラムは実際にホスト上で実行されます。ホストは、サーバー、コンピューターなどのさまざまなデバイスに展開できるソフトウェア プログラムです。ユーザーがプログラムを作成し、FMZ Web サイトで実行インスタンスを作成すると、FMZ プラットフォームはホストと通信し、ホスト上でプログラム インスタンスを開始します。

FMZを使用してEthereumベースのWeb3開発を簡単に開始する

2. ホスト

プログラムインスタンスを実行する場合は、ホストをデプロイする必要があります。ホストのデプロイも非常に簡単で、プラットフォーム上にデプロイチュートリアルがあります。 FMZ で提供される「ワンクリック展開ホスト」を使用して、FMZ がレンタルしたサーバーを使用して自動的に展開することもできます。

  • 個人用デバイスにホストを展開する

カストディアン プログラムは、ネットワークが正常である限り、サーバー、パソコン、その他のデバイスに展開して実行できます (交換インターフェイス、ノード アドレスなど、対応するターゲットにアクセスできる必要があります)。展開の主な手順は次のとおりです。

  1. ホストプログラムを展開するデバイスにログインするか開きます。サーバーにログインするまたはコンピュータの電源を入れ、オペレーティングシステムを起動します
  2. ホストプログラムの対応するバージョンをダウンロードします(デバイスのオペレーティングシステムによって異なります)。ダウンロードページ: https://www.fmz.com/m/add-node FMZを使用してEthereumベースのWeb3開発を簡単に開始する
  3. ダウンロードしたファイルは圧縮パッケージなので、解凍する必要があります。
  4. ホストプログラムを実行します。ホストプログラムは、robot実行可能ファイル。管理者の通信アドレスを設定します。この通信アドレスは各FMZアカウントに固有のものです。FMZにログイン後、https://www.fmz.com/m/add-nodeページは独自のアドレスを表示できます (つまり、./robot -s node.fmz.com/xxxxxこの一連のアドレスは、xxxxx場所の内容は FMZ アカウントごとに異なって表示されます。最後に、FMZ アカウントのパスワードを入力する必要があります。これらを設定したら、ホスト プログラムを実行します。
  • FMZプラットフォームの「ワンクリック管理者の導入」機能を使用する

FMZ プラットフォームに管理者ページを追加します。アドレス:https://www.fmz.com/m/add-node

FMZを使用してEthereumベースのWeb3開発を簡単に開始する

3. デバッグツール

FMZ定量取引プラットフォームは、以下の機能をサポートする無料のデバッグツールを提供しています。JavaScriptTypeScriptインスタンスの作成と実行には料金が発生するため、ページは https://www.fmz.com/m/debug です。このデバッグ ツールは、初期学習期間中のテストと学習に使用できます。デバッグ ツールは、実行時間が 3 分に制限されることを除いて、インスタンスの作成と変わりません。

使用TypeScript言語を使用する場合は、コードの最初の行に記述する必要があります// @ts-check切り替えるにはTypeScriptモード、切り替えない場合のデフォルトはJavaScript言語。

4. 交換

FMZ では、「取引所」は一般的な概念です。CEX 取引所の場合、特定の取引所アカウント構成を指します。 Web3 の場合、この交換はノード アドレスや秘密鍵の構成などの構成情報を指します。

FMZプラットフォームにログインすると、https://www.fmz.com/m/add-platformこのページでは、交換情報を設定することができます。ここでの交換は一般的な概念です。

FMZを使用してEthereumベースのWeb3開発を簡単に開始する

選ぶWeb3、RPC ノード アドレスと秘密キーを設定します。右下隅の「機密情報は独立した秘密キーを使用して暗号化され、保存されます」をクリックすると、セキュリティ メカニズムが表示されます。

ノードは自分で構築することも、ノード サービス プロバイダーによって提供されることもできます。次のような多くのノード サービス プロバイダーが存在します。Infura。登録後、アカウントのノードアドレスを表示できます。メインネットとテストネットの両方があり、どちらが便利です。このノードアドレスを上図のように設定します。Rpc Addressコントロールで。構成された交換オブジェクトを区別するために、タグに独自の名前を付けることができます。

FMZを使用してEthereumベースのWeb3開発を簡単に開始する

図ではhttps://mainnet.infura.io/v3/xxxxxxxxxxxxxこれは、Infura ETH メインネット RPC ノードのプライベート アドレスです。


FMZを使用してEthereumとやりとりする

カストディアン プログラムを展開し、交換オブジェクトを構成した後、FMZ.COM の「デバッグ ツール」を使用してテストを行うことができます。 Ethereumとやりとりするには、Ethereum RPCメソッドを呼び出します。この章でリストされているいくつかのRPCメソッドに加えて、次のような他のRPCメソッドのドキュメントを参照することもできます。https://www.quicknode.com/docs

いくつかの簡単な例を取り上げ、基本から始めましょう。図に示すように、さまざまな言語やツールで web3 にアクセスする方法があります。

FMZを使用してEthereumベースのWeb3開発を簡単に開始する

RPCメソッド呼び出しもFMZでカプセル化されます。これらの関数はFMZ API関数にカプセル化されています。exchange.IO真ん中。呼び出し方法はexchange.IO("api", "eth", ...)。最初のパラメータは固定です。"api"2番目のパラメータは固定です"eth"その他のパラメータは、呼び出される特定の RPC メソッドによって異なります。

情報の出力にはFMZプラットフォームを使用しますLog関数、Logこの関数は複数のパラメータを渡し、FMZ プラットフォームの「デバッグ ツール」または「リアル トレーディング」ページのログ領域に出力することができます。「デバッグ ツール」ページは、テストの主なツールになります。

eth_getBalance

イーサリアムeth_getBalanceこのメソッドは、Ethereum 上のアドレスの ETH 残高を照会するために使用されます。このメソッドでは、2 つのパラメータを渡す必要があります。

  • 照会するアドレス。
  • タグ、通常は「最新」。

イーサリアムの創始者を見てみましょうV神ETH ウォレット アドレス、既知のアドレスは次のとおりです:0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045

function main() {
    let ethBalance = exchange.IO("api", "eth", "eth_getBalance", "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", "latest")
    Log("ethBalance:", ethBalance)
}

カストディアンはデプロイされており (図では linux/amd64 …)、交換オブジェクトは構成されています (図では Web3 テスト)。デバッグ ツールでコードをテストします。

FMZを使用してEthereumベースのWeb3開発を簡単に開始する

「実行」ボタンをクリックしてこのコードを実行し、結果を表示します。

ethBalance: 0x117296558f185bbc4c6

Logこの関数は次のように出力しますethBalance変数値は次のとおりです。0x117296558f185bbc4c6、これは文字列型です。はいETH残高(16進数値)、によるweiユニットとして、1e18 wei1ですETH。したがって、読み取り可能な小数点の ETH 残高に変換する必要があります。

意思ethBalance読み取り可能なデータに変換します:

function main() {
    let ethBalance = exchange.IO("api", "eth", "eth_getBalance", "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", "latest")
    Log("ethBalance:", ethBalance)
    
    // 将ethBalance转换为可读的数据
    let vitalikEthBalance = parseInt(ethBalance.substring(2), 16) / 1e18
    Log("vitalikEthBalance:", vitalikEthBalance)
}

FMZを使用してEthereumベースのWeb3開発を簡単に開始する

上にhttps://etherscan.io/クエリ:

FMZを使用してEthereumベースのWeb3開発を簡単に開始する

ただし、この処理は言語自体の精度によって偏差が生じるため、FMZ プラットフォームにはデータを処理するための 2 つの組み込み関数があります。

  • BigInt: 16 進文字列を BigInt オブジェクトに変換します。
  • BigDecimal: 数値型オブジェクトを操作可能な BigDecimal オブジェクトに変換します。

コードを再度調整します。

function main() {
    let ethBalance = exchange.IO("api", "eth", "eth_getBalance", "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", "latest")

    // ETH的精度单位为1e18
    let ethDecimal = 18
    Log("vitalikEthBalance:", Number((BigDecimal(BigInt(ethBalance)) / BigDecimal(Math.pow(10, ethDecimal))).toString()))
}

vitalikEthBalance: 5149.6244846875215

eth_chainId

eth_chainIdそしてnet_version用途が似ているので、一緒にテストしました。どちらの関数も、現在のRPCノードが接続されているブロックチェーンのIDを返します。違いはnet_version10 進数の ID を返します。eth_chainId16 進数の ID を返します。

チェーンIDに対応するネットワーク名

1 - ethereum mainnet
2 - morden testnet (deprecated)
3 - ropsten testnet
4 - rinkeby testnet
5 - goerli testnet
11155111 - sepolia testnet
10 - optimism mainnet
69 - optimism kovan testnet
42 - kovan testnet
137 - matic/polygon mainnet
80001 - matic/polygon mumbai testnet
250 - fantom mainnet
100 - xdai mainnet
56 - bsc mainnet

FMZを使用してEthereumベースのWeb3開発を簡単に開始する

設定されたEthereumテストネットワークを使用するgoerliノードテスト:

function main() {
    let netVersionId = exchange.IO("api", "eth", "net_version")
    let ethChainId = exchange.IO("api", "eth", "eth_chainId")

    Log("netVersionId:", netVersionId)
    Log("ethChainId:", ethChainId, " ,转换:", parseInt(ethChainId.substring(2), 16))
}

FMZを使用してEthereumベースのWeb3開発を簡単に開始する

eth_gasPrice

電話eth_gasPrice現在のチェーンを照会するメソッドgas price

function toAmount(s, decimals) {
    return Number((BigDecimal(BigInt(s)) / BigDecimal(Math.pow(10, decimals))).toString())
}

function main() {
    let gasPrice = exchange.IO("api", "eth", "eth_gasPrice")
    Log("gasPrice:", gasPrice, " ,转换:", toAmount(gasPrice, 0))
}

ここでは、16 進文字列を読み取り可能な値に変換する関数を記述します。toAmount。もう一つ注目すべき点は、ガス価格の単位がweiなので、パラメータdecimals対応する実パラメータは 0 として渡すことができます。

eth_blockNumbe

eth_blockNumbeブロックの高さを照会するために使用されます。

function toAmount(s, decimals) {
    return Number((BigDecimal(BigInt(s)) / BigDecimal(Math.pow(10, decimals))).toString())
}

function main() {
    let blockNumber = exchange.IO("api", "eth", "eth_blockNumber")
    Log(toAmount(blockNumber, 0))
}

デバッガーで実行します:

FMZを使用してEthereumベースのWeb3開発を簡単に開始する

https://etherscan.io/クエリについて:

FMZを使用してEthereumベースのWeb3開発を簡単に開始する

eth_getBlockByNumber

ブロック情報を照会します。

function main() {
    let blockNumber = exchange.IO("api", "eth", "eth_blockNumber")    
    Log(blockNumber)
    let blockMsg = exchange.IO("api", "eth", "eth_getBlockByNumber", blockNumber, true)
    Log(typeof(blockMsg), blockMsg)
    
    // 由于Log输出的内容过多,会自动截断,所以遍历返回的区块信息各个字段,逐个打印
    for (let key in blockMsg) {
        Log("key:", key, ", val:", blockMsg[key])
    }
}

「デバッグ ツール」で実行すると、次の情報を取得できます。

FMZを使用してEthereumベースのWeb3開発を簡単に開始する


契約情報を読む

Ethereum 上で実行されるスマート コントラクト アプリケーションは多数あります。ENSもその一つです。ENS、つまり Ethereum Name Service は、Ethereum ブロックチェーンに基づく分散型ドメイン名解決サービスです。 チュートリアルで、Ethereum の創設者 Vitalik Buterin のウォレット残高を照会した例を覚えていますか? Vitalik のウォレット アドレスの 1 つは次のとおりです。0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045。それで、この住所はどうやってわかるのでしょうか?実際、ENS直感的な名前を使用したスマートコントラクトvitalik.eth(vitalik は Vitalik の名前です) クエリを実行します。

この章の以下の内容では、Ethereum メイン ネットワーク環境を使用します。ENS文書によると、照会するイーサリアムドメイン名はHashing Names、次のコードを使用してvitalik.eth名前が処理されました。

function nameHash(name) {
    if (name == "") {
        return "0000000000000000000000000000000000000000000000000000000000000000"
    } else {
        let arr = name.split(".")
        let label = arr[0]
        
        arr.shift()
        let remainder = arr.join(".")
        return Encode("sha3.keccak256", "hex", "hex", nameHash(remainder) + Encode("sha3.keccak256", "raw", "hex", label))
    }
}

上記のコード例では、もう一つの見慣れない関数が見られます。Encodeこの関数は、FMZ プラットフォームの API 関数であり、特に FMZ プラットフォームでエンコード操作を実行するために使用されます。この関数は、複数のエンコード方式と複数のハッシュ アルゴリズムをサポートします。

Encode(algo, inputFormat, outputFormat, data, keyFormat, key string)

ENSのドキュメントによると、sha3.keccak256アルゴリズムはデータを処理します。

電話nameHash関数の例:Log(nameHash("vitalik.eth"))すると、次のようになります:ee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835、プレフィックス「0x」を追加する必要があります。0xee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835ENSスマートコントラクトとしてresolverメソッドのパラメータ。

let ensNode = "0x" + nameHash("vitalik.eth")    // 准备好调用resolver方法的参数ensNode

ENS ドキュメントによると、ENS スマート コントラクト アプリケーションのコントラクト アドレスは次のとおりです。0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e。スマートコントラクトを呼び出す際にresolver先に進む前に契約書を準備する必要がありますABI

ABIの登録

これを学んだ後、私は思わず「スマート コントラクトとは何ですか?」と尋ねてしまいます。ABIウールの布?

ABI,即应用程序二进制接口(Application Binary Interface),是智能合约与外部世界进行通信的接口标准。
智能合约的 ABI 定义了合约的函数接口、参数类型、返回值等信息,以及调用合约的方式和参数传递方式等规范。

智能合约的 ABI 通常以 JSON 格式存储,包含以下信息:

合约的函数接口:函数名、参数列表、返回值等信息。
函数参数类型:如 uint256、bool、string 等。
函数的输入参数和输出参数的编码方式:智能合约使用一种称为 Solidity ABI 的编码方式来编码函数的输入参数和输出参数,
以便与以太坊网络进行交互。
在以太坊网络中,使用智能合约的 ABI 来调用合约的函数。当需要调用合约函数时,需要提供函数名和函数参数,以及将函数参数按照 ABI 编码方式编码后的字节码。
以太坊节点会将这些信息打包成一笔交易,并将交易发送到以太坊网络中执行。

智能合约的 ABI 在 Solidity 语言中可以通过 interface 关键字来定义。以太坊开发工具如 Remix IDE、Truffle 等也提供了 ABI 编辑和生成工具,
使得开发者可以方便地创建和使用智能合约的 ABI。

ENS ABI から次の内容を抽出します。resolver完全なABIは、https://etherscan.io/GitHub でコントラクトの ABI を照会したり、他の手段 (関連するプロジェクト ドキュメントなど) を通じて ABI を取得したりできます。

FMZを使用してEthereumベースのWeb3開発を簡単に開始する

let abiENS_resolver = `[{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"resolver","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"}]`

ここでは、FMZ プラットフォームでの新しい呼び出し方法を学習する必要があります。exchange.IO("abi", address, abiContent)この方法を使用してABIを登録します。addressパラメータはスマート コントラクトのアドレスです。abiContentパラメータは対応するスマート コントラクト ABI (文字列) です。

let abiENS_resolver = `[{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"resolver","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"}]`
exchange.IO("abi", "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e", abiENS_resolver)  // 0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e 是在以太坊主网上部署的ENS智能合约的地址

スマートコントラクトメソッドの呼び出し

次にENSスマートコントラクトを呼び出すことができますresolverメソッドは、ENS: Public Resolver契約の住所。

FMZを使用してEthereumベースのWeb3開発を簡単に開始する

let resolverAddress = exchange.IO("api", "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e", "resolver", ensNode)

使用ENS: Public Resolver契約上のaddrVitalikのウォレットアドレスを取得する方法。電話をかけるENS: Public Resolver契約ではまず ABI を登録する必要があります。このスマートコントラクトのABI情報は、https://etherscan.io/得る。

let abiENSPublicResolver = `[{"inputs":[{"internalType":"contract ENS","name":"_ens","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"contentType","type":"uint256"}],"name":"ABIChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"address","name":"a","type":"address"}],"name":"AddrChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"coinType","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"newAddress","type":"bytes"}],"name":"AddressChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"bool","name":"isAuthorised","type":"bool"}],"name":"AuthorisationChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"hash","type":"bytes"}],"name":"ContenthashChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"name","type":"bytes"},{"indexed":false,"internalType":"uint16","name":"resource","type":"uint16"},{"indexed":false,"internalType":"bytes","name":"record","type":"bytes"}],"name":"DNSRecordChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"name","type":"bytes"},{"indexed":false,"internalType":"uint16","name":"resource","type":"uint16"}],"name":"DNSRecordDeleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"DNSZoneCleared","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":true,"internalType":"bytes4","name":"interfaceID","type":"bytes4"},{"indexed":false,"internalType":"address","name":"implementer","type":"address"}],"name":"InterfaceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"string","name":"name","type":"string"}],"name":"NameChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"x","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"y","type":"bytes32"}],"name":"PubkeyChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":true,"internalType":"string","name":"indexedKey","type":"string"},{"indexed":false,"internalType":"string","name":"key","type":"string"}],"name":"TextChanged","type":"event"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"uint256","name":"contentTypes","type":"uint256"}],"name":"ABI","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"addr","outputs":[{"internalType":"address payable","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"uint256","name":"coinType","type":"uint256"}],"name":"addr","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"authorisations","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"clearDNSZone","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"contenthash","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes32","name":"name","type":"bytes32"},{"internalType":"uint16","name":"resource","type":"uint16"}],"name":"dnsRecord","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes32","name":"name","type":"bytes32"}],"name":"hasDNSRecords","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes4","name":"interfaceID","type":"bytes4"}],"name":"interfaceImplementer","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"pubkey","outputs":[{"internalType":"bytes32","name":"x","type":"bytes32"},{"internalType":"bytes32","name":"y","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"uint256","name":"contentType","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"setABI","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"uint256","name":"coinType","type":"uint256"},{"internalType":"bytes","name":"a","type":"bytes"}],"name":"setAddr","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"address","name":"a","type":"address"}],"name":"setAddr","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"address","name":"target","type":"address"},{"internalType":"bool","name":"isAuthorised","type":"bool"}],"name":"setAuthorisation","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes","name":"hash","type":"bytes"}],"name":"setContenthash","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"setDNSRecords","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes4","name":"interfaceID","type":"bytes4"},{"internalType":"address","name":"implementer","type":"address"}],"name":"setInterface","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"string","name":"name","type":"string"}],"name":"setName","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes32","name":"x","type":"bytes32"},{"internalType":"bytes32","name":"y","type":"bytes32"}],"name":"setPubkey","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"string","name":"key","type":"string"},{"internalType":"string","name":"value","type":"string"}],"name":"setText","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes4","name":"interfaceID","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"string","name":"key","type":"string"}],"name":"text","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"}]`
exchange.IO("abi", resolverAddress, abiENSPublicResolver)

FMZを使用してEthereumベースのWeb3開発を簡単に開始する

ラストコールENS: Public Resolver契約上のaddrメソッド、パラメータはまだensNode

let vitalikAddress = exchange.IO("api", resolverAddress, "addr", ensNode)
Log("vitalikAddress:", vitalikAddress)

ログ関数の出力:

FMZを使用してEthereumベースのWeb3開発を簡単に開始する

vitalikAddress: 0xd8da6bf26964af9d7eed9e03e53415d37aa96045

ENSを呼び出すための完全なコード

function nameHash(name) {
    if (name == "") {
        return "0000000000000000000000000000000000000000000000000000000000000000"
    } else {
        let arr = name.split(".")
        let label = arr[0]
        
        arr.shift()
        let remainder = arr.join(".")
        return Encode("sha3.keccak256", "hex", "hex", nameHash(remainder) + Encode("sha3.keccak256", "raw", "hex", label))
    }
}

function main() {
    // 计算名称
    let ensNode = "0x" + nameHash("vitalik.eth")

    // 注册ENS合约
    let abiENS_resolver = `[{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"resolver","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"}]`
    exchange.IO("abi", "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e", abiENS_resolver)
    let resolverAddress = exchange.IO("api", "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e", "resolver", ensNode)
    
    // 注册ENS Public Resolver合约
    let abiENSPublicResolver = `[{"inputs":[{"internalType":"contract ENS","name":"_ens","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"contentType","type":"uint256"}],"name":"ABIChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"address","name":"a","type":"address"}],"name":"AddrChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"coinType","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"newAddress","type":"bytes"}],"name":"AddressChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"bool","name":"isAuthorised","type":"bool"}],"name":"AuthorisationChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"hash","type":"bytes"}],"name":"ContenthashChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"name","type":"bytes"},{"indexed":false,"internalType":"uint16","name":"resource","type":"uint16"},{"indexed":false,"internalType":"bytes","name":"record","type":"bytes"}],"name":"DNSRecordChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"name","type":"bytes"},{"indexed":false,"internalType":"uint16","name":"resource","type":"uint16"}],"name":"DNSRecordDeleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"DNSZoneCleared","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":true,"internalType":"bytes4","name":"interfaceID","type":"bytes4"},{"indexed":false,"internalType":"address","name":"implementer","type":"address"}],"name":"InterfaceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"string","name":"name","type":"string"}],"name":"NameChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"x","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"y","type":"bytes32"}],"name":"PubkeyChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":true,"internalType":"string","name":"indexedKey","type":"string"},{"indexed":false,"internalType":"string","name":"key","type":"string"}],"name":"TextChanged","type":"event"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"uint256","name":"contentTypes","type":"uint256"}],"name":"ABI","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"addr","outputs":[{"internalType":"address payable","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"uint256","name":"coinType","type":"uint256"}],"name":"addr","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"authorisations","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"clearDNSZone","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"contenthash","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes32","name":"name","type":"bytes32"},{"internalType":"uint16","name":"resource","type":"uint16"}],"name":"dnsRecord","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes32","name":"name","type":"bytes32"}],"name":"hasDNSRecords","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes4","name":"interfaceID","type":"bytes4"}],"name":"interfaceImplementer","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"pubkey","outputs":[{"internalType":"bytes32","name":"x","type":"bytes32"},{"internalType":"bytes32","name":"y","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"uint256","name":"contentType","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"setABI","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"uint256","name":"coinType","type":"uint256"},{"internalType":"bytes","name":"a","type":"bytes"}],"name":"setAddr","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"address","name":"a","type":"address"}],"name":"setAddr","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"address","name":"target","type":"address"},{"internalType":"bool","name":"isAuthorised","type":"bool"}],"name":"setAuthorisation","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes","name":"hash","type":"bytes"}],"name":"setContenthash","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"setDNSRecords","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes4","name":"interfaceID","type":"bytes4"},{"internalType":"address","name":"implementer","type":"address"}],"name":"setInterface","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"string","name":"name","type":"string"}],"name":"setName","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes32","name":"x","type":"bytes32"},{"internalType":"bytes32","name":"y","type":"bytes32"}],"name":"setPubkey","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"string","name":"key","type":"string"},{"internalType":"string","name":"value","type":"string"}],"name":"setText","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes4","name":"interfaceID","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"string","name":"key","type":"string"}],"name":"text","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"}]`
    exchange.IO("abi", resolverAddress, abiENSPublicResolver)
    let vitalikAddress = exchange.IO("api", resolverAddress, "addr", ensNode)
    Log("vitalikAddress:", vitalikAddress)
}

ETHを送信

前のコースの章では、秘密鍵の設定方法を学習しました。設定された交換オブジェクトの場合、この秘密鍵に対応するウォレット アドレスをどのように知るのでしょうか。 FMZで利用可能exchange.IO("address")この関数は、設定された秘密鍵に対応するウォレット アドレスを取得します。

この章の以下の内容はGoerliテストネットワーク環境なので、使用するノードは次のとおりです。https://goerli.infura.io/v3/*******Infura は登録ユーザーごとに異なるノード アドレスを割り当てます。*******具体的な内容は非表示になっています。

function main() {
    let walletAddress = exchange.IO("address")
    Log("测试网 goerli 钱包地址:", walletAddress)
}

FMZを使用してEthereumベースのWeb3開発を簡単に開始する

ウォレットアドレスがわかれば、イーサリアムのRPCメソッドを使用することができます。eth_getTransactionCountウォレット アドレスのトランザクション数を照会します。このカウントは Ethereum で非常によく使用されます。実際、これは送金時に渡す必要があるものです。nonceパラメータ、Ethereum では、nonce は各トランザクションが一意であることを保証するために使用される数値です。これは、新しいトランザクションが送信されるたびに自動的に増加する数値です。したがって、スマート コントラクトにトランザクションを送信するときは、トランザクションが一意であり、正しい順序であることを確認するために nonce を提供する必要があります。いくつかのデータと文書では、次のことがわかります。

https://goethereumbook.org/en/

FMZを使用してEthereumベースのWeb3開発を簡単に開始する

Go言語のEthereumライブラリはこちらPendingNonceAt関数は実際にeth_getTransactionCount方法。前回のコースでは、RPC メソッドを呼び出す方法も学習しました。ここでもそれを再度使用します。exchange.IO("api", "eth", ...)関数。

function toAmount(s, decimals) {
    return Number((BigDecimal(BigInt(s)) / BigDecimal(Math.pow(10, decimals))).toString())
}

function main() {
    let walletAddress = exchange.IO("address")
    Log("测试网 goerli 钱包地址:", walletAddress)

    /**
    * eth_getTransactionCount
    * @param address - string - The address from which the transaction count to be checked.
    * @param blockNumber - string - The block number as a string in hexadecimal format or tags.
    * @returns The integer of the number of transactions sent from an address encoded as hexadecimal.
    */
    let nonce = exchange.IO("api", "eth", "eth_getTransactionCount", walletAddress, "pending")
    Log("钱包地址:", walletAddress, "当前的 nonce:", nonce, ",转换为10进制:", toAmount(nonce, 0))
}

送金操作を説明する前に、いくつかの概念を簡単に理解しておきましょう。Ethereum で送金する場合、一定量の ETH トークンが消費されます (ガス料金として)。ガス料金は 2 つのパラメータによって決まります。

  • gasPrice

ただし、Ethereum ネットワークのガス料金は市場の需要とユーザーが支払う意思のある金額に基づいて常に変動するため、コードに固定のガス料金を書き込むことは理想的ではない場合があります。以前学んだことを活用できるeth_gasPrice平均ガス価格を取得できる方法。

  • gasLimit

標準的なイーサ転送のガス制限は 21,000 ユニットです。

わかったnoncegasPricegasLimitこれらの概念を使用して、転送をテストできます。非常にシンプルで使いやすい転送関数が FMZ にカプセル化されています。

exchange.IO("api", "eth", "send", toAddress, toAmount)

転送に使用する場合、exchange.IO3 番目のパラメータは常に「send」です。toAddressパラメータは転送中に ETH を受信するアドレスです。toAmount転送された ETH の量。

noncegasPricegasLimitこれらのパラメータは、FMZ ではデフォルトでシステムによって自動的に取得される値を使用できます。以下も指定できます:

exchange.IO("api", "eth", "send", toAddress, toAmount, {gasPrice: 5000000000, gasLimit: 21000, nonce: 100})

次に、一定量の ETH をテスト ネットワーク goerli 上の特定のアドレスに転送します。

function toInnerAmount(s, decimals) {
    return (BigDecimal(s)*BigDecimal(Math.pow(10, decimals))).toFixed(0)
}

function main() {
    let walletAddress = exchange.IO("address")
    Log("测试网 goerli 钱包地址:", walletAddress)

    let ret = exchange.IO("api", "eth", "send", "0x4D75a08E870674E68cAE611f329A27f446A66813", toInnerAmount(0.01, 18))
    return ret    // 返回Transaction Hash : 0xa6f9f51b00d8ae850b0f204380b59da98f4bbce34b813577d3d948f61de4734e
}

イーサリアムの送金金額の単位はwei、カスタム関数を使用する必要がありますtoInnerAmount処理方法weiユニットの値。

存在するhttps://etherscan.io/クエリトランザクションハッシュ:0xa6f9f51b00d8ae850b0f204380b59da98f4bbce34b813577d3d948f61de4734e

FMZを使用してEthereumベースのWeb3開発を簡単に開始する

転送ハッシュを照会するコードを書くこともできる0xa6f9f51b00d8ae850b0f204380b59da98f4bbce34b813577d3d948f61de4734e、使用eth_getTransactionReceiptクエリを実行するメソッド。

function main() {
    let transHash = "0xa6f9f51b00d8ae850b0f204380b59da98f4bbce34b813577d3d948f61de4734e"
    let info = exchange.IO("api", "eth", "eth_getTransactionReceipt", transHash)
    return info
}

クエリ結果:

{
	"cumulativeGasUsed": "0x200850",
	"effectiveGasPrice": "0x1748774421",
	"transactionHash": "0xa6f9f51b00d8ae850b0f204380b59da98f4bbce34b813577d3d948f61de4734e",
	"type": "0x0",
	"blockHash": "0x6bdde8b0f0453ecd24eecf7c634d65306f05511e0e8f09f9ed3f59eee2d06ac7",
	"contractAddress": null,
	"blockNumber": "0x868a50",
	"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
	"gasUsed": "0x5208",
	"to": "0x4d75a08e870674e68cae611f329a27f446a66813",
	"status": "0x1",
	"transactionIndex": "0x23",
	"from": "0x6b3f11d807809b0b1e5e3243df04a280d9f94bf4",
	"logs": []
}

各フィールドの説明:

”`desc blockHash - 该交易所在区块的哈希值 blockNumber - 以十六进制编码的该交易所在区块的块号 contractAddress - 如果是合约创建,该合约的地址;否则为null cumulativeGasUsed - 该交易在区块中执行时使用的总燃气量 effectiveGasPrice - 每单位燃气的总基础费用加小费 from - 发送者的地址 gasUsed - 该特定交易使用的燃气量 logs - 生成该交易的日志对象数组 address - 生成该日志的地址 topics - 0到4个32字节索引日志参数的数据数组。在Solidity中,第一个主题是事件签名的哈希值(例如Deposit(address,bytes32,uint256)),除非你使用匿名说明符声明该事件 data - 日志的32字节非索引参数 blockNumber - 该日志所在区块的块号 transactionHash - 该日志创建时的交易哈希值。如果该日志处于待定状态,则为null transactionIndex - 该日志创建时的交易索引位置。如果该日志处于待定状态,则为null blockHash - 该日志所在区块�