Type/to search
8
Follow
1364
Followers
FMZを使用してEthereumベースのWeb3開発を簡単に開始する
Original
Created 2023-03-28 13:32:48  Updated 2024-11-11 22:28:24
 0
 4375

img

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 プラットフォームはホストと通信し、ホスト上でプログラム インスタンスを開始します。

img

2. ホスト

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

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

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

    1. ホストプログラムを展開するデバイスにログインするか開きます。サーバーにログインするまたはコンピュータの電源を入れ、オペレーティングシステムを起動します
    2. ホストプログラムの対応するバージョンをダウンロードします(デバイスのオペレーティングシステムによって異なります)。ダウンロードページ: https://www.fmz.com/m/add-node
      img
    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

    img

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このページでは、交換情報を設定することができます。ここでの交換は一般的な概念です。

img

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

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

img

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


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

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

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

img

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

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

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

img

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

ethBalance: 0x117296558f185bbc4c6

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

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

javascript
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) }

img

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

img

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

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

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

javascript
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に対応するネットワーク名

desc
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

img

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

javascript
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)) }

img

eth_gasPrice

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

javascript
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ブロックの高さを照会するために使用されます。

javascript
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)) }

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

img

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

img

eth_getBlockByNumber

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

javascript
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]) } }

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

img


契約情報を読む

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

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

javascript
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メソッドのパラメータ。

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

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

ABIの登録

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

desc
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 を取得したりできます。

img

javascript
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 (文字列) です。

javascript
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契約の住所。

img

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

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

javascript
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)

img

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

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

ログ関数の出力:

img

run
vitalikAddress: 0xd8da6bf26964af9d7eed9e03e53415d37aa96045

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

javascript
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 は登録ユーザーごとに異なるノード アドレスを割り当てます。*******具体的な内容は非表示になっています。

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

img

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

https://goethereumbook.org/en/

img

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

javascript
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 にカプセル化されています。

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

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

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

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

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

javascript
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

img

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

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

クエリ結果:

run
{ "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 - 该日志所在区块的哈希值 logIndex - 该日志在区块中的索引位置,以十六进制编码的整数。如果该日志处于待定状态,则为null removed - 如果该日志已被删除,则为true,由于链重组而被删除;如果是有效的日志,则为false logsBloom - 用于检索相关日志的布隆过滤器 status - 以十六进制编码的值,它要么是1(成功),要么是0(失败) to - 接收者的地址。如果是合约创建交易,则为null transactionHash - 该交易的哈希值 transactionIndex - 以十六进制编码的该交易在区块中的索引位置 type - 值的类型

Ethereumスマートコントラクトの呼び出し

私たちは契約情報を読むこのセクションでは、完全な例を使用して、Ethereum にデプロイされた ENS コントラクト メソッドを呼び出して、Vitalik のウォレット アドレスを取得します。これらの方法は、Readメソッド、これらのメソッドを呼び出す必要はありませんgas(以前ガスについて話したことを覚えていますか?)このセクションでは、イーサリアム上のいくつかのスマートコントラクトを呼び出します。Write方法と支払いgas。これらの操作は、ネットワーク全体のすべてのノードとマイナーによって検証され、ブロックチェーンの状態を変更します。

ERC20

ERC20 コントラクト(ERC20 トークン コントラクト)の場合、FMZ プラットフォームは ERC20 コントラクトの ABI を一般的に使用される ABI としてリストし、システムに直接組み込むため、ABI を登録する手順が不要になります。前回のチュートリアルでも ABI について学習しました。ENS コントラクト メソッドを呼び出すときは、まず ENS コントラクトの ABI を登録します。

ABI をより明確に理解するために、使用前に確認することができます。以下は ERC20 コントラクトの ABI です。

javascript
[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"guy","type":"address"},{"name":"wad","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"src","type":"address"},{"name":"dst","type":"address"},{"name":"wad","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"wad","type":"uint256"}],"name":"withdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"dst","type":"address"},{"name":"wad","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"deposit","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"src","type":"address"},{"indexed":true,"name":"guy","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"src","type":"address"},{"indexed":true,"name":"dst","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"dst","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"src","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Withdrawal","type":"event"}]

この章では以下の内容が使用されていますGoerliテストネット環境。

balanceOf

次に、契約の呼び方をもう一度練習してみましょう。Readコントラクト情報を読み取り、ERC20コントラクトを呼び出す方法balanceOfトークン残高を照会する方法、balanceOfこのメソッドにはパラメータが 1 つしかありませんが、名前は付けられていません。型から、それがアドレス (つまり、照会されるトークン アドレス) であることがわかります。返されるデータは1トークン単位ではないため、変換にはトークン精度データも必要になります。トークン精度はERC20コントラクトを使用して計算できます。decimalsメソッドの取得。イーサリアムテストネットを使用していますgoerliテストして、トークン コントラクト アドレスがチェーンごとに異なる場合があることに注意してください。

javascript
function toAmount(s, decimals) { return Number((BigDecimal(BigInt(s)) / BigDecimal(Math.pow(10, decimals))).toString()) } function main() { let walletAddress = exchange.IO("address") // goerli WETH address let wethAddress = "0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6" // goerli LINK address let linkAddress = "0x326C977E6efc84E512bB9C30f76E30c160eD06FB" // 由于是ERC20合约,FMZ已经内置ABI注册,所以这里不用注册ERC20 ABI let wethDecimals = exchange.IO("api", wethAddress, "decimals") let linkDecimals = exchange.IO("api", linkAddress, "decimals") let wethBalance = exchange.IO("api", wethAddress, "balanceOf", walletAddress) let linkBalance = exchange.IO("api", linkAddress, "balanceOf", walletAddress) Log("WETH精度:", wethDecimals, "wethBalance:", toAmount(wethBalance, wethDecimals)) Log("LINK精度:", linkDecimals, "linkBalance:", toAmount(linkBalance, linkDecimals)) }

上記のコードを実行すると、現在のウォレット内の WETH および LINK トークンの残高を照会できます。

WETH精度: 18 wethバランス: 0
リンク精度: 18 リンクバランス: 51.41374973681053

deposit

このウォレット内のWETHトークンの残高は0であることがわかります。次に、WETHトークンのERC20スマートコントラクトとのやり取りを続けます。今回はWriteタイプのメソッドを呼び出します。deposit
deposit簡単に言えば、この方法の機能は、一定量の ETH を WETH に変換することです。depositこのメソッドにはパラメーターがありません (ABI を見るとわかります)。また、このメソッドには次の属性があります。payableのためにtrueそのため、入金するETHの金額を指定するには、呼び出し時に転送ETH(payableAmount)金額を設定する必要があります。

スマート コントラクト メソッドを呼び出すときの注意:
呼び出されたメソッドに payable 属性がある場合は、メソッド名 (exchange.IO 関数の 4 番目のパラメーター) の後に転送 ETH 値を追加する必要があります。この値は数値型または文字列値にすることができます。

javascript
function toAmount(s, decimals) { return Number((BigDecimal(BigInt(s)) / BigDecimal(Math.pow(10, decimals))).toString()) } function toInnerAmount(s, decimals) { return (BigDecimal(s)*BigDecimal(Math.pow(10, decimals))).toFixed(0) } function main() { let walletAddress = exchange.IO("address") // goerli WETH address let wethAddress = "0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6" // 由于是ERC20合约,FMZ已经内置ABI注册,所以这里不用注册ERC20 ABI let wethDecimals = exchange.IO("api", wethAddress, "decimals") let wethBalance = exchange.IO("api", wethAddress, "balanceOf", walletAddress) Log("WETH精度:", wethDecimals, "wethBalance:", toAmount(wethBalance, wethDecimals)) let ethBalance = exchange.IO("api", "eth", "eth_getBalance", walletAddress, "latest") Log("ETH精度:", 18, "ethBalance:", toAmount(ethBalance, 18)) // 调用deposit方法,由于deposit是ERC20标准之外的方法,所以这里要注册这个方法的ABI let abiWETH = `[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"guy","type":"address"},{"name":"wad","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"src","type":"address"},{"name":"dst","type":"address"},{"name":"wad","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"wad","type":"uint256"}],"name":"withdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"dst","type":"address"},{"name":"wad","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"deposit","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"src","type":"address"},{"indexed":true,"name":"guy","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"src","type":"address"},{"indexed":true,"name":"dst","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"dst","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"src","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Withdrawal","type":"event"}]` exchange.IO("abi", wethAddress, abiWETH) let payableAmount = toInnerAmount(0.01, 18) let ret = exchange.IO("api", wethAddress, "deposit", payableAmount) Log("Transaction Hash:", ret) }

WETH精度: 18 wethバランス: 0
ETH精度: 18 ethBalance: 0.14333094664072302
Transaction Hash: 0xaf15b0b0e25a81eda583295e82b249e2d02e4eafebecc906470ccc2c89e23563

img

WETH と ETH の残高を再度照会します。

WETH精度: 18 wethバランス: 0.01
ETH精度: 18 ethBalance: 0.1333309358060905

電話deposit前にWETH0 です、ETH0.14333094664072302、呼び出しdepositWETH0.01、ETH0.1333309358060905です。 0.01が正常に完了したことがわかりますETH置き換えWETH

transfer

ERC20トークンは以下を使用して転送することもできます。transferこのアドレスに送金する方法0x4D75a08E870674E68cAE611f329A27f446A668130.01 WETH トークン。transferこのメソッドには2つのパラメータがあり、最初のパラメータはdst2番目のパラメータは送金先のウォレットアドレスですwad振込金額です。

javascript
function toAmount(s, decimals) { return Number((BigDecimal(BigInt(s)) / BigDecimal(Math.pow(10, decimals))).toString()) } function toInnerAmount(s, decimals) { return (BigDecimal(s)*BigDecimal(Math.pow(10, decimals))).toFixed(0) } function waitMined (tx) { for (var i = 0 ; i < 10 ; i++) { Sleep(5000) let info = exchange.IO("api", "eth", "eth_getTransactionReceipt", tx) if (info && info.gasUsed) { Log(info) return true } Log('Transaction not yet mined', tx) } return false } function main() { let walletAddress = exchange.IO("address") // goerli WETH address let wethAddress = "0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6" // 由于是ERC20合约,FMZ已经内置ABI注册,所以这里不用注册ERC20 ABI let wethDecimals = exchange.IO("api", wethAddress, "decimals") let wethBalance = exchange.IO("api", wethAddress, "balanceOf", walletAddress) Log("WETH精度:", wethDecimals, "wethBalance:", toAmount(wethBalance, wethDecimals)) let dst = "0x4D75a08E870674E68cAE611f329A27f446A66813" let wad = toInnerAmount(0.01, wethDecimals) let tx = exchange.IO("api", wethAddress, "transfer", dst, wad) Log("Transaction Hash:", tx) waitMined(tx) wethBalance = exchange.IO("api", wethAddress, "balanceOf", walletAddress) Log("WETH精度:", wethDecimals, "wethBalance:", toAmount(wethBalance, wethDecimals)) }

img

上記の例ではカスタム関数を使用していますwaitMined実際、私たちはこの機能の機能を知らないわけではありません。覚えておいてくださいeth_getTransactionReceipt方法?この waitMined カスタム関数の機能は、渡されたトランザクション ハッシュの結果を待機することです。

このWETH転送については、興味のある読者はトランザクションハッシュを照会することもできます。0x2fafb62b548a1fffb0f3189429e3c5a4f57ddafb0acbc0678d8b3cf0a2f7c92c詳細を確認するには(これはテストネット goerli 上にあることに注意してください)。

withdraw

今回はWETH交換ETH、使用withdrawパラメータが1つだけのメソッドwad簡単に言えば、どれだけの ETH を交換するかを設定するために使用されます。

javascript
function toAmount(s, decimals) { return Number((BigDecimal(BigInt(s)) / BigDecimal(Math.pow(10, decimals))).toString()) } function toInnerAmount(s, decimals) { return (BigDecimal(s)*BigDecimal(Math.pow(10, decimals))).toFixed(0) } function main() { let walletAddress = exchange.IO("address") // goerli WETH address let wethAddress = "0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6" // 由于是ERC20合约,FMZ已经内置ABI注册,所以这里不用注册ERC20 ABI let wethDecimals = exchange.IO("api", wethAddress, "decimals") let wethBalance = exchange.IO("api", wethAddress, "balanceOf", walletAddress) Log("WETH精度:", wethDecimals, "wethBalance:", toAmount(wethBalance, wethDecimals)) let ethBalance = exchange.IO("api", "eth", "eth_getBalance", walletAddress, "latest") Log("ETH精度:", 18, "ethBalance:", toAmount(ethBalance, 18)) let abiWETH = `[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"guy","type":"address"},{"name":"wad","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"src","type":"address"},{"name":"dst","type":"address"},{"name":"wad","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"wad","type":"uint256"}],"name":"withdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"dst","type":"address"},{"name":"wad","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"deposit","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"src","type":"address"},{"indexed":true,"name":"guy","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"src","type":"address"},{"indexed":true,"name":"dst","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"dst","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"src","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Withdrawal","type":"event"}]` exchange.IO("abi", wethAddress, abiWETH) let wad = toInnerAmount(0.01, 18) let ret = exchange.IO("api", wethAddress, "withdraw", wad) Log("Transaction Hash:", ret) }

Transaction Hash: 0x446423c841451a8d04428a075b556eb5564186b09926da915f5da1c9837d2af4

上記のコードと前のdepositメソッドの例は基本的に同じですが、最後のステップで呼び出されるメソッドが次のように変更されています。withdraw、電話する前に:

WETH精度: 18 wethバランス: 0.01
ETH精度: 18 ethバランス: 0.11322979983231546

再度クエリを実行:

WETH精度: 18 wethバランス: 0
ETH精度: 18 ethBalance: 0.1231207156449464

0.01がWETHスイッチバックETH

Uniswap V3

Uniswap V3これは、暗号通貨の取引と流動性の提供のために、Ethereum ブロックチェーン上に構築された分散型取引プロトコルです。コア コントラクト、プール コントラクト、ファクトリー コントラクト、ルーティング コントラクトなど、一連のスマート コントラクトで構成されています。

使用中Uniswap以下のコントラクトは主に、現在の交換価格を照会し、交換操作を実行するために使用されます。

  • Router(ルーティング契約)
    これはトランザクションを実行するために使用される契約であり、ユーザーはトランザクション パスとパラメータを指定してトランザクション操作を実行できます。
  • Pool(プール契約)
    プール契約はUniswap特定の資産ペアの流動性を保管および管理するために使用される、Ethereum ブロックチェーンの主要コンポーネント。各資産ペアには対応するプール契約があり、流動性プロバイダーによって提供される資金、価格帯、手数料設定などの情報が含まれています。プール契約は、取引の処理、資金プールの状態の計算、および取引の円滑な実行の確保を担当します。
  • Factory(工場契約)
    工場契約は、作成と管理に使用されます。Uniswapプール契約の契約。ユーザーが新しいアセット ペアを作成したい場合は、ファクトリ コントラクトと対話して新しいプール コントラクトをデプロイします。ファクトリー コントラクトは、プール コントラクトの作成と初期化を調整する役割を担い、ユーザーが新しいアセット ペアを動的に作成できるようにします。

これまで学んだことを基に、FMZ 定量取引プラットフォーム戦略コードにスマート コントラクトを登録する方法を確認しましょう。ABIスマート コントラクトの ABI を取得する方法については、以前のコースですでに説明しましたので、ここでは繰り返しません。
3回の登録が必要ですUniswapスマートコントラクトABI例として Ethereum メインネットを使用します。

javascript
var abiRoute = '[{"inputs":[{"internalType":"address","name":"_factoryV2","type":"address"},{"internalType":"address","name":"factoryV3","type":"address"},{"internalType":"address","name":"_positionManager","type":"address"},{"internalType":"address","name":"_WETH9","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"WETH9","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"approveMax","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"approveMaxMinusOne","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"approveZeroThenMax","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"approveZeroThenMaxMinusOne","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"callPositionManager","outputs":[{"internalType":"bytes","name":"result","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"paths","type":"bytes[]"},{"internalType":"uint128[]","name":"amounts","type":"uint128[]"},{"internalType":"uint24","name":"maximumTickDivergence","type":"uint24"},{"internalType":"uint32","name":"secondsAgo","type":"uint32"}],"name":"checkOracleSlippage","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"path","type":"bytes"},{"internalType":"uint24","name":"maximumTickDivergence","type":"uint24"},{"internalType":"uint32","name":"secondsAgo","type":"uint32"}],"name":"checkOracleSlippage","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"path","type":"bytes"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMinimum","type":"uint256"}],"internalType":"struct IV3SwapRouter.ExactInputParams","name":"params","type":"tuple"}],"name":"exactInput","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMinimum","type":"uint256"},{"internalType":"uint160","name":"sqrtPriceLimitX96","type":"uint160"}],"internalType":"struct IV3SwapRouter.ExactInputSingleParams","name":"params","type":"tuple"}],"name":"exactInputSingle","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"path","type":"bytes"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMaximum","type":"uint256"}],"internalType":"struct IV3SwapRouter.ExactOutputParams","name":"params","type":"tuple"}],"name":"exactOutput","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMaximum","type":"uint256"},{"internalType":"uint160","name":"sqrtPriceLimitX96","type":"uint160"}],"internalType":"struct IV3SwapRouter.ExactOutputSingleParams","name":"params","type":"tuple"}],"name":"exactOutputSingle","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"factoryV2","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"getApprovalType","outputs":[{"internalType":"enum IApproveAndCall.ApprovalType","name":"","type":"uint8"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"amount0Min","type":"uint256"},{"internalType":"uint256","name":"amount1Min","type":"uint256"}],"internalType":"struct IApproveAndCall.IncreaseLiquidityParams","name":"params","type":"tuple"}],"name":"increaseLiquidity","outputs":[{"internalType":"bytes","name":"result","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"int24","name":"tickLower","type":"int24"},{"internalType":"int24","name":"tickUpper","type":"int24"},{"internalType":"uint256","name":"amount0Min","type":"uint256"},{"internalType":"uint256","name":"amount1Min","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"internalType":"struct IApproveAndCall.MintParams","name":"params","type":"tuple"}],"name":"mint","outputs":[{"internalType":"bytes","name":"result","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"previousBlockhash","type":"bytes32"},{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"positionManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"pull","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"refundETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"selfPermit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"selfPermitAllowed","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"selfPermitAllowedIfNecessary","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"selfPermitIfNecessary","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"}],"name":"swapExactTokensForTokens","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"}],"name":"swapTokensForExactTokens","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepToken","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountMinimum","type":"uint256"}],"name":"sweepToken","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"uint256","name":"feeBips","type":"uint256"},{"internalType":"address","name":"feeRecipient","type":"address"}],"name":"sweepTokenWithFee","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"feeBips","type":"uint256"},{"internalType":"address","name":"feeRecipient","type":"address"}],"name":"sweepTokenWithFee","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"int256","name":"amount0Delta","type":"int256"},{"internalType":"int256","name":"amount1Delta","type":"int256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"uniswapV3SwapCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"unwrapWETH9","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountMinimum","type":"uint256"}],"name":"unwrapWETH9","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"feeBips","type":"uint256"},{"internalType":"address","name":"feeRecipient","type":"address"}],"name":"unwrapWETH9WithFee","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"uint256","name":"feeBips","type":"uint256"},{"internalType":"address","name":"feeRecipient","type":"address"}],"name":"unwrapWETH9WithFee","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"wrapETH","outputs":[],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]'; var abiPool = '[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"int24\",\"name\":\"tickLower\",\"type\":\"int24\"},{\"indexed\":true,\"internalType\":\"int24\",\"name\":\"tickUpper\",\"type\":\"int24\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"}],\"name\":\"Burn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"int24\",\"name\":\"tickLower\",\"type\":\"int24\"},{\"indexed\":true,\"internalType\":\"int24\",\"name\":\"tickUpper\",\"type\":\"int24\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"amount0\",\"type\":\"uint128\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"amount1\",\"type\":\"uint128\"}],\"name\":\"Collect\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"amount0\",\"type\":\"uint128\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"amount1\",\"type\":\"uint128\"}],\"name\":\"CollectProtocol\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"paid0\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"paid1\",\"type\":\"uint256\"}],\"name\":\"Flash\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"observationCardinalityNextOld\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"observationCardinalityNextNew\",\"type\":\"uint16\"}],\"name\":\"IncreaseObservationCardinalityNext\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint160\",\"name\":\"sqrtPriceX96\",\"type\":\"uint160\"},{\"indexed\":false,\"internalType\":\"int24\",\"name\":\"tick\",\"type\":\"int24\"}],\"name\":\"Initialize\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"int24\",\"name\":\"tickLower\",\"type\":\"int24\"},{\"indexed\":true,\"internalType\":\"int24\",\"name\":\"tickUpper\",\"type\":\"int24\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"}],\"name\":\"Mint\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"feeProtocol0Old\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"feeProtocol1Old\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"feeProtocol0New\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"feeProtocol1New\",\"type\":\"uint8\"}],\"name\":\"SetFeeProtocol\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"amount0\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"amount1\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"uint160\",\"name\":\"sqrtPriceX96\",\"type\":\"uint160\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"liquidity\",\"type\":\"uint128\"},{\"indexed\":false,\"internalType\":\"int24\",\"name\":\"tick\",\"type\":\"int24\"}],\"name\":\"Swap\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"int24\",\"name\":\"tickLower\",\"type\":\"int24\"},{\"internalType\":\"int24\",\"name\":\"tickUpper\",\"type\":\"int24\"},{\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"}],\"name\":\"burn\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"int24\",\"name\":\"tickLower\",\"type\":\"int24\"},{\"internalType\":\"int24\",\"name\":\"tickUpper\",\"type\":\"int24\"},{\"internalType\":\"uint128\",\"name\":\"amount0Requested\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"amount1Requested\",\"type\":\"uint128\"}],\"name\":\"collect\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"amount0\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"amount1\",\"type\":\"uint128\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint128\",\"name\":\"amount0Requested\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"amount1Requested\",\"type\":\"uint128\"}],\"name\":\"collectProtocol\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"amount0\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"amount1\",\"type\":\"uint128\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"factory\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fee\",\"outputs\":[{\"internalType\":\"uint24\",\"name\":\"\",\"type\":\"uint24\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"feeGrowthGlobal0X128\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"feeGrowthGlobal1X128\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"flash\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"observationCardinalityNext\",\"type\":\"uint16\"}],\"name\":\"increaseObservationCardinalityNext\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint160\",\"name\":\"sqrtPriceX96\",\"type\":\"uint160\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"liquidity\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maxLiquidityPerTick\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"int24\",\"name\":\"tickLower\",\"type\":\"int24\"},{\"internalType\":\"int24\",\"name\":\"tickUpper\",\"type\":\"int24\"},{\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"mint\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"observations\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"blockTimestamp\",\"type\":\"uint32\"},{\"internalType\":\"int56\",\"name\":\"tickCumulative\",\"type\":\"int56\"},{\"internalType\":\"uint160\",\"name\":\"secondsPerLiquidityCumulativeX128\",\"type\":\"uint160\"},{\"internalType\":\"bool\",\"name\":\"initialized\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32[]\",\"name\":\"secondsAgos\",\"type\":\"uint32[]\"}],\"name\":\"observe\",\"outputs\":[{\"internalType\":\"int56[]\",\"name\":\"tickCumulatives\",\"type\":\"int56[]\"},{\"internalType\":\"uint160[]\",\"name\":\"secondsPerLiquidityCumulativeX128s\",\"type\":\"uint160[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"positions\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"liquidity\",\"type\":\"uint128\"},{\"internalType\":\"uint256\",\"name\":\"feeGrowthInside0LastX128\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"feeGrowthInside1LastX128\",\"type\":\"uint256\"},{\"internalType\":\"uint128\",\"name\":\"tokensOwed0\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"tokensOwed1\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"token0\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"token1\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"feeProtocol0\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"feeProtocol1\",\"type\":\"uint8\"}],\"name\":\"setFeeProtocol\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"slot0\",\"outputs\":[{\"internalType\":\"uint160\",\"name\":\"sqrtPriceX96\",\"type\":\"uint160\"},{\"internalType\":\"int24\",\"name\":\"tick\",\"type\":\"int24\"},{\"internalType\":\"uint16\",\"name\":\"observationIndex\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"observationCardinality\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"observationCardinalityNext\",\"type\":\"uint16\"},{\"internalType\":\"uint8\",\"name\":\"feeProtocol\",\"type\":\"uint8\"},{\"internalType\":\"bool\",\"name\":\"unlocked\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int24\",\"name\":\"tickLower\",\"type\":\"int24\"},{\"internalType\":\"int24\",\"name\":\"tickUpper\",\"type\":\"int24\"}],\"name\":\"snapshotCumulativesInside\",\"outputs\":[{\"internalType\":\"int56\",\"name\":\"tickCumulativeInside\",\"type\":\"int56\"},{\"internalType\":\"uint160\",\"name\":\"secondsPerLiquidityInsideX128\",\"type\":\"uint160\"},{\"internalType\":\"uint32\",\"name\":\"secondsInside\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"zeroForOne\",\"type\":\"bool\"},{\"internalType\":\"int256\",\"name\":\"amountSpecified\",\"type\":\"int256\"},{\"internalType\":\"uint160\",\"name\":\"sqrtPriceLimitX96\",\"type\":\"uint160\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"swap\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"amount0\",\"type\":\"int256\"},{\"internalType\":\"int256\",\"name\":\"amount1\",\"type\":\"int256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int16\",\"name\":\"\",\"type\":\"int16\"}],\"name\":\"tickBitmap\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"tickSpacing\",\"outputs\":[{\"internalType\":\"int24\",\"name\":\"\",\"type\":\"int24\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int24\",\"name\":\"\",\"type\":\"int24\"}],\"name\":\"ticks\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"liquidityGross\",\"type\":\"uint128\"},{\"internalType\":\"int128\",\"name\":\"liquidityNet\",\"type\":\"int128\"},{\"internalType\":\"uint256\",\"name\":\"feeGrowthOutside0X128\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"feeGrowthOutside1X128\",\"type\":\"uint256\"},{\"internalType\":\"int56\",\"name\":\"tickCumulativeOutside\",\"type\":\"int56\"},{\"internalType\":\"uint160\",\"name\":\"secondsPerLiquidityOutsideX128\",\"type\":\"uint160\"},{\"internalType\":\"uint32\",\"name\":\"secondsOutside\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"initialized\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"token0\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"token1\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]' var abiFactory = '[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint24\",\"name\":\"fee\",\"type\":\"uint24\"},{\"indexed\":true,\"internalType\":\"int24\",\"name\":\"tickSpacing\",\"type\":\"int24\"}],\"name\":\"FeeAmountEnabled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oldOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnerChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token0\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token1\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint24\",\"name\":\"fee\",\"type\":\"uint24\"},{\"indexed\":false,\"internalType\":\"int24\",\"name\":\"tickSpacing\",\"type\":\"int24\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"pool\",\"type\":\"address\"}],\"name\":\"PoolCreated\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"tokenA\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"tokenB\",\"type\":\"address\"},{\"internalType\":\"uint24\",\"name\":\"fee\",\"type\":\"uint24\"}],\"name\":\"createPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"pool\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint24\",\"name\":\"fee\",\"type\":\"uint24\"},{\"internalType\":\"int24\",\"name\":\"tickSpacing\",\"type\":\"int24\"}],\"name\":\"enableFeeAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint24\",\"name\":\"\",\"type\":\"uint24\"}],\"name\":\"feeAmountTickSpacing\",\"outputs\":[{\"internalType\":\"int24\",\"name\":\"\",\"type\":\"int24\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint24\",\"name\":\"\",\"type\":\"uint24\"}],\"name\":\"getPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"parameters\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"factory\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"token0\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"token1\",\"type\":\"address\"},{\"internalType\":\"uint24\",\"name\":\"fee\",\"type\":\"uint24\"},{\"internalType\":\"int24\",\"name\":\"tickSpacing\",\"type\":\"int24\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"setOwner\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]' var contractV3FactoryAddress = "0x1F98431c8aD98523631AE4a59f267346ea31F984" var contractV3SwapRouterV2Address = "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45" function main() { // 注册Uniswap工厂合约的ABI exchange.IO("abi", contractV3FactoryAddress, abiFactory) // 测试Factory合约的owner方法 var owner = exchange.IO("api", contractV3FactoryAddress, "owner") Log("owner:", owner) // 返回值应当为: 0x1a9C8182C09F50C8318d769245beA52c32BE35BC // 注册Uniswap路由合约的ABI exchange.IO("abi", contractV3SwapRouterV2Address, abiRoute) // 测试Uniswap V3 Router V2合约的factory方法 var factoryOfRouter = exchange.IO("api", contractV3SwapRouterV2Address, "factory") Log("factoryOfRouter:", factoryOfRouter) // 返回值应当为: 0x1F98431c8aD98523631AE4a59f267346ea31F984 // 获取交易对的池地址 var tokenIn = {name : "DAI", address: "0x6b175474e89094c44da98b954eedeac495271d0f"} var tokenOut = {name : "USDT", address: "0xdac17f958d2ee523a2206206994597c13d831ec7"} var poolAddress = exchange.IO("api", contractV3FactoryAddress, "getPool", tokenIn.address, tokenOut.address, 3000) var pair = "tokenIn:" + tokenIn.name + ", tokenOut:" + tokenOut.name + ", fee:" + 3000 Log("使用工厂合约的getPool方法获取", pair, "池地址:", poolAddress) // 注册池合约ABI exchange.IO("abi", poolAddress, abiPool) // 测试池合约的 var factoryOfPool = exchange.IO("api", poolAddress, "factory") Log("factoryOfPool:", factoryOfPool) // 返回值应当为: 0x1F98431c8aD98523631AE4a59f267346ea31F984 }

上記のコードは、ファクトリ コントラクト、ルーティング コントラクト、プール コントラクトの ABI を登録し、いくつかのテストを行います。ルーティング契約とプール契約はfactoryメソッドは0x1F98431c8aD98523631AE4a59f267346ea31F984このアドレスはUniswapファクトリーコントラクト(コード内)ですcontractV3FactoryAddress変数)。

javascript
var contractV3FactoryAddress = "0x1F98431c8aD98523631AE4a59f267346ea31F984"

スマートコントラクトのABIを登録したら、まずはUniswap V3交換操作には以下のコンテンツを使用しますERC20具体的なシナリオとして、トークンの交換(Ethereum メインネット上)が使用されます。

クエリUniswap V3ルーティング契約承認

存在するERC20契約書には、allowanceこの関数は、他のアドレスに承認されたトークンの数を照会するために使用されます。特定のアドレスが別のアドレス(通常はコントラクト アドレス)に自身のアカウントから転送することを許可したトークンの数を照会できます。
のためにUniswap V3ルーティング契約については、approveこの機能はルーター契約のアドレスに許可され、その後使用できますERC20トークンallowance承認数量を照会する機能。

前回のチュートリアルで説明したことを思い出してくださいERC20契約メソッドの呼び出しですか?allowanceapprove両方ERC20契約方法はこれまで説明したものと同様です。balanceOftransferすべての方法は同等の地位にあります。

引き換える前に、まず承認が与えられているかどうかを確認する必要があります。Uniswapルーター コントラクトには、交換を実行するのに十分なトークンがあります。交換したいアクションが次の場合:1INCH->ETH、レートは10000に設定されます。このレートは 10000 に設定されており、レートは 1% であることを意味します。Uniswap交換プールには様々なレートがあり、一般的にはUniswapいくつかのオプションが提供されています。例えば、レートが3000に設定されている場合、レートは0.3%であることを意味します。Uniswapドキュメントおよび関連情報。

ここで注目すべきは、実際の交換プールは1INCH/WETHETH と WETH は、Ethereum 内の 2 つの異なるトークンです。

  • ETH(イーサ):
    ETH は、Ethereum ブロックチェーンのネイティブ暗号通貨であり、Ethereum ネットワークの主要な資産およびコンピューティング ユニットです。 ETH は、普遍的な流通性と使いやすさを備えた Ethereum のネイティブ トークンです。取引手数料の支払い、スマート コントラクトのやり取りへの参加、価値の保存などに使用できます。
  • WETH(ラップされたエーテル):
    WETH は、ERC20 標準トークンとしてカプセル化された ETH の形式です。これは、ETH がスマート コントラクト内の ERC20 トークンとシームレスにやり取りできるようにすることを目的とした、Ethereum 上のスマート コントラクトです。 WETH は、ETH を WETH 契約アドレスに入金することで作成および取得でき、WETH はいつでも ETH に戻すことができます。イーサリアムエコシステムにおけるWETHの主な役割は、ETHに他のERC20トークンと同じ標準インターフェースと互換性を提供し、ETHが分散型トランザクション、流動性プール、その他のDeFiプロトコルに参加できるようにすることです。

したがって、WETH は ETH のパッケージ化された形式であり、これにより ETH は Ethereum スマート コントラクト内で ERC20 トークンの形式で対話できるようになります。通常、ETH をスマート コントラクトで使用する必要がある場合は、ETH を WETH に変換して取引したり、DeFi 操作に使用したりすることができ、その後、必要に応じて WETH を ETH に戻すことができます。

使用ERC20allowance認可数量の取得方法:

javascript
var abiRoute = '[{"inputs":[{"internalType":"address","name":"_factoryV2","type":"address"},{"internalType":"address","name":"factoryV3","type":"address"},{"internalType":"address","name":"_positionManager","type":"address"},{"internalType":"address","name":"_WETH9","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"WETH9","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"approveMax","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"approveMaxMinusOne","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"approveZeroThenMax","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"approveZeroThenMaxMinusOne","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"callPositionManager","outputs":[{"internalType":"bytes","name":"result","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"paths","type":"bytes[]"},{"internalType":"uint128[]","name":"amounts","type":"uint128[]"},{"internalType":"uint24","name":"maximumTickDivergence","type":"uint24"},{"internalType":"uint32","name":"secondsAgo","type":"uint32"}],"name":"checkOracleSlippage","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"path","type":"bytes"},{"internalType":"uint24","name":"maximumTickDivergence","type":"uint24"},{"internalType":"uint32","name":"secondsAgo","type":"uint32"}],"name":"checkOracleSlippage","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"path","type":"bytes"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMinimum","type":"uint256"}],"internalType":"struct IV3SwapRouter.ExactInputParams","name":"params","type":"tuple"}],"name":"exactInput","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMinimum","type":"uint256"},{"internalType":"uint160","name":"sqrtPriceLimitX96","type":"uint160"}],"internalType":"struct IV3SwapRouter.ExactInputSingleParams","name":"params","type":"tuple"}],"name":"exactInputSingle","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"path","type":"bytes"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMaximum","type":"uint256"}],"internalType":"struct IV3SwapRouter.ExactOutputParams","name":"params","type":"tuple"}],"name":"exactOutput","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMaximum","type":"uint256"},{"internalType":"uint160","name":"sqrtPriceLimitX96","type":"uint160"}],"internalType":"struct IV3SwapRouter.ExactOutputSingleParams","name":"params","type":"tuple"}],"name":"exactOutputSingle","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"factoryV2","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"getApprovalType","outputs":[{"internalType":"enum IApproveAndCall.ApprovalType","name":"","type":"uint8"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"amount0Min","type":"uint256"},{"internalType":"uint256","name":"amount1Min","type":"uint256"}],"internalType":"struct IApproveAndCall.IncreaseLiquidityParams","name":"params","type":"tuple"}],"name":"increaseLiquidity","outputs":[{"internalType":"bytes","name":"result","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"int24","name":"tickLower","type":"int24"},{"internalType":"int24","name":"tickUpper","type":"int24"},{"internalType":"uint256","name":"amount0Min","type":"uint256"},{"internalType":"uint256","name":"amount1Min","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"internalType":"struct IApproveAndCall.MintParams","name":"params","type":"tuple"}],"name":"mint","outputs":[{"internalType":"bytes","name":"result","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"previousBlockhash","type":"bytes32"},{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"positionManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"pull","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"refundETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"selfPermit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"selfPermitAllowed","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"selfPermitAllowedIfNecessary","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"selfPermitIfNecessary","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"}],"name":"swapExactTokensForTokens","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"}],"name":"swapTokensForExactTokens","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepToken","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountMinimum","type":"uint256"}],"name":"sweepToken","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"uint256","name":"feeBips","type":"uint256"},{"internalType":"address","name":"feeRecipient","type":"address"}],"name":"sweepTokenWithFee","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"feeBips","type":"uint256"},{"internalType":"address","name":"feeRecipient","type":"address"}],"name":"sweepTokenWithFee","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"int256","name":"amount0Delta","type":"int256"},{"internalType":"int256","name":"amount1Delta","type":"int256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"uniswapV3SwapCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"unwrapWETH9","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountMinimum","type":"uint256"}],"name":"unwrapWETH9","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"feeBips","type":"uint256"},{"internalType":"address","name":"feeRecipient","type":"address"}],"name":"unwrapWETH9WithFee","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"uint256","name":"feeBips","type":"uint256"},{"internalType":"address","name":"feeRecipient","type":"address"}],"name":"unwrapWETH9WithFee","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"wrapETH","outputs":[],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]'; var abiPool = '[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"int24\",\"name\":\"tickLower\",\"type\":\"int24\"},{\"indexed\":true,\"internalType\":\"int24\",\"name\":\"tickUpper\",\"type\":\"int24\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"}],\"name\":\"Burn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"int24\",\"name\":\"tickLower\",\"type\":\"int24\"},{\"indexed\":true,\"internalType\":\"int24\",\"name\":\"tickUpper\",\"type\":\"int24\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"amount0\",\"type\":\"uint128\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"amount1\",\"type\":\"uint128\"}],\"name\":\"Collect\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"amount0\",\"type\":\"uint128\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"amount1\",\"type\":\"uint128\"}],\"name\":\"CollectProtocol\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"paid0\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"paid1\",\"type\":\"uint256\"}],\"name\":\"Flash\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"observationCardinalityNextOld\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"observationCardinalityNextNew\",\"type\":\"uint16\"}],\"name\":\"IncreaseObservationCardinalityNext\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint160\",\"name\":\"sqrtPriceX96\",\"type\":\"uint160\"},{\"indexed\":false,\"internalType\":\"int24\",\"name\":\"tick\",\"type\":\"int24\"}],\"name\":\"Initialize\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"int24\",\"name\":\"tickLower\",\"type\":\"int24\"},{\"indexed\":true,\"internalType\":\"int24\",\"name\":\"tickUpper\",\"type\":\"int24\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"}],\"name\":\"Mint\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"feeProtocol0Old\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"feeProtocol1Old\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"feeProtocol0New\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"feeProtocol1New\",\"type\":\"uint8\"}],\"name\":\"SetFeeProtocol\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"amount0\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"amount1\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"uint160\",\"name\":\"sqrtPriceX96\",\"type\":\"uint160\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"liquidity\",\"type\":\"uint128\"},{\"indexed\":false,\"internalType\":\"int24\",\"name\":\"tick\",\"type\":\"int24\"}],\"name\":\"Swap\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"int24\",\"name\":\"tickLower\",\"type\":\"int24\"},{\"internalType\":\"int24\",\"name\":\"tickUpper\",\"type\":\"int24\"},{\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"}],\"name\":\"burn\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"int24\",\"name\":\"tickLower\",\"type\":\"int24\"},{\"internalType\":\"int24\",\"name\":\"tickUpper\",\"type\":\"int24\"},{\"internalType\":\"uint128\",\"name\":\"amount0Requested\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"amount1Requested\",\"type\":\"uint128\"}],\"name\":\"collect\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"amount0\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"amount1\",\"type\":\"uint128\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint128\",\"name\":\"amount0Requested\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"amount1Requested\",\"type\":\"uint128\"}],\"name\":\"collectProtocol\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"amount0\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"amount1\",\"type\":\"uint128\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"factory\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fee\",\"outputs\":[{\"internalType\":\"uint24\",\"name\":\"\",\"type\":\"uint24\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"feeGrowthGlobal0X128\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"feeGrowthGlobal1X128\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"flash\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"observationCardinalityNext\",\"type\":\"uint16\"}],\"name\":\"increaseObservationCardinalityNext\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint160\",\"name\":\"sqrtPriceX96\",\"type\":\"uint160\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"liquidity\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maxLiquidityPerTick\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"int24\",\"name\":\"tickLower\",\"type\":\"int24\"},{\"internalType\":\"int24\",\"name\":\"tickUpper\",\"type\":\"int24\"},{\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"mint\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"observations\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"blockTimestamp\",\"type\":\"uint32\"},{\"internalType\":\"int56\",\"name\":\"tickCumulative\",\"type\":\"int56\"},{\"internalType\":\"uint160\",\"name\":\"secondsPerLiquidityCumulativeX128\",\"type\":\"uint160\"},{\"internalType\":\"bool\",\"name\":\"initialized\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32[]\",\"name\":\"secondsAgos\",\"type\":\"uint32[]\"}],\"name\":\"observe\",\"outputs\":[{\"internalType\":\"int56[]\",\"name\":\"tickCumulatives\",\"type\":\"int56[]\"},{\"internalType\":\"uint160[]\",\"name\":\"secondsPerLiquidityCumulativeX128s\",\"type\":\"uint160[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"positions\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"liquidity\",\"type\":\"uint128\"},{\"internalType\":\"uint256\",\"name\":\"feeGrowthInside0LastX128\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"feeGrowthInside1LastX128\",\"type\":\"uint256\"},{\"internalType\":\"uint128\",\"name\":\"tokensOwed0\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"tokensOwed1\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"token0\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"token1\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"feeProtocol0\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"feeProtocol1\",\"type\":\"uint8\"}],\"name\":\"setFeeProtocol\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"slot0\",\"outputs\":[{\"internalType\":\"uint160\",\"name\":\"sqrtPriceX96\",\"type\":\"uint160\"},{\"internalType\":\"int24\",\"name\":\"tick\",\"type\":\"int24\"},{\"internalType\":\"uint16\",\"name\":\"observationIndex\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"observationCardinality\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"observationCardinalityNext\",\"type\":\"uint16\"},{\"internalType\":\"uint8\",\"name\":\"feeProtocol\",\"type\":\"uint8\"},{\"internalType\":\"bool\",\"name\":\"unlocked\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int24\",\"name\":\"tickLower\",\"type\":\"int24\"},{\"internalType\":\"int24\",\"name\":\"tickUpper\",\"type\":\"int24\"}],\"name\":\"snapshotCumulativesInside\",\"outputs\":[{\"internalType\":\"int56\",\"name\":\"tickCumulativeInside\",\"type\":\"int56\"},{\"internalType\":\"uint160\",\"name\":\"secondsPerLiquidityInsideX128\",\"type\":\"uint160\"},{\"internalType\":\"uint32\",\"name\":\"secondsInside\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"zeroForOne\",\"type\":\"bool\"},{\"internalType\":\"int256\",\"name\":\"amountSpecified\",\"type\":\"int256\"},{\"internalType\":\"uint160\",\"name\":\"sqrtPriceLimitX96\",\"type\":\"uint160\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"swap\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"amount0\",\"type\":\"int256\"},{\"internalType\":\"int256\",\"name\":\"amount1\",\"type\":\"int256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int16\",\"name\":\"\",\"type\":\"int16\"}],\"name\":\"tickBitmap\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"tickSpacing\",\"outputs\":[{\"internalType\":\"int24\",\"name\":\"\",\"type\":\"int24\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int24\",\"name\":\"\",\"type\":\"int24\"}],\"name\":\"ticks\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"liquidityGross\",\"type\":\"uint128\"},{\"internalType\":\"int128\",\"name\":\"liquidityNet\",\"type\":\"int128\"},{\"internalType\":\"uint256\",\"name\":\"feeGrowthOutside0X128\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"feeGrowthOutside1X128\",\"type\":\"uint256\"},{\"internalType\":\"int56\",\"name\":\"tickCumulativeOutside\",\"type\":\"int56\"},{\"internalType\":\"uint160\",\"name\":\"secondsPerLiquidityOutsideX128\",\"type\":\"uint160\"},{\"internalType\":\"uint32\",\"name\":\"secondsOutside\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"initialized\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"token0\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"token1\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]' var abiFactory = '[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint24\",\"name\":\"fee\",\"type\":\"uint24\"},{\"indexed\":true,\"internalType\":\"int24\",\"name\":\"tickSpacing\",\"type\":\"int24\"}],\"name\":\"FeeAmountEnabled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oldOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnerChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token0\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token1\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint24\",\"name\":\"fee\",\"type\":\"uint24\"},{\"indexed\":false,\"internalType\":\"int24\",\"name\":\"tickSpacing\",\"type\":\"int24\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"pool\",\"type\":\"address\"}],\"name\":\"PoolCreated\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"tokenA\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"tokenB\",\"type\":\"address\"},{\"internalType\":\"uint24\",\"name\":\"fee\",\"type\":\"uint24\"}],\"name\":\"createPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"pool\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint24\",\"name\":\"fee\",\"type\":\"uint24\"},{\"internalType\":\"int24\",\"name\":\"tickSpacing\",\"type\":\"int24\"}],\"name\":\"enableFeeAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint24\",\"name\":\"\",\"type\":\"uint24\"}],\"name\":\"feeAmountTickSpacing\",\"outputs\":[{\"internalType\":\"int24\",\"name\":\"\",\"type\":\"int24\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint24\",\"name\":\"\",\"type\":\"uint24\"}],\"name\":\"getPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"parameters\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"factory\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"token0\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"token1\",\"type\":\"address\"},{\"internalType\":\"uint24\",\"name\":\"fee\",\"type\":\"uint24\"},{\"internalType\":\"int24\",\"name\":\"tickSpacing\",\"type\":\"int24\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"setOwner\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]' var contractV3FactoryAddress = "0x1F98431c8aD98523631AE4a59f267346ea31F984" var contractV3SwapRouterV2Address = "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45" function toAmount(s, decimals) { return Number((BigDecimal(BigInt(s)) / BigDecimal(Math.pow(10, decimals))).toString()) } function main() { // 注册Uniswap工厂合约的ABI exchange.IO("abi", contractV3FactoryAddress, abiFactory) // 注册Uniswap路由合约的ABI exchange.IO("abi", contractV3SwapRouterV2Address, abiRoute) // 获取交易对的池地址 var tokenIn = {name : "1INCH", address: "0x111111111117dC0aa78b770fA6A738034120C302", decimals: exchange.IO("api", "0x111111111117dC0aa78b770fA6A738034120C302", "decimals")} var tokenOut = {name : "WETH", address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", decimals: exchange.IO("api", "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "decimals")} var poolAddress = exchange.IO("api", contractV3FactoryAddress, "getPool", tokenIn.address, tokenOut.address, 10000) // 注册池合约ABI exchange.IO("abi", poolAddress, abiPool) // 获取当前配置的钱包地址 var walletAddress = exchange.IO("address") // 1INCH -> ETH, tokenIn: 1INCH var allowanceAmount = exchange.IO("api", tokenIn.address, "allowance", walletAddress, contractV3SwapRouterV2Address) Log("allowanceAmount:", allowanceAmount, ", 使用toAmount()函数转换为可读数值:", toAmount(allowanceAmount, tokenIn.decimals)) }

コードについてtoAmount()関数についてよく理解しておく必要があります。これまでの章では、このカスタム関数コードを何度も使用して、データを人間が読みやすい数値に処理してきました。

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

コードを実行すると、現在の承認数量が 0 であることがわかります。したがって、引き換えるには、ルーティング コントラクトに十分な数量を承認する必要があります。

img

承認Uniswap V3ルーティング契約

使用している場合allowance照会後に承認数が不十分な場合は、approve承認Uniswap V3ルーティング契約により、一定数のERC20トークン。

または1INCH -> ETH例えば、ERC20approve方法Uniswapルーティング契約は、現在設定されているウォレットの操作を承認します。1INCHトークン。

javascript
var abiRoute = '[{"inputs":[{"internalType":"address","name":"_factoryV2","type":"address"},{"internalType":"address","name":"factoryV3","type":"address"},{"internalType":"address","name":"_positionManager","type":"address"},{"internalType":"address","name":"_WETH9","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"WETH9","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"approveMax","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"approveMaxMinusOne","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"approveZeroThenMax","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"approveZeroThenMaxMinusOne","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"callPositionManager","outputs":[{"internalType":"bytes","name":"result","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"paths","type":"bytes[]"},{"internalType":"uint128[]","name":"amounts","type":"uint128[]"},{"internalType":"uint24","name":"maximumTickDivergence","type":"uint24"},{"internalType":"uint32","name":"secondsAgo","type":"uint32"}],"name":"checkOracleSlippage","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"path","type":"bytes"},{"internalType":"uint24","name":"maximumTickDivergence","type":"uint24"},{"internalType":"uint32","name":"secondsAgo","type":"uint32"}],"name":"checkOracleSlippage","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"path","type":"bytes"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMinimum","type":"uint256"}],"internalType":"struct IV3SwapRouter.ExactInputParams","name":"params","type":"tuple"}],"name":"exactInput","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMinimum","type":"uint256"},{"internalType":"uint160","name":"sqrtPriceLimitX96","type":"uint160"}],"internalType":"struct IV3SwapRouter.ExactInputSingleParams","name":"params","type":"tuple"}],"name":"exactInputSingle","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"path","type":"bytes"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMaximum","type":"uint256"}],"internalType":"struct IV3SwapRouter.ExactOutputParams","name":"params","type":"tuple"}],"name":"exactOutput","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMaximum","type":"uint256"},{"internalType":"uint160","name":"sqrtPriceLimitX96","type":"uint160"}],"internalType":"struct IV3SwapRouter.ExactOutputSingleParams","name":"params","type":"tuple"}],"name":"exactOutputSingle","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"factoryV2","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"getApprovalType","outputs":[{"internalType":"enum IApproveAndCall.ApprovalType","name":"","type":"uint8"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"amount0Min","type":"uint256"},{"internalType":"uint256","name":"amount1Min","type":"uint256"}],"internalType":"struct IApproveAndCall.IncreaseLiquidityParams","name":"params","type":"tuple"}],"name":"increaseLiquidity","outputs":[{"internalType":"bytes","name":"result","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"int24","name":"tickLower","type":"int24"},{"internalType":"int24","name":"tickUpper","type":"int24"},{"internalType":"uint256","name":"amount0Min","type":"uint256"},{"internalType":"uint256","name":"amount1Min","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"internalType":"struct IApproveAndCall.MintParams","name":"params","type":"tuple"}],"name":"mint","outputs":[{"internalType":"bytes","name":"result","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"previousBlockhash","type":"bytes32"},{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"positionManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"pull","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"refundETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"selfPermit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"selfPermitAllowed","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"selfPermitAllowedIfNecessary","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"selfPermitIfNecessary","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"}],"name":"swapExactTokensForTokens","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"}],"name":"swapTokensForExactTokens","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepToken","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountMinimum","type":"uint256"}],"name":"sweepToken","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"uint256","name":"feeBips","type":"uint256"},{"internalType":"address","name":"feeRecipient","type":"address"}],"name":"sweepTokenWithFee","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"feeBips","type":"uint256"},{"internalType":"address","name":"feeRecipient","type":"address"}],"name":"sweepTokenWithFee","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"int256","name":"amount0Delta","type":"int256"},{"internalType":"int256","name":"amount1Delta","type":"int256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"uniswapV3SwapCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"unwrapWETH9","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountMinimum","type":"uint256"}],"name":"unwrapWETH9","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"feeBips","type":"uint256"},{"internalType":"address","name":"feeRecipient","type":"address"}],"name":"unwrapWETH9WithFee","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"uint256","name":"feeBips","type":"uint256"},{"internalType":"address","name":"feeRecipient","type":"address"}],"name":"unwrapWETH9WithFee","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"wrapETH","outputs":[],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]'; var abiPool = '[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"int24\",\"name\":\"tickLower\",\"type\":\"int24\"},{\"indexed\":true,\"internalType\":\"int24\",\"name\":\"tickUpper\",\"type\":\"int24\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"}],\"name\":\"Burn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"int24\",\"name\":\"tickLower\",\"type\":\"int24\"},{\"indexed\":true,\"internalType\":\"int24\",\"name\":\"tickUpper\",\"type\":\"int24\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"amount0\",\"type\":\"uint128\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"amount1\",\"type\":\"uint128\"}],\"name\":\"Collect\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"amount0\",\"type\":\"uint128\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"amount1\",\"type\":\"uint128\"}],\"name\":\"CollectProtocol\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"paid0\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"paid1\",\"type\":\"uint256\"}],\"name\":\"Flash\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"observationCardinalityNextOld\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"observationCardinalityNextNew\",\"type\":\"uint16\"}],\"name\":\"IncreaseObservationCardinalityNext\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint160\",\"name\":\"sqrtPriceX96\",\"type\":\"uint160\"},{\"indexed\":false,\"internalType\":\"int24\",\"name\":\"tick\",\"type\":\"int24\"}],\"name\":\"Initialize\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"int24\",\"name\":\"tickLower\",\"type\":\"int24\"},{\"indexed\":true,\"internalType\":\"int24\",\"name\":\"tickUpper\",\"type\":\"int24\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"}],\"name\":\"Mint\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"feeProtocol0Old\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"feeProtocol1Old\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"feeProtocol0New\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"feeProtocol1New\",\"type\":\"uint8\"}],\"name\":\"SetFeeProtocol\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"amount0\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"amount1\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"uint160\",\"name\":\"sqrtPriceX96\",\"type\":\"uint160\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"liquidity\",\"type\":\"uint128\"},{\"indexed\":false,\"internalType\":\"int24\",\"name\":\"tick\",\"type\":\"int24\"}],\"name\":\"Swap\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"int24\",\"name\":\"tickLower\",\"type\":\"int24\"},{\"internalType\":\"int24\",\"name\":\"tickUpper\",\"type\":\"int24\"},{\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"}],\"name\":\"burn\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"int24\",\"name\":\"tickLower\",\"type\":\"int24\"},{\"internalType\":\"int24\",\"name\":\"tickUpper\",\"type\":\"int24\"},{\"internalType\":\"uint128\",\"name\":\"amount0Requested\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"amount1Requested\",\"type\":\"uint128\"}],\"name\":\"collect\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"amount0\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"amount1\",\"type\":\"uint128\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint128\",\"name\":\"amount0Requested\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"amount1Requested\",\"type\":\"uint128\"}],\"name\":\"collectProtocol\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"amount0\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"amount1\",\"type\":\"uint128\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"factory\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fee\",\"outputs\":[{\"internalType\":\"uint24\",\"name\":\"\",\"type\":\"uint24\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"feeGrowthGlobal0X128\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"feeGrowthGlobal1X128\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"flash\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"observationCardinalityNext\",\"type\":\"uint16\"}],\"name\":\"increaseObservationCardinalityNext\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint160\",\"name\":\"sqrtPriceX96\",\"type\":\"uint160\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"liquidity\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maxLiquidityPerTick\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"int24\",\"name\":\"tickLower\",\"type\":\"int24\"},{\"internalType\":\"int24\",\"name\":\"tickUpper\",\"type\":\"int24\"},{\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"mint\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"observations\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"blockTimestamp\",\"type\":\"uint32\"},{\"internalType\":\"int56\",\"name\":\"tickCumulative\",\"type\":\"int56\"},{\"internalType\":\"uint160\",\"name\":\"secondsPerLiquidityCumulativeX128\",\"type\":\"uint160\"},{\"internalType\":\"bool\",\"name\":\"initialized\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32[]\",\"name\":\"secondsAgos\",\"type\":\"uint32[]\"}],\"name\":\"observe\",\"outputs\":[{\"internalType\":\"int56[]\",\"name\":\"tickCumulatives\",\"type\":\"int56[]\"},{\"internalType\":\"uint160[]\",\"name\":\"secondsPerLiquidityCumulativeX128s\",\"type\":\"uint160[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"positions\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"liquidity\",\"type\":\"uint128\"},{\"internalType\":\"uint256\",\"name\":\"feeGrowthInside0LastX128\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"feeGrowthInside1LastX128\",\"type\":\"uint256\"},{\"internalType\":\"uint128\",\"name\":\"tokensOwed0\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"tokensOwed1\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"token0\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"token1\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"feeProtocol0\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"feeProtocol1\",\"type\":\"uint8\"}],\"name\":\"setFeeProtocol\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"slot0\",\"outputs\":[{\"internalType\":\"uint160\",\"name\":\"sqrtPriceX96\",\"type\":\"uint160\"},{\"internalType\":\"int24\",\"name\":\"tick\",\"type\":\"int24\"},{\"internalType\":\"uint16\",\"name\":\"observationIndex\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"observationCardinality\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"observationCardinalityNext\",\"type\":\"uint16\"},{\"internalType\":\"uint8\",\"name\":\"feeProtocol\",\"type\":\"uint8\"},{\"internalType\":\"bool\",\"name\":\"unlocked\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int24\",\"name\":\"tickLower\",\"type\":\"int24\"},{\"internalType\":\"int24\",\"name\":\"tickUpper\",\"type\":\"int24\"}],\"name\":\"snapshotCumulativesInside\",\"outputs\":[{\"internalType\":\"int56\",\"name\":\"tickCumulativeInside\",\"type\":\"int56\"},{\"internalType\":\"uint160\",\"name\":\"secondsPerLiquidityInsideX128\",\"type\":\"uint160\"},{\"internalType\":\"uint32\",\"name\":\"secondsInside\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"zeroForOne\",\"type\":\"bool\"},{\"internalType\":\"int256\",\"name\":\"amountSpecified\",\"type\":\"int256\"},{\"internalType\":\"uint160\",\"name\":\"sqrtPriceLimitX96\",\"type\":\"uint160\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"swap\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"amount0\",\"type\":\"int256\"},{\"internalType\":\"int256\",\"name\":\"amount1\",\"type\":\"int256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int16\",\"name\":\"\",\"type\":\"int16\"}],\"name\":\"tickBitmap\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"tickSpacing\",\"outputs\":[{\"internalType\":\"int24\",\"name\":\"\",\"type\":\"int24\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int24\",\"name\":\"\",\"type\":\"int24\"}],\"name\":\"ticks\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"liquidityGross\",\"type\":\"uint128\"},{\"internalType\":\"int128\",\"name\":\"liquidityNet\",\"type\":\"int128\"},{\"internalType\":\"uint256\",\"name\":\"feeGrowthOutside0X128\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"feeGrowthOutside1X128\",\"type\":\"uint256\"},{\"internalType\":\"int56\",\"name\":\"tickCumulativeOutside\",\"type\":\"int56\"},{\"internalType\":\"uint160\",\"name\":\"secondsPerLiquidityOutsideX128\",\"type\":\"uint160\"},{\"internalType\":\"uint32\",\"name\":\"secondsOutside\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"initialized\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"token0\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"token1\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]' var abiFactory = '[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint24\",\"name\":\"fee\",\"type\":\"uint24\"},{\"indexed\":true,\"internalType\":\"int24\",\"name\":\"tickSpacing\",\"type\":\"int24\"}],\"name\":\"FeeAmountEnabled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oldOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnerChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token0\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token1\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint24\",\"name\":\"fee\",\"type\":\"uint24\"},{\"indexed\":false,\"internalType\":\"int24\",\"name\":\"tickSpacing\",\"type\":\"int24\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"pool\",\"type\":\"address\"}],\"name\":\"PoolCreated\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"tokenA\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"tokenB\",\"type\":\"address\"},{\"internalType\":\"uint24\",\"name\":\"fee\",\"type\":\"uint24\"}],\"name\":\"createPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"pool\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint24\",\"name\":\"fee\",\"type\":\"uint24\"},{\"internalType\":\"int24\",\"name\":\"tickSpacing\",\"type\":\"int24\"}],\"name\":\"enableFeeAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint24\",\"name\":\"\",\"type\":\"uint24\"}],\"name\":\"feeAmountTickSpacing\",\"outputs\":[{\"internalType\":\"int24\",\"name\":\"\",\"type\":\"int24\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint24\",\"name\":\"\",\"type\":\"uint24\"}],\"name\":\"getPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"parameters\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"factory\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"token0\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"token1\",\"type\":\"address\"},{\"internalType\":\"uint24\",\"name\":\"fee\",\"type\":\"uint24\"},{\"internalType\":\"int24\",\"name\":\"tickSpacing\",\"type\":\"int24\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"setOwner\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]' var contractV3FactoryAddress = "0x1F98431c8aD98523631AE4a59f267346ea31F984" var contractV3SwapRouterV2Address = "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45" function toAmount(s, decimals) { return Number((BigDecimal(BigInt(s)) / BigDecimal(Math.pow(10, decimals))).toString()) } function toInnerAmount(n, decimals) { return (BigDecimal(n) * BigDecimal(Math.pow(10, decimals))).toFixed(0) } function main() { // 注册Uniswap工厂合约的ABI exchange.IO("abi", contractV3FactoryAddress, abiFactory) // 注册Uniswap路由合约的ABI exchange.IO("abi", contractV3SwapRouterV2Address, abiRoute) // 获取交易对的池地址 var tokenIn = {name : "1INCH", address: "0x111111111117dC0aa78b770fA6A738034120C302", decimals: exchange.IO("api", "0x111111111117dC0aa78b770fA6A738034120C302", "decimals")} var tokenOut = {name : "WETH", address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", decimals: exchange.IO("api", "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "decimals")} var poolAddress = exchange.IO("api", contractV3FactoryAddress, "getPool", tokenIn.address, tokenOut.address, 10000) // 注册池合约ABI exchange.IO("abi", poolAddress, abiPool) // 获取当前配置的钱包地址 var walletAddress = exchange.IO("address") // 1INCH -> WETH, tokenIn: 1INCH var allowanceAmount = exchange.IO("api", tokenIn.address, "allowance", walletAddress, contractV3SwapRouterV2Address) Log("allowanceAmount:", allowanceAmount, ", 使用toAmount()函数转换为可读数值:", toAmount(allowanceAmount, tokenIn.decimals)) var balance = exchange.IO("api", "0x111111111117dC0aa78b770fA6A738034120C302", "balanceOf", walletAddress) var balanceOf1INCH = toAmount(balance, tokenIn.decimals) Log("balanceOf1INCH:", balanceOf1INCH) var swapAmount = 38 if (balanceOf1INCH < swapAmount) { Log("钱包中", tokenIn.name, "不足,数量只有:", balanceOf1INCH) } if (toAmount(allowanceAmount, tokenIn.decimals) < swapAmount) { Log("授权数量不足,进行授权") // 也可以指定授权数量为无限,即把代码中toInnerAmount(swapAmount, tokenIn.decimals) 替换为 '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' var txApprove = exchange.IO("api", tokenIn.address, "approve", contractV3SwapRouterV2Address, toInnerAmount(swapAmount, tokenIn.decimals)) if (!txApprove) { Log("授权失败") } else { for (var i = 0; i < 10; i++) { Sleep(5000) var info = exchange.IO("api", "eth", "eth_getTransactionReceipt", txApprove) if (info && info.gasUsed) { Log("info:", info) break } Log('Transaction not yet mined', txApprove) } // 再次查询授权数量 allowanceAmount = exchange.IO("api", tokenIn.address, "allowance", walletAddress, contractV3SwapRouterV2Address) Log("再次查询授权数量,", "allowanceAmount:", allowanceAmount, ", 使用toAmount()函数转换为可读数值:", toAmount(allowanceAmount, tokenIn.decimals)) } } }

img

追加しましたtoInnerAmount()カスタム関数の実装。この関数は以前のコースで頻繁に使用されているため、ここでは詳細には説明しません。
承認レコードを確認し、コードを再度呼び出して承認ステータスを確認できます。

javascript
allowanceAmount = exchange.IO("api", tokenIn.address, "allowance", walletAddress, contractV3SwapRouterV2Address) Log("再次查询授权数量,", "allowanceAmount:", allowanceAmount, ", 使用toAmount()函数转换为可读数值:", toAmount(allowanceAmount, tokenIn.decimals))

img

Uniswapを使用したトークンスワップ

ウォレットに支払うのに十分なトークンがある場合(つまりtokenIn)、そして承認Uniswapルーティング コントラクトに十分な操作があれば、交換を実行できます。
Uniswapルーティング契約には複数の償還方法があり、ここで説明します。exactInput方法、実際の交換プールは1INCH/WETH、交換して再度使用するunwrapWETH9WETH を ETH に解凍する方法。この概念については、前の ERC20 の章で説明しました。withdraw説明文に記載されています。

交換操作は主に3つの方法を使用します。exactInputunwrapWETH9multicall、まずUniswapルーティング契約exactInputメソッド呼び出し、unwrapWETH9メソッド呼び出しコードはルーティングコントラクトによって使用される。multicallメソッドのバッチ実行。

javascript
// 兑换 var recipientAddress = "0x0000000000000000000000000000000000000002" // 如果最终兑换到手的是ETH或者WETH,需要把exactInput方法的recipient参数指定为"0x0000000000000000000000000000000000000002" var fee = exchange.IO("encodePacked", "uint24", 10000) var path = tokenIn.address.slice(2).toLowerCase() + fee + tokenOut.address.slice(2).toLowerCase() var minOut = 1 var amountIn = toInnerAmount(swapAmount, tokenIn.decimals) var swapToken = exchange.IO("encode", contractV3SwapRouterV2Address, "exactInput", { path: path, recipient: recipientAddress, amountIn: amountIn, amountOutMinimum: minOut }) var data = [swapToken] data.push(exchange.IO("encode", contractV3SwapRouterV2Address, "unwrapWETH9(uint256,address)", 1, walletAddress)) var tx = exchange.IO("api", contractV3SwapRouterV2Address, "multicall(uint256,bytes[])", 0, (new Date().getTime() / 1000) + 3600, data) Log("tx:", tx)
  • 使用exchange.IO("encodePacked", ...)この関数はレートパラメータをエンコードして圧縮します。
  • によるとexactInputメソッドパラメータ要件、構築パスパラメータpath
  • 使用exchange.IO("encode", ...)関数エンコーディングexactInputメソッド呼び出し。
    注意: 最終交換が ETH または WETH の場合、exactInput メソッドの受信者パラメータを「0x0000000000000000000000000000000000000000000000002」として指定する必要があります。
  • 使用exchange.IO("encode", ...)関数エンコーディングunwrapWETH9(uint256,address)メソッド呼び出し。
  • 使用multicall(uint256,bytes[])メソッドは上記でコード化された関数呼び出しを実行します。

交換結果を照会します。

img

完全なコード:

javascript
var abiRoute = '[{"inputs":[{"internalType":"address","name":"_factoryV2","type":"address"},{"internalType":"address","name":"factoryV3","type":"address"},{"internalType":"address","name":"_positionManager","type":"address"},{"internalType":"address","name":"_WETH9","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"WETH9","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"approveMax","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"approveMaxMinusOne","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"approveZeroThenMax","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"approveZeroThenMaxMinusOne","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"callPositionManager","outputs":[{"internalType":"bytes","name":"result","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"paths","type":"bytes[]"},{"internalType":"uint128[]","name":"amounts","type":"uint128[]"},{"internalType":"uint24","name":"maximumTickDivergence","type":"uint24"},{"internalType":"uint32","name":"secondsAgo","type":"uint32"}],"name":"checkOracleSlippage","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"path","type":"bytes"},{"internalType":"uint24","name":"maximumTickDivergence","type":"uint24"},{"internalType":"uint32","name":"secondsAgo","type":"uint32"}],"name":"checkOracleSlippage","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"path","type":"bytes"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMinimum","type":"uint256"}],"internalType":"struct IV3SwapRouter.ExactInputParams","name":"params","type":"tuple"}],"name":"exactInput","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMinimum","type":"uint256"},{"internalType":"uint160","name":"sqrtPriceLimitX96","type":"uint160"}],"internalType":"struct IV3SwapRouter.ExactInputSingleParams","name":"params","type":"tuple"}],"name":"exactInputSingle","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"path","type":"bytes"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMaximum","type":"uint256"}],"internalType":"struct IV3SwapRouter.ExactOutputParams","name":"params","type":"tuple"}],"name":"exactOutput","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMaximum","type":"uint256"},{"internalType":"uint160","name":"sqrtPriceLimitX96","type":"uint160"}],"internalType":"struct IV3SwapRouter.ExactOutputSingleParams","name":"params","type":"tuple"}],"name":"exactOutputSingle","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"factoryV2","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"getApprovalType","outputs":[{"internalType":"enum IApproveAndCall.ApprovalType","name":"","type":"uint8"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"amount0Min","type":"uint256"},{"internalType":"uint256","name":"amount1Min","type":"uint256"}],"internalType":"struct IApproveAndCall.IncreaseLiquidityParams","name":"params","type":"tuple"}],"name":"increaseLiquidity","outputs":[{"internalType":"bytes","name":"result","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"int24","name":"tickLower","type":"int24"},{"internalType":"int24","name":"tickUpper","type":"int24"},{"internalType":"uint256","name":"amount0Min","type":"uint256"},{"internalType":"uint256","name":"amount1Min","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"internalType":"struct IApproveAndCall.MintParams","name":"params","type":"tuple"}],"name":"mint","outputs":[{"internalType":"bytes","name":"result","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"previousBlockhash","type":"bytes32"},{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"positionManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"pull","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"refundETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"selfPermit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"selfPermitAllowed","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"selfPermitAllowedIfNecessary","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"selfPermitIfNecessary","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"}],"name":"swapExactTokensForTokens","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"}],"name":"swapTokensForExactTokens","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepToken","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountMinimum","type":"uint256"}],"name":"sweepToken","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"uint256","name":"feeBips","type":"uint256"},{"internalType":"address","name":"feeRecipient","type":"address"}],"name":"sweepTokenWithFee","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"feeBips","type":"uint256"},{"internalType":"address","name":"feeRecipient","type":"address"}],"name":"sweepTokenWithFee","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"int256","name":"amount0Delta","type":"int256"},{"internalType":"int256","name":"amount1Delta","type":"int256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"uniswapV3SwapCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"unwrapWETH9","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountMinimum","type":"uint256"}],"name":"unwrapWETH9","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"feeBips","type":"uint256"},{"internalType":"address","name":"feeRecipient","type":"address"}],"name":"unwrapWETH9WithFee","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"uint256","name":"feeBips","type":"uint256"},{"internalType":"address","name":"feeRecipient","type":"address"}],"name":"unwrapWETH9WithFee","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"wrapETH","outputs":[],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]'; var abiPool = '[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"int24\",\"name\":\"tickLower\",\"type\":\"int24\"},{\"indexed\":true,\"internalType\":\"int24\",\"name\":\"tickUpper\",\"type\":\"int24\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"}],\"name\":\"Burn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"int24\",\"name\":\"tickLower\",\"type\":\"int24\"},{\"indexed\":true,\"internalType\":\"int24\",\"name\":\"tickUpper\",\"type\":\"int24\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"amount0\",\"type\":\"uint128\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"amount1\",\"type\":\"uint128\"}],\"name\":\"Collect\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"amount0\",\"type\":\"uint128\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"amount1\",\"type\":\"uint128\"}],\"name\":\"CollectProtocol\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"paid0\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"paid1\",\"type\":\"uint256\"}],\"name\":\"Flash\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"observationCardinalityNextOld\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"observationCardinalityNextNew\",\"type\":\"uint16\"}],\"name\":\"IncreaseObservationCardinalityNext\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint160\",\"name\":\"sqrtPriceX96\",\"type\":\"uint160\"},{\"indexed\":false,\"internalType\":\"int24\",\"name\":\"tick\",\"type\":\"int24\"}],\"name\":\"Initialize\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"int24\",\"name\":\"tickLower\",\"type\":\"int24\"},{\"indexed\":true,\"internalType\":\"int24\",\"name\":\"tickUpper\",\"type\":\"int24\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"}],\"name\":\"Mint\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"feeProtocol0Old\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"feeProtocol1Old\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"feeProtocol0New\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"feeProtocol1New\",\"type\":\"uint8\"}],\"name\":\"SetFeeProtocol\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"amount0\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"amount1\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"uint160\",\"name\":\"sqrtPriceX96\",\"type\":\"uint160\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"liquidity\",\"type\":\"uint128\"},{\"indexed\":false,\"internalType\":\"int24\",\"name\":\"tick\",\"type\":\"int24\"}],\"name\":\"Swap\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"int24\",\"name\":\"tickLower\",\"type\":\"int24\"},{\"internalType\":\"int24\",\"name\":\"tickUpper\",\"type\":\"int24\"},{\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"}],\"name\":\"burn\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"int24\",\"name\":\"tickLower\",\"type\":\"int24\"},{\"internalType\":\"int24\",\"name\":\"tickUpper\",\"type\":\"int24\"},{\"internalType\":\"uint128\",\"name\":\"amount0Requested\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"amount1Requested\",\"type\":\"uint128\"}],\"name\":\"collect\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"amount0\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"amount1\",\"type\":\"uint128\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint128\",\"name\":\"amount0Requested\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"amount1Requested\",\"type\":\"uint128\"}],\"name\":\"collectProtocol\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"amount0\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"amount1\",\"type\":\"uint128\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"factory\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fee\",\"outputs\":[{\"internalType\":\"uint24\",\"name\":\"\",\"type\":\"uint24\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"feeGrowthGlobal0X128\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"feeGrowthGlobal1X128\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"flash\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"observationCardinalityNext\",\"type\":\"uint16\"}],\"name\":\"increaseObservationCardinalityNext\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint160\",\"name\":\"sqrtPriceX96\",\"type\":\"uint160\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"liquidity\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maxLiquidityPerTick\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"int24\",\"name\":\"tickLower\",\"type\":\"int24\"},{\"internalType\":\"int24\",\"name\":\"tickUpper\",\"type\":\"int24\"},{\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"mint\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"observations\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"blockTimestamp\",\"type\":\"uint32\"},{\"internalType\":\"int56\",\"name\":\"tickCumulative\",\"type\":\"int56\"},{\"internalType\":\"uint160\",\"name\":\"secondsPerLiquidityCumulativeX128\",\"type\":\"uint160\"},{\"internalType\":\"bool\",\"name\":\"initialized\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32[]\",\"name\":\"secondsAgos\",\"type\":\"uint32[]\"}],\"name\":\"observe\",\"outputs\":[{\"internalType\":\"int56[]\",\"name\":\"tickCumulatives\",\"type\":\"int56[]\"},{\"internalType\":\"uint160[]\",\"name\":\"secondsPerLiquidityCumulativeX128s\",\"type\":\"uint160[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"positions\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"liquidity\",\"type\":\"uint128\"},{\"internalType\":\"uint256\",\"name\":\"feeGrowthInside0LastX128\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"feeGrowthInside1LastX128\",\"type\":\"uint256\"},{\"internalType\":\"uint128\",\"name\":\"tokensOwed0\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"tokensOwed1\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"token0\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"token1\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"feeProtocol0\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"feeProtocol1\",\"type\":\"uint8\"}],\"name\":\"setFeeProtocol\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"slot0\",\"outputs\":[{\"internalType\":\"uint160\",\"name\":\"sqrtPriceX96\",\"type\":\"uint160\"},{\"internalType\":\"int24\",\"name\":\"tick\",\"type\":\"int24\"},{\"internalType\":\"uint16\",\"name\":\"observationIndex\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"observationCardinality\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"observationCardinalityNext\",\"type\":\"uint16\"},{\"internalType\":\"uint8\",\"name\":\"feeProtocol\",\"type\":\"uint8\"},{\"internalType\":\"bool\",\"name\":\"unlocked\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int24\",\"name\":\"tickLower\",\"type\":\"int24\"},{\"internalType\":\"int24\",\"name\":\"tickUpper\",\"type\":\"int24\"}],\"name\":\"snapshotCumulativesInside\",\"outputs\":[{\"internalType\":\"int56\",\"name\":\"tickCumulativeInside\",\"type\":\"int56\"},{\"internalType\":\"uint160\",\"name\":\"secondsPerLiquidityInsideX128\",\"type\":\"uint160\"},{\"internalType\":\"uint32\",\"name\":\"secondsInside\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"zeroForOne\",\"type\":\"bool\"},{\"internalType\":\"int256\",\"name\":\"amountSpecified\",\"type\":\"int256\"},{\"internalType\":\"uint160\",\"name\":\"sqrtPriceLimitX96\",\"type\":\"uint160\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"swap\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"amount0\",\"type\":\"int256\"},{\"internalType\":\"int256\",\"name\":\"amount1\",\"type\":\"int256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int16\",\"name\":\"\",\"type\":\"int16\"}],\"name\":\"tickBitmap\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"tickSpacing\",\"outputs\":[{\"internalType\":\"int24\",\"name\":\"\",\"type\":\"int24\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int24\",\"name\":\"\",\"type\":\"int24\"}],\"name\":\"ticks\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"liquidityGross\",\"type\":\"uint128\"},{\"internalType\":\"int128\",\"name\":\"liquidityNet\",\"type\":\"int128\"},{\"internalType\":\"uint256\",\"name\":\"feeGrowthOutside0X128\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"feeGrowthOutside1X128\",\"type\":\"uint256\"},{\"internalType\":\"int56\",\"name\":\"tickCumulativeOutside\",\"type\":\"int56\"},{\"internalType\":\"uint160\",\"name\":\"secondsPerLiquidityOutsideX128\",\"type\":\"uint160\"},{\"internalType\":\"uint32\",\"name\":\"secondsOutside\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"initialized\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"token0\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"token1\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]' var abiFactory = '[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint24\",\"name\":\"fee\",\"type\":\"uint24\"},{\"indexed\":true,\"internalType\":\"int24\",\"name\":\"tickSpacing\",\"type\":\"int24\"}],\"name\":\"FeeAmountEnabled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oldOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnerChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token0\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token1\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint24\",\"name\":\"fee\",\"type\":\"uint24\"},{\"indexed\":false,\"internalType\":\"int24\",\"name\":\"tickSpacing\",\"type\":\"int24\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"pool\",\"type\":\"address\"}],\"name\":\"PoolCreated\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"tokenA\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"tokenB\",\"type\":\"address\"},{\"internalType\":\"uint24\",\"name\":\"fee\",\"type\":\"uint24\"}],\"name\":\"createPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"pool\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint24\",\"name\":\"fee\",\"type\":\"uint24\"},{\"internalType\":\"int24\",\"name\":\"tickSpacing\",\"type\":\"int24\"}],\"name\":\"enableFeeAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint24\",\"name\":\"\",\"type\":\"uint24\"}],\"name\":\"feeAmountTickSpacing\",\"outputs\":[{\"internalType\":\"int24\",\"name\":\"\",\"type\":\"int24\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint24\",\"name\":\"\",\"type\":\"uint24\"}],\"name\":\"getPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"parameters\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"factory\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"token0\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"token1\",\"type\":\"address\"},{\"internalType\":\"uint24\",\"name\":\"fee\",\"type\":\"uint24\"},{\"internalType\":\"int24\",\"name\":\"tickSpacing\",\"type\":\"int24\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"setOwner\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]' var contractV3FactoryAddress = "0x1F98431c8aD98523631AE4a59f267346ea31F984" var contractV3SwapRouterV2Address = "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45" function toAmount(s, decimals) { return Number((BigDecimal(BigInt(s)) / BigDecimal(Math.pow(10, decimals))).toString()) } function toInnerAmount(n, decimals) { return (BigDecimal(n) * BigDecimal(Math.pow(10, decimals))).toFixed(0) } function main() { // 注册Uniswap工厂合约的ABI exchange.IO("abi", contractV3FactoryAddress, abiFactory) // 注册Uniswap路由合约的ABI exchange.IO("abi", contractV3SwapRouterV2Address, abiRoute) // 获取交易对的池地址 var tokenIn = {name : "1INCH", address: "0x111111111117dC0aa78b770fA6A738034120C302", decimals: exchange.IO("api", "0x111111111117dC0aa78b770fA6A738034120C302", "decimals")} var tokenOut = {name : "WETH", address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", decimals: exchange.IO("api", "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "decimals")} var poolAddress = exchange.IO("api", contractV3FactoryAddress, "getPool", tokenIn.address, tokenOut.address, 10000) // 注册池合约ABI exchange.IO("abi", poolAddress, abiPool) // 获取当前配置的钱包地址 var walletAddress = exchange.IO("address") // 1INCH -> WETH, tokenIn: 1INCH var allowanceAmount = exchange.IO("api", tokenIn.address, "allowance", walletAddress, contractV3SwapRouterV2Address) Log("allowanceAmount:", allowanceAmount, ", 使用toAmount()函数转换为可读数值:", toAmount(allowanceAmount, tokenIn.decimals)) var balance = exchange.IO("api", "0x111111111117dC0aa78b770fA6A738034120C302", "balanceOf", walletAddress) var balanceOf1INCH = toAmount(balance, tokenIn.decimals) Log("balanceOf1INCH:", balanceOf1INCH) var swapAmount = 38 if (balanceOf1INCH < swapAmount) { Log("钱包中", tokenIn.name, "不足,数量只有:", balanceOf1INCH) } if (toAmount(allowanceAmount, tokenIn.decimals) < swapAmount) { Log("授权数量不足,进行授权") // 也可以指定授权数量为无限,即把代码中toInnerAmount(swapAmount, tokenIn.decimals) 替换为 '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' var txApprove = exchange.IO("api", tokenIn.address, "approve", contractV3SwapRouterV2Address, toInnerAmount(swapAmount, tokenIn.decimals)) if (!txApprove) { Log("授权失败") } else { for (var i = 0; i < 10; i++) { Sleep(5000) var info = exchange.IO("api", "eth", "eth_getTransactionReceipt", txApprove) if (info && info.gasUsed) { Log("info:", info) break } Log('Transaction not yet mined', txApprove) } // 再次查询授权数量 allowanceAmount = exchange.IO("api", tokenIn.address, "allowance", walletAddress, contractV3SwapRouterV2Address) Log("再次查询授权数量,", "allowanceAmount:", allowanceAmount, ", 使用toAmount()函数转换为可读数值:", toAmount(allowanceAmount, tokenIn.decimals)) } } // 兑换 var recipientAddress = "0x0000000000000000000000000000000000000002" var fee = exchange.IO("encodePacked", "uint24", 10000) var path = tokenIn.address.slice(2).toLowerCase() + fee + tokenOut.address.slice(2).toLowerCase() var minOut = 1 var amountIn = toInnerAmount(swapAmount, tokenIn.decimals) var swapToken = exchange.IO("encode", contractV3SwapRouterV2Address, "exactInput", { path: path, recipient: recipientAddress, amountIn: amountIn, amountOutMinimum: minOut }) var data = [swapToken] data.push(exchange.IO("encode", contractV3SwapRouterV2Address, "unwrapWETH9(uint256,address)", 1, walletAddress)) var tx = exchange.IO("api", contractV3SwapRouterV2Address, "multicall(uint256,bytes[])", 0, (new Date().getTime() / 1000) + 3600, data) Log("tx:", tx) }

プール内の交換価格を取得する

前に説明したように、トークンアドレス(tokenInとtokenOutの2つ)とレート設定を使用すると、UniswapFactory契約上のgetPoolこの交換組み合わせの交換プール (スマート コントラクト) アドレスを取得する方法。
交換プールアドレスを取得したら、プールコントラクトのABIを登録します。その後、プール契約を呼び出すことができますslot0現在の為替レートに関連するデータを取得し、さらに為替レートを解析する方法。

javascript
var abiRoute = '[{"inputs":[{"internalType":"address","name":"_factoryV2","type":"address"},{"internalType":"address","name":"factoryV3","type":"address"},{"internalType":"address","name":"_positionManager","type":"address"},{"internalType":"address","name":"_WETH9","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"WETH9","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"approveMax","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"approveMaxMinusOne","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"approveZeroThenMax","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"approveZeroThenMaxMinusOne","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"callPositionManager","outputs":[{"internalType":"bytes","name":"result","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"paths","type":"bytes[]"},{"internalType":"uint128[]","name":"amounts","type":"uint128[]"},{"internalType":"uint24","name":"maximumTickDivergence","type":"uint24"},{"internalType":"uint32","name":"secondsAgo","type":"uint32"}],"name":"checkOracleSlippage","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"path","type":"bytes"},{"internalType":"uint24","name":"maximumTickDivergence","type":"uint24"},{"internalType":"uint32","name":"secondsAgo","type":"uint32"}],"name":"checkOracleSlippage","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"path","type":"bytes"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMinimum","type":"uint256"}],"internalType":"struct IV3SwapRouter.ExactInputParams","name":"params","type":"tuple"}],"name":"exactInput","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMinimum","type":"uint256"},{"internalType":"uint160","name":"sqrtPriceLimitX96","type":"uint160"}],"internalType":"struct IV3SwapRouter.ExactInputSingleParams","name":"params","type":"tuple"}],"name":"exactInputSingle","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"path","type":"bytes"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMaximum","type":"uint256"}],"internalType":"struct IV3SwapRouter.ExactOutputParams","name":"params","type":"tuple"}],"name":"exactOutput","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMaximum","type":"uint256"},{"internalType":"uint160","name":"sqrtPriceLimitX96","type":"uint160"}],"internalType":"struct IV3SwapRouter.ExactOutputSingleParams","name":"params","type":"tuple"}],"name":"exactOutputSingle","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"factoryV2","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"getApprovalType","outputs":[{"internalType":"enum IApproveAndCall.ApprovalType","name":"","type":"uint8"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"amount0Min","type":"uint256"},{"internalType":"uint256","name":"amount1Min","type":"uint256"}],"internalType":"struct IApproveAndCall.IncreaseLiquidityParams","name":"params","type":"tuple"}],"name":"increaseLiquidity","outputs":[{"internalType":"bytes","name":"result","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"int24","name":"tickLower","type":"int24"},{"internalType":"int24","name":"tickUpper","type":"int24"},{"internalType":"uint256","name":"amount0Min","type":"uint256"},{"internalType":"uint256","name":"amount1Min","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"internalType":"struct IApproveAndCall.MintParams","name":"params","type":"tuple"}],"name":"mint","outputs":[{"internalType":"bytes","name":"result","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"previousBlockhash","type":"bytes32"},{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"positionManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"pull","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"refundETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"selfPermit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"selfPermitAllowed","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"selfPermitAllowedIfNecessary","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"selfPermitIfNecessary","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"}],"name":"swapExactTokensForTokens","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"}],"name":"swapTokensForExactTokens","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepToken","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountMinimum","type":"uint256"}],"name":"sweepToken","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"uint256","name":"feeBips","type":"uint256"},{"internalType":"address","name":"feeRecipient","type":"address"}],"name":"sweepTokenWithFee","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"feeBips","type":"uint256"},{"internalType":"address","name":"feeRecipient","type":"address"}],"name":"sweepTokenWithFee","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"int256","name":"amount0Delta","type":"int256"},{"internalType":"int256","name":"amount1Delta","type":"int256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"uniswapV3SwapCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"unwrapWETH9","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountMinimum","type":"uint256"}],"name":"unwrapWETH9","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"feeBips","type":"uint256"},{"internalType":"address","name":"feeRecipient","type":"address"}],"name":"unwrapWETH9WithFee","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"uint256","name":"feeBips","type":"uint256"},{"internalType":"address","name":"feeRecipient","type":"address"}],"name":"unwrapWETH9WithFee","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"wrapETH","outputs":[],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]'; var abiPool = '[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"int24\",\"name\":\"tickLower\",\"type\":\"int24\"},{\"indexed\":true,\"internalType\":\"int24\",\"name\":\"tickUpper\",\"type\":\"int24\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"}],\"name\":\"Burn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"int24\",\"name\":\"tickLower\",\"type\":\"int24\"},{\"indexed\":true,\"internalType\":\"int24\",\"name\":\"tickUpper\",\"type\":\"int24\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"amount0\",\"type\":\"uint128\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"amount1\",\"type\":\"uint128\"}],\"name\":\"Collect\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"amount0\",\"type\":\"uint128\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"amount1\",\"type\":\"uint128\"}],\"name\":\"CollectProtocol\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"paid0\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"paid1\",\"type\":\"uint256\"}],\"name\":\"Flash\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"observationCardinalityNextOld\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"observationCardinalityNextNew\",\"type\":\"uint16\"}],\"name\":\"IncreaseObservationCardinalityNext\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint160\",\"name\":\"sqrtPriceX96\",\"type\":\"uint160\"},{\"indexed\":false,\"internalType\":\"int24\",\"name\":\"tick\",\"type\":\"int24\"}],\"name\":\"Initialize\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"int24\",\"name\":\"tickLower\",\"type\":\"int24\"},{\"indexed\":true,\"internalType\":\"int24\",\"name\":\"tickUpper\",\"type\":\"int24\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"}],\"name\":\"Mint\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"feeProtocol0Old\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"feeProtocol1Old\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"feeProtocol0New\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"feeProtocol1New\",\"type\":\"uint8\"}],\"name\":\"SetFeeProtocol\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"amount0\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"int256\",\"name\":\"amount1\",\"type\":\"int256\"},{\"indexed\":false,\"internalType\":\"uint160\",\"name\":\"sqrtPriceX96\",\"type\":\"uint160\"},{\"indexed\":false,\"internalType\":\"uint128\",\"name\":\"liquidity\",\"type\":\"uint128\"},{\"indexed\":false,\"internalType\":\"int24\",\"name\":\"tick\",\"type\":\"int24\"}],\"name\":\"Swap\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"int24\",\"name\":\"tickLower\",\"type\":\"int24\"},{\"internalType\":\"int24\",\"name\":\"tickUpper\",\"type\":\"int24\"},{\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"}],\"name\":\"burn\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"int24\",\"name\":\"tickLower\",\"type\":\"int24\"},{\"internalType\":\"int24\",\"name\":\"tickUpper\",\"type\":\"int24\"},{\"internalType\":\"uint128\",\"name\":\"amount0Requested\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"amount1Requested\",\"type\":\"uint128\"}],\"name\":\"collect\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"amount0\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"amount1\",\"type\":\"uint128\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint128\",\"name\":\"amount0Requested\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"amount1Requested\",\"type\":\"uint128\"}],\"name\":\"collectProtocol\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"amount0\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"amount1\",\"type\":\"uint128\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"factory\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"fee\",\"outputs\":[{\"internalType\":\"uint24\",\"name\":\"\",\"type\":\"uint24\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"feeGrowthGlobal0X128\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"feeGrowthGlobal1X128\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"flash\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"observationCardinalityNext\",\"type\":\"uint16\"}],\"name\":\"increaseObservationCardinalityNext\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint160\",\"name\":\"sqrtPriceX96\",\"type\":\"uint160\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"liquidity\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maxLiquidityPerTick\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"int24\",\"name\":\"tickLower\",\"type\":\"int24\"},{\"internalType\":\"int24\",\"name\":\"tickUpper\",\"type\":\"int24\"},{\"internalType\":\"uint128\",\"name\":\"amount\",\"type\":\"uint128\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"mint\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"observations\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"blockTimestamp\",\"type\":\"uint32\"},{\"internalType\":\"int56\",\"name\":\"tickCumulative\",\"type\":\"int56\"},{\"internalType\":\"uint160\",\"name\":\"secondsPerLiquidityCumulativeX128\",\"type\":\"uint160\"},{\"internalType\":\"bool\",\"name\":\"initialized\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32[]\",\"name\":\"secondsAgos\",\"type\":\"uint32[]\"}],\"name\":\"observe\",\"outputs\":[{\"internalType\":\"int56[]\",\"name\":\"tickCumulatives\",\"type\":\"int56[]\"},{\"internalType\":\"uint160[]\",\"name\":\"secondsPerLiquidityCumulativeX128s\",\"type\":\"uint160[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"positions\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"liquidity\",\"type\":\"uint128\"},{\"internalType\":\"uint256\",\"name\":\"feeGrowthInside0LastX128\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"feeGrowthInside1LastX128\",\"type\":\"uint256\"},{\"internalType\":\"uint128\",\"name\":\"tokensOwed0\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"tokensOwed1\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"protocolFees\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"token0\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"token1\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"feeProtocol0\",\"type\":\"uint8\"},{\"internalType\":\"uint8\",\"name\":\"feeProtocol1\",\"type\":\"uint8\"}],\"name\":\"setFeeProtocol\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"slot0\",\"outputs\":[{\"internalType\":\"uint160\",\"name\":\"sqrtPriceX96\",\"type\":\"uint160\"},{\"internalType\":\"int24\",\"name\":\"tick\",\"type\":\"int24\"},{\"internalType\":\"uint16\",\"name\":\"observationIndex\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"observationCardinality\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"observationCardinalityNext\",\"type\":\"uint16\"},{\"internalType\":\"uint8\",\"name\":\"feeProtocol\",\"type\":\"uint8\"},{\"internalType\":\"bool\",\"name\":\"unlocked\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int24\",\"name\":\"tickLower\",\"type\":\"int24\"},{\"internalType\":\"int24\",\"name\":\"tickUpper\",\"type\":\"int24\"}],\"name\":\"snapshotCumulativesInside\",\"outputs\":[{\"internalType\":\"int56\",\"name\":\"tickCumulativeInside\",\"type\":\"int56\"},{\"internalType\":\"uint160\",\"name\":\"secondsPerLiquidityInsideX128\",\"type\":\"uint160\"},{\"internalType\":\"uint32\",\"name\":\"secondsInside\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"zeroForOne\",\"type\":\"bool\"},{\"internalType\":\"int256\",\"name\":\"amountSpecified\",\"type\":\"int256\"},{\"internalType\":\"uint160\",\"name\":\"sqrtPriceLimitX96\",\"type\":\"uint160\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"swap\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"amount0\",\"type\":\"int256\"},{\"internalType\":\"int256\",\"name\":\"amount1\",\"type\":\"int256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int16\",\"name\":\"\",\"type\":\"int16\"}],\"name\":\"tickBitmap\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"tickSpacing\",\"outputs\":[{\"internalType\":\"int24\",\"name\":\"\",\"type\":\"int24\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int24\",\"name\":\"\",\"type\":\"int24\"}],\"name\":\"ticks\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"liquidityGross\",\"type\":\"uint128\"},{\"internalType\":\"int128\",\"name\":\"liquidityNet\",\"type\":\"int128\"},{\"internalType\":\"uint256\",\"name\":\"feeGrowthOutside0X128\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"feeGrowthOutside1X128\",\"type\":\"uint256\"},{\"internalType\":\"int56\",\"name\":\"tickCumulativeOutside\",\"type\":\"int56\"},{\"internalType\":\"uint160\",\"name\":\"secondsPerLiquidityOutsideX128\",\"type\":\"uint160\"},{\"internalType\":\"uint32\",\"name\":\"secondsOutside\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"initialized\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"token0\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"token1\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]' var abiFactory = '[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint24\",\"name\":\"fee\",\"type\":\"uint24\"},{\"indexed\":true,\"internalType\":\"int24\",\"name\":\"tickSpacing\",\"type\":\"int24\"}],\"name\":\"FeeAmountEnabled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oldOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnerChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token0\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token1\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint24\",\"name\":\"fee\",\"type\":\"uint24\"},{\"indexed\":false,\"internalType\":\"int24\",\"name\":\"tickSpacing\",\"type\":\"int24\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"pool\",\"type\":\"address\"}],\"name\":\"PoolCreated\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"tokenA\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"tokenB\",\"type\":\"address\"},{\"internalType\":\"uint24\",\"name\":\"fee\",\"type\":\"uint24\"}],\"name\":\"createPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"pool\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint24\",\"name\":\"fee\",\"type\":\"uint24\"},{\"internalType\":\"int24\",\"name\":\"tickSpacing\",\"type\":\"int24\"}],\"name\":\"enableFeeAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint24\",\"name\":\"\",\"type\":\"uint24\"}],\"name\":\"feeAmountTickSpacing\",\"outputs\":[{\"internalType\":\"int24\",\"name\":\"\",\"type\":\"int24\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint24\",\"name\":\"\",\"type\":\"uint24\"}],\"name\":\"getPool\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"parameters\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"factory\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"token0\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"token1\",\"type\":\"address\"},{\"internalType\":\"uint24\",\"name\":\"fee\",\"type\":\"uint24\"},{\"internalType\":\"int24\",\"name\":\"tickSpacing\",\"type\":\"int24\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"setOwner\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]' var contractV3FactoryAddress = "0x1F98431c8aD98523631AE4a59f267346ea31F984" var contractV3SwapRouterV2Address = "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45" function toAmount(s, decimals) { return Number((BigDecimal(BigInt(s)) / BigDecimal(Math.pow(10, decimals))).toString()) } function toInnerAmount(n, decimals) { return (BigDecimal(n) * BigDecimal(Math.pow(10, decimals))).toFixed(0) } function main() { // 注册Uniswap工厂合约的ABI exchange.IO("abi", contractV3FactoryAddress, abiFactory) // 注册Uniswap路由合约的ABI exchange.IO("abi", contractV3SwapRouterV2Address, abiRoute) // 获取交易对的池地址 var tokenIn = {name : "1INCH", address: "0x111111111117dC0aa78b770fA6A738034120C302", decimals: exchange.IO("api", "0x111111111117dC0aa78b770fA6A738034120C302", "decimals")} var tokenOut = {name : "WETH", address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", decimals: exchange.IO("api", "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "decimals")} var poolAddress = exchange.IO("api", contractV3FactoryAddress, "getPool", tokenIn.address, tokenOut.address, 10000) // 注册池合约ABI exchange.IO("abi", poolAddress, abiPool) var slot0 = exchange.IO("api", poolAddress, "slot0") Log("slot0:", slot0) }

交換プールの価格情報を取得し、コードを印刷しますslot0変数:

javascript
{ "feeProtocol":0, "unlocked":true, "sqrtPriceX96":"1128983883551457130720648561", "tick":"-85025", "observationIndex":5, "observationCardinality":6, "observationCardinalityNext":6 }

主な価格情報データは、sqrtPriceX96フィールドでは、交換プールの現在の価格は、交換組み合わせのトークン精度データに基づいて計算する必要があります。Uniswapドキュメントに記載されているように、次の計算を行う関数を実装します。

javascript
function computePoolPrice(decimals0, decimals1, sqrtPriceX96) { // sqrtPriceX96 = sqrt(price) * 2^96 [decimals0, decimals1, sqrtPriceX96] = [decimals0, decimals1, sqrtPriceX96].map(BigInt); const TWO = BigInt(2); const TEN = BigInt(10); const SIX_TENTH = BigInt(1000000); const Q192 = (TWO ** BigInt(96)) ** TWO; return ( Number((sqrtPriceX96 ** TWO * TEN ** decimals0 * SIX_TENTH) / (Q192 * TEN ** decimals1)) / Number(SIX_TENTH) ); }

この関数を使用してトークンの組み合わせを計算します。1INCH/WETH、手数料 10,000 の交換プールの現在の価格。

javascript
function computePoolPrice(decimals0, decimals1, sqrtPriceX96) { // sqrtPriceX96 = sqrt(price) * 2^96 [decimals0, decimals1, sqrtPriceX96] = [decimals0, decimals1, sqrtPriceX96].map(BigInt); const TWO = BigInt(2); const TEN = BigInt(10); const SIX_TENTH = BigInt(1000000); const Q192 = (TWO ** BigInt(96)) ** TWO; return ( Number((sqrtPriceX96 ** TWO * TEN ** decimals0 * SIX_TENTH) / (Q192 * TEN ** decimals1)) / Number(SIX_TENTH) ); } function main() { var tokenIn = {name : "1INCH", address: "0x111111111117dC0aa78b770fA6A738034120C302", decimals: exchange.IO("api", "0x111111111117dC0aa78b770fA6A738034120C302", "decimals")} var tokenOut = {name : "WETH", address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", decimals: exchange.IO("api", "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "decimals")} // 获取的slot0变量中"sqrtPriceX96":"1128983883551457130720648561", var price = computePoolPrice(tokenIn.decimals, tokenOut.decimals, "1128983883551457130720648561") Log("price:", price) }

変数の印刷price見せる:price: 0.000203(1 1INCH は 0.000203 WETH に換算されます)。

Uniswap V3 トレーディングライブラリ

定量取引プラットフォームの発明者は、パッケージ化されたUniswapテンプレート交換、価格取得、ウォレット残高照会などの機能を実現しています。上記で説明した内容に従ってコードを繰り返す必要はありません。このテンプレートのソースコードを読んで、より深く学び、Web3アプリケーションを開発することができます。 。
このテンプレート ライブラリには、学ぶ価値のある詳細が多数あります。

  • トークン情報を自動的に取得する
    コードの一部を取り上げて説明します。テンプレートのパラメータがAutoFetchTokenstrueに設定すると、テンプレートプログラムは自動的にhttps://tokens.coingecko.com/uniswap/all.jsonすべてのトークン情報をリンク、取得し、自動的に処理します。この方法では、戦略コードにトークンを手動で追加する必要はありません(そうでない場合は、addToken(name, address)トークンを追加します。

    javascript
    if (AutoFetchTokens) { let res = JSON.parse(HttpQuery("https://tokens.coingecko.com/uniswap/all.json")) Log("fetch", res.tokens.length, "tokens from", res.name) res.tokens.forEach(function(token) { if (token.chainId == chainId && token.symbol != "WETH") { self.tokenInfo[token.symbol] = { name: token.symbol, decimals: token.decimals, address: token.address } } }) }
  • チェーン設定に応じて異なるコントラクトアドレスを適応させる
    このテンプレートはChainTypeパラメータ、複数のチェーンの切り替えをサポート:

    desc
    'https://rpc.ankr.com/eth', 'https://arb1.arbitrum.io/rpc', 'https://mainnet.optimism.io/', 'https://rpc.ankr.com/avalanche', 'https://polygon-rpc.com', 'https://rpc.ankr.com/celo',

    抜粋コード:

    javascript
    if (typeof(ChainType) === 'number') { let chainRpc = [ '', 'https://rpc.ankr.com/eth', 'https://arb1.arbitrum.io/rpc', 'https://mainnet.optimism.io/', 'https://rpc.ankr.com/avalanche', 'https://polygon-rpc.com', 'https://rpc.ankr.com/celo', //'https://mainnet.aurora.dev', //'https://bsc-dataseed.binance.org', //'https://exchainrpc.okex.org' ][ChainType] if (chainRpc && chainRpc.length > 0) { e.IO("base", chainRpc) Log("change base rpc to", chainRpc) } }

    EthereumのRPCメソッドの呼び出しeth_chainId現在のクエリchainId、そしてそれに従ってchainIdWETHアドレスを適応させるには、Uniswap一連の契約アドレス、USDTスマート コントラクトのコントラクト アドレスは、チェーンごとに異なる場合があります。

    抜粋コード:

    javascript
    // https://docs.uniswap.org/contracts/v3/reference/deployments let WETHAddress = { 1: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", // Ethereum 3: "0xc778417E063141139Fce010982780140Aa0cD5Ab", // Ropsten 4: "0xc778417E063141139Fce010982780140Aa0cD5Ab", // Rinkeby 5: "0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6", // Goerli 42: "0xd0A1E359811322d97991E03f863a0C30C2cF029C", // Kovan 10: "0x4200000000000000000000000000000000000006", // Optimism 69: "0x4200000000000000000000000000000000000006", // Optimistic Kovan 42161: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1", // Arbitrum One 421611: "0xB47e6A5f8b33b3F17603C83a0535A9dcD7E32681", // Arbitrum Rinkeby 137: "0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270", // Polygon 80001: "0x9c3C9283D3e44854697Cd22D3Faa240Cfb032889", // Polygon Mumbai } let chainId = e.IO("api", "ETH", "eth_chainId") if (chainId) { chainId = Number(chainId) Log("chainId: ", chainId) let addr = WETHAddress[chainId] if (addr) { Log("Register WETH address", addr) self.addToken("ETH", addr) } if (chainId == 42220) { // Celo Address ContractV3Factory = '0xAfE208a311B21f13EF87E33A90049fC17A7acDEc' ContractV3SwapRouterV2 = '0x5615CDAb10dc425a742d643d949a7F474C01abc4' self.addToken('CELO', '0x471ece3750da237f93b8e339c536989b8978a438') } else if (chainId == 42161) { self.addToken('USDT', '0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9') } } else { panic("get chain Id error") }
  • 「Uniswap V3 Trading Library」の使用

    このテンプレートでは$.testUniswap()この関数は、テンプレートの機能をテストする関数です。このコードには、テンプレート呼び出しの使用方法の例が示されています。

    javascript
    $.testUniswap = function() { let ex = $.NewUniswapV3() Log("walletAddress: ", ex.walletAddress) let tokenAddressMap = { "USDT": "0xdac17f958d2ee523a2206206994597c13d831ec7", "1INCH": "0x111111111117dC0aa78b770fA6A738034120C302", "USDC": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "DAI": "0x6b175474e89094c44da98b954eedeac495271d0f", } for (let name in tokenAddressMap) { ex.addToken(name, tokenAddressMap[name]) } Log(ex.getPrice('ETH_USDT')) Log(ex.getPrice('1INCH_USDT')) // swap 0.01 ETH to USDT Log(ex.swapToken('ETH', 0.01, 'USDT')) let usdtBalance = ex.balanceOf('USDT') Log("balance of USDT", usdtBalance) // swap USDT to DAI then DAI to ETH Log(ex.swapToken('USDT', usdtBalance, 'DAI,ETH')) Log("balance of ETH", ex.getETHBalance()) // Log(ex.sendETH('0x11111', 0.02)) // ... }

    戦略が「Uniswap V3 Trading Library」を参照する場合(テンプレートライブラリの参照方法については、FMZ プラットフォームのドキュメントを参照してください)、このテンプレートライブラリ内のカプセル化された関数を呼び出すことができます。

    というファイルを作成しますex変数は、「Uniswap V3 Trading Library」テンプレートによってカプセル化されたインターフェース関数を呼び出します。$.NewUniswapV3()オブジェクトを作成し、割り当てるex

    javascript
    let ex = $.NewUniswapV3()

    使用exオブジェクトのメンバー関数addToken()トークン情報を追加(登録)します。

    javascript
    let tokenAddressMap = { "USDT": "0xdac17f958d2ee523a2206206994597c13d831ec7", "1INCH": "0x111111111117dC0aa78b770fA6A738034120C302", "USDC": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "DAI": "0x6b175474e89094c44da98b954eedeac495271d0f", } for (let name in tokenAddressMap) { ex.addToken(name, tokenAddressMap[name]) }

    特定の取引ペアの交換プール価格を取得して印刷したい場合は、次のようにします。exオブジェクトのメンバー関数getPrice()次のように書くことができます。

    javascript
    Log(ex.getPrice('ETH_USDT')) Log(ex.getPrice('1INCH_USDT'))

    償還操作を実行する場合は、exオブジェクトのメンバー関数swapToken()交換を実行します:

    javascript
    // swap 0.01 ETH to USDT Log(ex.swapToken('ETH', 0.01, 'USDT')) let usdtBalance = ex.balanceOf('USDT') Log("balance of USDT", usdtBalance) // swap USDT to DAI then DAI to ETH Log(ex.swapToken('USDT', usdtBalance, 'DAI,ETH'))

イベントを取得する

この章では、Inventor Quantitative Trading Platform を使用してスマート コントラクトによってリリースされたイベントを読み取る方法を学習します。スマート コントラクトによってリリースされたイベントは、Ethereum 仮想マシンのログに保存されます。

eth_getLogs

スマートコントラクトによってリリースされたイベントを照会するには、EthereumのRPCメソッドを使用する必要があります。eth_getLogs、オンチェーン ログ データを取得します。Ethereum RPC ノードを呼び出す方法については、前回のコースですでに説明しました。
例えば、WETH契約イベントはFMZを使用してコード化できるデバッグツールテストでは、交換オブジェクトによって構成されたRPCノードは、Ethereumのメインネットワークノードであり、eth_getLogsメソッドを使用する際に3つのパラメータを指定した。fromBlocktoBlockaddressでは、fromBlock および toBlock パラメータを使用して、クエリをブロック内のデータに制限します。

javascript
function toAmount(s, decimals) { return Number((BigDecimal(BigInt(s)) / BigDecimal(Math.pow(10, decimals))).toString()) } function toInnerAmount(n, decimals) { return (BigDecimal(n) * BigDecimal(Math.pow(10, decimals))).toFixed(0) } function main() { // getBlockNumber var blockNumber = exchange.IO("api", "eth", "eth_blockNumber") Log("blockNumber:", blockNumber) // get logs var fromBlock = "0x" + (toAmount(blockNumber, 0) - 1).toString(16) var toBlock = "0x" + toAmount(blockNumber, 0).toString(16) var params = { "fromBlock" : fromBlock, "toBlock" : toBlock, "address" : "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" // WETH合约的地址 } var logs = exchange.IO("api", "eth", "eth_getLogs", params) // 由于数据量比较大,如果使用Log函数打印,数据会被截断。使用return将完整数据返回在页面「函数结果」编辑框中 return logs }

ログデータを取得します。データが大きいため、一部の内容を省略します。

javascript
[{ "data": "0x00000000000000000000000000000000000000000000000001c1a55000000000", "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x0000000000000000000000006b75d8af000000e20b7a7ddf000ba900b4009a80", "0x000000000000000000000000bcb095c1f9c3dc02e834976706c87dee5d0f1fb6"], "transactionHash": "0x27f9bf5abe3148169b4b85a83e1de32bd50eb81ecc52e5af006157d93353e4c4", "transactionIndex": "0x0", "removed": false, "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "blockHash": "0x847be24a7b159c292bda030a011dfec89487b70e71eed486969b032d6ef04bad", "blockNumber": "0x109b1cc", "logIndex": "0x0" }, { "data": "0x00000000000000000000000000000000000000000000000008ea20cdea027c00", "logIndex": "0x5", "topics": ["0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c", "0x0000000000000000000000007a250d5630b4cf539739df2c5dacb4c659f2488d"], "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "blockHash": "0x847be24a7b159c292bda030a011dfec89487b70e71eed486969b032d6ef04bad", "blockNumber": "0x109b1cc", "removed": false, "transactionHash": "0xace3afa02e8af5d1ef6fc1635fbdf7bee37624547937ea5272c23968dd034c09", "transactionIndex": "0x1" }, ... { "blockNumber": "0x109b1cd", "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "data": "0x00000000000000000000000000000000000000000000000002c053531ab8a000", "logIndex": "0xd3", "removed": false, "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x0000000000000000000000001111111254eeb25477b68fb85ed929f73a960582", "0x000000000000000000000000252ba9b5916171dbdadd2cec7f91875a006955d0"], "transactionHash": "0x3012b82891f85b077cfe1c12cb9722b93c696ef2c37d67981ccddcc9c3396aca", "transactionIndex": "0x8d", "blockHash": "0xcd3d567c9bd02a4549b1de0dc638ab5523e847c3c156b096424f56c633000fd9" }, { "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x00000000000000000000000012b791bb27b3a4ee958b5a435fea7d49ec076e9c", "0x000000000000000000000000ef1c6e67703c7bd7107eed8303fbe6ec2554bf6b"], "transactionIndex": "0x91", "logIndex": "0xdb", "removed": false, "blockNumber": "0x109b1cd", "data": "0x0000000000000000000000000000000000000000000000000164f2434262e1cc", "transactionHash": "0x6aa8d80daf42f442591e7530e31323d05e1d6dd9f9f9b9c102e157d89810c048", "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "blockHash": "0xcd3d567c9bd02a4549b1de0dc638ab5523e847c3c156b096424f56c633000fd9" }, { "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "blockHash": "0xcd3d567c9bd02a4549b1de0dc638ab5523e847c3c156b096424f56c633000fd9", "blockNumber": "0x109b1cd", "logIndex": "0xde", "removed": false, "topics": ["0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65", "0x000000000000000000000000ef1c6e67703c7bd7107eed8303fbe6ec2554bf6b"], "data": "0x0000000000000000000000000000000000000000000000000164f2434262e1cc", "transactionHash": "0x6aa8d80daf42f442591e7530e31323d05e1d6dd9f9f9b9c102e157d89810c048", "transactionIndex": "0x91" }]

ログデータにはさまざまなイベントがあることがわかります。TransferイベントではこれらのデータをTransferイベントは除外されます。

ログを取得する

イーサリアムのログは2つの部分に分かれています: 1. トピックtopics2. データdata

  • テーマtopics
    によるeth_getLogs章のテストのコード実行結果を例に挙げます。topicsフィールドのデータは次のとおりです。

    desc
    "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x00000000000000000000000012b791bb27b3a4ee958b5a435fea7d49ec076e9c", "0x000000000000000000000000ef1c6e67703c7bd7107eed8303fbe6ec2554bf6b"],

    これtopics(トピック) フィールドの値は、イベントを記述する配列構造です。配列の長さは 4 を超えないことが規定されており、最初の要素はイベントの署名ハッシュ値です。
    Inventor定量取引プラットフォームでは、Encodeこの関数は、次のコードを使用して署名ハッシュ値を計算できます。

    javascript
    function main() { var eventFunction = "Transfer(address,address,uint256)" var eventHash = Encode("keccak256", "string", "hex", eventFunction) Log("eventHash:", "0x" + eventHash) // eventHash: 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef }

    計算されたTransfer(address,address,uint256)keccak256ハッシュ値(16進数エンコード)は0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef

    topicsフィールドの値は配列構造であり、2 番目の要素と 3 番目の要素は次のとおりです。

    • 送信先住所from
    • 受取住所to
  • データdata

    dataフィールドのデータは次のとおりです。

    desc
    "data": "0x0000000000000000000000000000000000000000000000000164f2434262e1cc",

    イベント内の一部のパラメータ(スマートコントラクトのSolidityコードでインデックス宣言されていないパラメータ)は、data一部。

    このデータを解析する0x0000000000000000000000000000000000000000000000000164f2434262e1cc

    javascript
    function toAmount(s, decimals) { return Number((BigDecimal(BigInt(s)) / BigDecimal(Math.pow(10, decimals))).toString()) } function main() { var value = "0x0000000000000000000000000000000000000000000000000164f2434262e1cc" Log(toAmount(value, 0) / 1e18) // 0.10047146239950075 }

    データ: 0.10047146239950075、dataデータは振込金額に対応します。


上記の内容を説明して実践したら準備完了です。ログの取得を開始できます。

javascript
function toAmount(s, decimals) { return Number((BigDecimal(BigInt(s)) / BigDecimal(Math.pow(10, decimals))).toString()) } function toInnerAmount(n, decimals) { return (BigDecimal(n) * BigDecimal(Math.pow(10, decimals))).toFixed(0) } function main() { // getBlockNumber var blockNumber = exchange.IO("api", "eth", "eth_blockNumber") Log("blockNumber:", blockNumber) // get logs var fromBlock = "0x" + (toAmount(blockNumber, 0) - 1).toString(16) var toBlock = "0x" + toAmount(blockNumber, 0).toString(16) var params = { "fromBlock" : fromBlock, "toBlock" : toBlock, "address" : "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } var logs = exchange.IO("api", "eth", "eth_getLogs", params) // 遍历logs var eventFunction = "Transfer(address,address,uint256)" var eventHash = "0x" + Encode("keccak256", "string", "hex", eventFunction) Log("eventHash:", eventHash) var counter = 0 for (var i = logs.length - 1; i >= 0 && counter < 10; i--) { if (logs[i].topics[0] == eventHash) { Log("Event Transfer, data:", toAmount(logs[i].data, 0) / 1e18, ", blockNumber:", toAmount(logs[i].blockNumber, 0), ", transactionHash:", logs[i].transactionHash, ", log:", logs[i]) counter++ } } }

存在するhttps://etherscan.io/クエリについて:

img

FMZ デバッグ ツールでテスト コードを実行した結果:

img

検索のニーズに応じて解析することもできるfromtoフィールドのデータ、例:

javascript
function main() { var from = "0x00000000000000000000000012b791bb27b3a4ee958b5a435fea7d49ec076e9c" var address = "0x" + exchange.IO("encodePacked", "address", from) Log("address:", address) }

操作結果:

address: 0x12b791bb27b3a4ee958b5a435fea7d49ec076e9c

契約イベントを監視する

なぜならデバッグツールコードのテストは短時間しかできず、内容はコード実行後にのみ出力されます。リアルタイムでログを表示・出力することは不可能です。このセクションでは、Inventor Quantitative Trading Platform を使用して、テスト用の実際のアカウントを作成します。

ここではイーサリアムメインネットを使って監視してみましょうUSDTこの通貨契約Transfer(address,address,uint256)イベントでは、前回の授業で学んだことを基に、スマート コントラクト イベントを継続的に監視する例を設計して記述しました。

javascript
function toAmount(s, decimals) { return Number((BigDecimal(BigInt(s)) / BigDecimal(Math.pow(10, decimals))).toString()) } function toInnerAmount(n, decimals) { return (BigDecimal(n) * BigDecimal(Math.pow(10, decimals))).toFixed(0) } function addEventListener(contractAddress, event, callBack) { var self = {} self.eventHash = "0x" + Encode("keccak256", "string", "hex", event) self.contractAddress = contractAddress self.latestBlockNumber = 0 self.fromBlockNumber = 0 self.firstBlockNumber = 0 /* TODO: test self.isFirst = true */ self.getBlockNumber = function() { var maxTry = 10 for (var i = 0; i < maxTry; i++) { var ret = exchange.IO("api", "eth", "eth_blockNumber") if (ret) { return toAmount(ret, 0) } Sleep(5000) } throw "getBlockNumber failed" } self.run = function() { var currBlockNumber = self.getBlockNumber() var fromBlock = "0x" + self.fromBlockNumber.toString(16) var toBlock = "0x" + currBlockNumber.toString(16) var params = { "fromBlock" : fromBlock, "toBlock" : toBlock, "address" : self.contractAddress, "topics" : [self.eventHash] } // Log("fromBlockNumber:", self.fromBlockNumber, ", currBlockNumber:", currBlockNumber, "#FF0000") var logs = exchange.IO("api", "eth", "eth_getLogs", params) if (!logs) { return } for (var i = 0; i < logs.length; i++) { if (toAmount(logs[i].blockNumber, 0) > self.latestBlockNumber) { /* TODO: test if (self.isFirst) { self.firstBlockNumber = toAmount(logs[i].blockNumber, 0) Log("firstBlockNumber:", self.firstBlockNumber) self.isFirst = false } */ callBack(logs[i]) } } self.latestBlockNumber = currBlockNumber self.fromBlockNumber = self.latestBlockNumber - 1 } self.latestBlockNumber = self.getBlockNumber() self.fromBlockNumber = self.latestBlockNumber - 1 return self } var listener = null function main() { var event = "Transfer(address,address,uint256)" var contractAddress = "0xdac17f958d2ee523a2206206994597c13d831ec7" var decimals = exchange.IO("api", contractAddress, "decimals") Log(exchange.IO("api", contractAddress, "name"), " decimals:", decimals) listener = addEventListener(contractAddress, event, function(log) { var fromAddress = "0x" + exchange.IO("encodePacked", "address", log.topics[1]) var toAddress = "0x" + exchange.IO("encodePacked", "address", log.topics[2]) Log("Transfer:", fromAddress, "->", toAddress, ", value:", toAmount(log.data, decimals), ", blockNumber:", toAmount(log.blockNumber, 0)) /* TODO: test arrLog.push(log) */ }) while (true) { listener.run() Sleep(5000) } } /* TODO: test var arrLog = [] function onexit() { Log("结束运行,验证记录") var firstBlockNumber = listener.firstBlockNumber var endBlockNumber = listener.latestBlockNumber Log("getLogs, from:", firstBlockNumber, " -> to:", endBlockNumber) var fromBlock = "0x" + (firstBlockNumber).toString(16) var toBlock = "0x" + (endBlockNumber).toString(16) var params = { "fromBlock" : fromBlock, "toBlock" : toBlock, "topics" : ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"], "address" : "0xdac17f958d2ee523a2206206994597c13d831ec7" } var logs = exchange.IO("api", "eth", "eth_getLogs", params) Log("arrLog:", arrLog.length) Log("logs:", logs.length) if (arrLog.length != logs.length) { Log("长度不等!") return } for (var i = 0; i < arrLog.length; i++) { Log("判断blockNumber:", logs[i].blockNumber == arrLog[i].blockNumber, ",判断from:", logs[i].topics[1] == arrLog[i].topics[1], "判断to:", logs[i].topics[2] == arrLog[i].topics[2]) } } */

実際のディスク操作:

img

実行結果については、検証部分(TODO:テスト)もコード内に記述します。簡単な検証の後、USDT 契約が継続的に監視されていることがわかります。Transferイベントが記録され、データが記録されます。このデータを一度取得したイベント データと比較すると、データが一貫していることがわかります。

img

イベントフィルタリング

前回のレッスン「契約イベントの監視」に基づいて、監視プロセスにフィルターを追加して、指定されたアドレスへの転送と指定されたアドレスからの転送を監視することで、これを拡張します。スマートコントラクトがログを作成する(つまりイベントをリリースする)と、ログデータはtopics最大 4 つのメッセージが含まれます。そこで私たちはフィルタリングルールを設計し、[[A1, A2, ...An], null, [C1], D]例えば。

1、[A1, A2, ...An]対応するtopics[0]位置データ。
2、null対応するtopics[1]位置データ。
3、[C1]対応するtopics[2]位置データ。
4、D対応するtopics[3]位置データ。

  • ケース構造の要素が設定されている場合nullフィルタリングされていないことを示します。例:null対応するtopics[1]、任意の値が一致します。
  • ケース構造内の要素が単一の値を設定する場合、位置が一致する必要があることを示します。例:[C1]対応するtopics[2]またはD対応するtopics[3]一致しないログは除外されます。
  • 条件構造の要素が配列である場合、配列内の少なくとも1つの要素が一致する必要があることを意味します。たとえば、[A1, A2, ...An]対応するtopics[0][A1, A2, ...An]いずれか1つとtopics[0]一致が見つかった場合、ログはフィルタリングされません。

取引所でのUSDTの送金を監視する

Binanceとの間の送金を監視するUSDT取引:

javascript
function toAmount(s, decimals) { return Number((BigDecimal(BigInt(s)) / BigDecimal(Math.pow(10, decimals))).toString()) } function toInnerAmount(n, decimals) { return (BigDecimal(n) * BigDecimal(Math.pow(10, decimals))).toFixed(0) } function addEventListener(contractAddress, event, callBack) { var self = {} self.eventHash = "0x" + Encode("keccak256", "string", "hex", event) self.contractAddress = contractAddress self.latestBlockNumber = 0 self.fromBlockNumber = 0 self.firstBlockNumber = 0 self.filters = [] self.setFilter = function(filterCondition) { if (filterCondition.length > 4) { throw "filterCondition error" } self.filters.push(filterCondition) Log("设置过滤条件:", filterCondition) } self.getTokenBalanceOfWallet = function(walletAddress, tokenAddress, tokenDecimals) { var balance = exchange.IO("api", tokenAddress, "balanceOf", walletAddress) if (balance) { return toAmount(balance, tokenDecimals) } return null } self.getBlockNumber = function() { var maxTry = 10 for (var i = 0; i < maxTry; i++) { var ret = exchange.IO("api", "eth", "eth_blockNumber") if (ret) { return toAmount(ret, 0) } Sleep(5000) } throw "getBlockNumber failed" } self.run = function() { var currBlockNumber = self.getBlockNumber() var fromBlock = "0x" + self.fromBlockNumber.toString(16) var toBlock = "0x" + currBlockNumber.toString(16) var params = { "fromBlock" : fromBlock, "toBlock" : toBlock, "address" : self.contractAddress, "topics" : [self.eventHash] } var logs = exchange.IO("api", "eth", "eth_getLogs", params) if (!logs) { return } for (var i = 0; i < logs.length; i++) { if (toAmount(logs[i].blockNumber, 0) > self.latestBlockNumber) { // 检查过滤条件,设置了过滤条件则执行判断 if (self.filters.length != 0) { // 初始过滤标记 var isFilter = true // 遍历过滤条件设置 for (var j = 0; j < self.filters.length; j++) { // 取一个过滤设置,例如:[[A1, A2, ...An], null, [C1], D] var cond = self.filters[j] // 遍历这个过滤设置 var final = true for (var topicsIndex = 0; topicsIndex < cond.length; topicsIndex++) { // 拿到这个过滤设置中的某一个条件,如果是第一个条件:即要和topics[0]对比的数据 var condValue = cond[topicsIndex] // 日志中的数据 if (topicsIndex > logs[i].topics.length - 1) { continue } var topicsEleValue = logs[i].topics[topicsIndex] // 如果是Transfer事件,需要处理from和to if (logs[i].topics[0] == "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef") { if (topicsIndex == 1 || topicsIndex == 2) { topicsEleValue = "0x" + exchange.IO("encodePacked", "address", topicsEleValue) } } // 如果condValue类型是数组,表示该位置的对比条件有多个,多个条件对比是逻辑或关系 if (Array.isArray(condValue) && condValue.length > 1) { // 判断 condValue[0] == topicsEleValue || condValue[1] == topicsEleValue final = final && condValue.some(element => element === topicsEleValue) }else if (condValue === null) { final = final && true } else { final = final && (condValue === topicsEleValue) } } if (final) { isFilter = false } } if (isFilter) { continue } } callBack(logs[i]) } } self.latestBlockNumber = currBlockNumber self.fromBlockNumber = self.latestBlockNumber - 1 } self.latestBlockNumber = self.getBlockNumber() self.fromBlockNumber = self.latestBlockNumber - 1 return self } var listener = null function main() { // 初始清理日志 LogReset(1) LogProfitReset() var event = "Transfer(address,address,uint256)" // 监听事件 var contractAddress = "0xdac17f958d2ee523a2206206994597c13d831ec7" // USDT合约地址 var decimals = exchange.IO("api", contractAddress, "decimals") // 获取USDT token的精度信息 var accountBinanceAddress = "0x28C6c06298d514Db089934071355E5743bf21d60" // Binance 热钱包地址 accountBinanceAddress = accountBinanceAddress.toLowerCase() // 地址处理为小写 Log(exchange.IO("api", contractAddress, "name"), " decimals:", decimals) // 创建监听对象 listener = addEventListener(contractAddress, event, function(log) { var fromAddress = "0x" + exchange.IO("encodePacked", "address", log.topics[1]) var toAddress = "0x" + exchange.IO("encodePacked", "address", log.topics[2]) if (fromAddress == accountBinanceAddress) { Log("币安转出 - ", " Transfer:", fromAddress, "->", toAddress, ", value:", toAmount(log.data, decimals), ", blockNumber:", toAmount(log.blockNumber, 0), "#CD32CD") } else if (toAddress == accountBinanceAddress) { Log("转入币安 - ", " Transfer:", fromAddress, "->", toAddress, ", value:", toAmount(log.data, decimals), ", blockNumber:", toAmount(log.blockNumber, 0), "#FF0000") } }) // 设置事件过滤 listener.setFilter([null, accountBinanceAddress, null]) // Binance -> USDT listener.setFilter([null, null, accountBinanceAddress]) // USDT -> Binance var preBalance = 0 while (true) { listener.run() var balance = listener.getTokenBalanceOfWallet(accountBinanceAddress, contractAddress, decimals) if (balance) { var direction = "" if (preBalance != 0 && preBalance > balance) { direction = " ↓ " + (preBalance - balance) + "#CD32CD" } else if (preBalance != 0 && preBalance < balance) { direction = " ↑ " + (balance - preBalance) + "#FF0000" } Log("币安钱包地址:", accountBinanceAddress, " 余额:", balance, direction) LogProfit(balance, "&") // 只画图,不打印日志 preBalance = balance } LogStatus(_D(), "币安钱包地址:", accountBinanceAddress, ", 余额:", balance) Sleep(5000 * 3) } }

上記のコードは実際のディスクで実行されます。

img

img

このレッスンでは、イベント フィルターの設計方法を紹介しました。そして、Binance Exchangeのホットウォレットを監視するために使用しましたUSDT貿易。このサンプル プログラムを変更および拡張して、関心のあるイベントをリッスンすることができます。smart moneyどのような新しい取引が行われましたか?NFT大物たちはどんな新しいプロジェクトに取り組んでいるのか、など。

単位変換

多くのイーサリアム関連の計算では、値がJavaScript言語の最大安全整数。したがって、Inventor Quantitative Trading Platform で大量の数値を処理するには、いくつかの方法が必要です。これらの方法は以前のコースで使用しましたが、詳細には説明していませんでした。この章では、この点について詳しく説明します。

印刷JavaScript言語で定義されている最大の安全な整数:

javascript
function main() { Log("Number.MAX_SAFE_INTEGER:", Number.MAX_SAFE_INTEGER) }

操作結果:

Number.MAX_SAFE_INTEGER: 9007199254740991

BigInt

イーサリアムで定義されている最小単位は1wei、意味1Gwei等しい1000000000 wei1Gwei実は、イーサリアム関連の計算ではそれほど大きな数字ではありません。一部のデータはこれよりはるかに大きいです。すると、非常に大きな値を持つこれらのデータは簡単に超過する可能性がありますNumber.MAX_SAFE_INTEGER: 9007199254740991

Inventor Quantitative Trading Platformでは、プラットフォームのBigIntこれらの非常に大きな整数データを表すためにオブジェクトが使用されます。コンストラクタの使用BigInt()構築するBigInt物体。数値または16進数値文字列をパラメータとして使用して構築できますBigInt物体。使用BigInt物体toString()このメソッドは、オブジェクトによって表されるデータを文字列として出力します。

BigIntオブジェクトでサポートされる操作:

  • 加算演算:+
  • 減算:-
  • 乗算:*
  • 除算演算:/
  • モジュロ演算:%
  • 電源操作:**

次のコード例を参照してください。

javascript
function main() { // 1Gwei的十进制表示 var oneGwei = 1000000000 // 1Gwei的十进制转换为十六进制表示 var oneGweiForHex = "0x" + oneGwei.toString(16) Log("oneGwei : ", oneGwei) Log("oneGweiForHex : ", oneGweiForHex) // 构造BigInt对象 Log("1Gwei / 1Gwei : ", (BigInt(oneGwei) / BigInt(oneGweiForHex)).toString(10)) Log("1Gwei * 1Gwei : ", (BigInt(oneGwei) * BigInt(oneGweiForHex)).toString(10)) Log("1Gwei - 1Gwei : ", (BigInt(oneGwei) - BigInt(oneGweiForHex)).toString(10)) Log("1Gwei + 1Gwei : ", (BigInt(oneGwei) + BigInt(oneGweiForHex)).toString(10)) Log("(1Gwei + 1) % 1Gwei : ", (BigInt(oneGwei + 1) % BigInt(oneGweiForHex)).toString(10)) Log("1Gwei ** 2 : ", (BigInt(oneGwei) ** BigInt(2)).toString(10)) Log("100 的平方根 : ", (BigInt(100) ** BigFloat(0.5)).toString(10)) Log("Number.MAX_SAFE_INTEGER : ", BigInt(Number.MAX_SAFE_INTEGER).toString(10)) Log("Number.MAX_SAFE_INTEGER * 2 : ", (BigInt(Number.MAX_SAFE_INTEGER) * BigInt("2")).toString(10)) }

デバッグツールテスト:

run
2023-06-08 11:39:50 信息 Number.MAX_SAFE_INTEGER * 2 : 18014398509481982 2023-06-08 11:39:50 信息 Number.MAX_SAFE_INTEGER : 9007199254740991 2023-06-08 11:39:50 信息 100 的平方根 : 10 2023-06-08 11:39:50 信息 1Gwei ** 2 : 1000000000000000000 2023-06-08 11:39:50 信息 (1Gwei + 1) % 1Gwei : 1 2023-06-08 11:39:50 信息 1Gwei + 1Gwei : 2000000000 2023-06-08 11:39:50 信息 1Gwei - 1Gwei : 0 2023-06-08 11:39:50 信息 1Gwei * 1Gwei : 1000000000000000000 2023-06-08 11:39:50 信息 1Gwei / 1Gwei : 1 2023-06-08 11:39:50 信息 oneGweiForHex : 0x3b9aca00 2023-06-08 11:39:50 信息 oneGwei : 1000000000

BigFloat

BigFloatオブジェクトとBigIntオブジェクトも同様に使用され、より大きな値の浮動小数点数を表すために使用されます。また、加算、減算、乗算、除算の演算もサポートしています。
BigFloatオブジェクトのサポートtoFixed()方法。

次のコード例を参照してください。

javascript
function main() { var pi = 3.14 var oneGwei = "1000000000" var oneGweiForHex = "0x3b9aca00" Log("pi + oneGwei : ", (BigFloat(pi) + BigFloat(oneGwei)).toFixed(2)) Log("pi - oneGweiForHex : ", (BigFloat(pi) - BigFloat(oneGweiForHex)).toFixed(2)) Log("pi * 2.0 : ", (BigFloat(pi) * BigFloat(2.0)).toFixed(2)) Log("pi / 2.0 : ", (BigFloat(pi) / BigFloat(2.0)).toFixed(2)) }

デバッグツールテスト:

javascript
2023-06-08 13:56:44 信息 pi / 2.0 : 1.57 2023-06-08 13:56:44 信息 pi * 2.0 : 6.28 2023-06-08 13:56:44 信息 pi - oneGweiForHex : -999999996.86 2023-06-08 13:56:44 信息 pi + oneGwei : 1000000003.14

BigDecimal

BigDecimalこのオブジェクトは整数値と浮動小数点値と互換性があり、BigIntオブジェクト、BigFloatオブジェクトの初期化では、加算、減算、乗算、除算の演算もサポートされます。

次のコード例を参照してください。

javascript
function main() { var pi = 3.1415 var oneGwei = 1000000000 var oneGweiForHex = "0x3b9aca00" Log("pi : ", BigDecimal(pi).toFixed(2)) Log("oneGwei : ", BigDecimal(oneGwei).toString()) Log("oneGweiForHex : ", BigDecimal(BigInt(oneGweiForHex)).toString()) Log("BigInt(oneGwei) : ", BigDecimal(BigInt(oneGwei)).toString()) Log("BigFloat(pi) : ", BigDecimal(BigFloat(pi)).toFixed(4)) Log("oneGwei + pi : ", (BigDecimal(oneGwei) + BigDecimal(pi)).toString()) Log("oneGwei - pi : ", (BigDecimal(oneGwei) - BigDecimal(pi)).toString()) Log("2.0 * pi : ", (BigDecimal(2.0) * BigDecimal(pi)).toString()) Log("pi / pi : ", (BigDecimal(pi) / BigDecimal(pi)).toString()) }

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

run
2023-06-08 14:52:53 信息 pi / pi : 1 2023-06-08 14:52:53 信息 2.0 * pi : 6.283 2023-06-08 14:52:53 信息 oneGwei - pi : 999999996.8585 2023-06-08 14:52:53 信息 oneGwei + pi : 1000000003.1415 2023-06-08 14:52:53 信息 BigFloat(pi) : 3.1415 2023-06-08 14:52:53 信息 BigInt(oneGwei) : 1e+9 2023-06-08 14:52:53 信息 oneGweiForHex : 1e+9 2023-06-08 14:52:53 信息 oneGwei : 1e+9 2023-06-08 14:52:53 信息 pi : 3.14

単位変換

次の 2 つの機能:toAmount()toInnerAmount()これら 2 つの関数は、以前のコースで何度も使用しました。これらは主に、データの精度変換に使用されます。

javascript
function toAmount(s, decimals) { return Number((BigDecimal(BigInt(s)) / BigDecimal(Math.pow(10, decimals))).toString()) } function toInnerAmount(n, decimals) { return (BigDecimal(n) * BigDecimal(Math.pow(10, decimals))).toFixed(0) }

toAmount()この関数は変数を変換するs精度パラメータに応じてdecimals(縮小)変換を実行します。実際、web3 の開発では、チェーン上で 16 進数データを処理する必要がある場合がよくあります。
スマート コントラクトなど、これまでのコースでこれによく遭遇します。Transfer(address,address,uint256)イベントではdataフィールドデータ:

desc
{ "data": "0x00000000000000000000000000000000000000000000000001c1a55000000000", "topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x0000000000000000000000006b75d8af000000e20b7a7ddf000ba900b4009a80", "0x000000000000000000000000bcb095c1f9c3dc02e834976706c87dee5d0f1fb6"], "transactionHash": "0x27f9bf5abe3148169b4b85a83e1de32bd50eb81ecc52e5af006157d93353e4c4", "transactionIndex": "0x0", "removed": false, "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "blockHash": "0x847be24a7b159c292bda030a011dfec89487b70e71eed486969b032d6ef04bad", "blockNumber": "0x109b1cc", "logIndex": "0x0" }

データ処理"data": "0x00000000000000000000000000000000000000000000000001c1a55000000000"、今回はtoAmount()関数。この処理設計はdataフィールド データを読み取り可能な数値に変換します。

javascript
function toAmount(s, decimals) { return Number((BigDecimal(BigInt(s)) / BigDecimal(Math.pow(10, decimals))).toString()) } function main() { var data = "0x00000000000000000000000000000000000000000000000001c1a55000000000" Log(toAmount(data, 18)) // 打印出 0.12656402755905127 }

私たちが知っている1ETHトークンは1e18 weiもし私たちがwei単位のデータ126564027559051260それをETHトークンの数に変換するにはどうすればいいですか?
使用toAmount(, 18)関数は簡単に変換できます。toInnerAmount()機能はtoAmount()関数の逆操作(精度、増幅に応じて)この 2 つの関数を使用すると、データを変換するのに非常に便利です。

JavaScript言語における整数値の安全な範囲はNumber.MAX_SAFE_INTEGER次の例は、データ変換におけるより隠れた問題を示しています。

javascript
function toAmount(s, decimals) { return Number((BigDecimal(BigInt(s)) / BigDecimal(Math.pow(10, decimals))).toString()) } function toInnerAmount(n, decimals) { return (BigDecimal(n) * BigDecimal(Math.pow(10, decimals))).toFixed(0) } function main() { var amount = 0.01 var innerAmount = Number(toInnerAmount(amount, 18)) Log("Number.MAX_SAFE_INTEGER:", Number.MAX_SAFE_INTEGER) // 9007199254740991 Log("innerAmount:", innerAmount) // 10000000000000000 Log("typeof(innerAmount):", typeof(innerAmount), ", innerAmount:", innerAmount) // 十进制数值 10000000000000000 -> 十六进制数值 0x2386f26fc10000 Log("转换", innerAmount, "为十六进制:", innerAmount.toString(16)) Log("转换", BigInt(10000000000000000).toString(10), "为十六进制:", BigInt(10000000000000000).toString(16)) Log("0x" + BigInt(10000000000000000).toString(16), "转换为10进制:", toAmount("0x" + BigInt(10000000000000000).toString(16), 0)) }

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

run
2023-06-15 16:21:40 信息 0x2386f26fc10000 转换为10进制: 10000000000000000 2023-06-15 16:21:40 信息 转换 10000000000000000 为十六进制: 2386f26fc10000 2023-06-15 16:21:40 信息 转换 10000000000000000 为十六进制: 10000000000000000 2023-06-15 16:21:40 信息 typeof(innerAmount): number , innerAmount: 10000000000000000 2023-06-15 16:21:40 信息 innerAmount: 10000000000000000 2023-06-15 16:21:40 信息 Number.MAX_SAFE_INTEGER: 9007199254740991

観察を通じて次のことがわかりました。

javascript
Log("转换", innerAmount, "为十六进制:", innerAmount.toString(16))

このコード行に対応するログ出力は次のとおりです。转换 10000000000000000 为十六进制: 10000000000000000が正しく変換されませんでした。理由は当然100000000000000000を超えるからですNumber.MAX_SAFE_INTEGER

ただし、小数値が安全範囲内、つまりNumber.MAX_SAFE_INTEGER時間、toString(16)関数変換は再び正常になります。例:

javascript
function main() { var value = 1000 Log("把value转换为十六进制:", "0x" + value.toString(16)) // 0x3e8 Log("把0x3e8转换为十进制:", Number("0x3e8")) // 1000 }

ブロックチェーンの分野でも0.01ETHに変換weiユニットの値10000000000000000また、Number.MAX_SAFE_INTEGERしたがって、この状況でのより安全な変換は次のようになります。BigInt(10000000000000000).toString(16)

通話をシミュレートする

Ethereumでトランザクションを実行し、スマートコントラクトを呼び出すWriteこの方法は一定量のガスを消費し、失敗するリスクもあります。トランザクションを送信または呼び出す前に、どのトランザクションが失敗する可能性があるかを把握することが重要です。 Ethereum にはテスト用のシミュレートされた呼び出しメソッドがあります。

eth_call

イーサリアムのRPC方式eth_call:トランザクションをシミュレートし、可能なトランザクション結果を返すことはできますが、ブロックチェーン上で実際にトランザクションを実行することはありません。

eth_callこのメソッドには2つのパラメータがあり、最初のパラメータは辞書構造です。transactionObject

javascript
// transactionObject { "from" : ..., // The address from which the transaction is sent "to" : ..., // The address to which the transaction is addressed "gas" : ..., // The integer of gas provided for the transaction execution "gasPrice" : ..., // The integer of gasPrice used for each paid gas encoded as hexadecimal "value" : ..., // The integer of value sent with this transaction encoded as hexadecimal "data" : ..., // The hash of the method signature and encoded parameters. For more information, see the Contract ABI description in the Solidity documentation }

2番目のパラメータはblockNumber: タグを渡すことができるlatest/pending/earliest待って:

javascript
/* blockNumber The block number in hexadecimal format or the string latest, earliest, pending, safe or finalized (safe and finalized tags are only supported on Ethereum, Gnosis, Arbitrum, Arbitrum Nova and Avalanche C-chain), see the default block parameter description in the official Ethereum documentation */

次にトークンを使用しますDAIスマートコントラクト方式approvetransfer通話は模擬通話の一例です。以下のテスト環境はEthereumメインネットワークです。

承認の呼び出しをシミュレートする

ERC20契約の場合approve私たちはすでにこの方法に精通しており、以前のコースで練習しました。 ERC20 コントラクトはすでに FMZ プラットフォーム ABI に組み込まれているため、シミュレートするスマート コントラクトの ABI を登録する必要はありません。

javascript
function main() { var contractAddressUniswapV3SwapRouterV2 = "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45" var contractAddress_DAI = "0x6b175474e89094c44da98b954eedeac495271d0f" var wallet = exchange.IO("address") // encode approve var data = exchange.IO("encode", contractAddress_DAI, "approve(address,uint256)", contractAddressUniswapV3SwapRouterV2, "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff") Log("ERC20 token DAI approve encode, data:", data) var transactionObject = { "from" : wallet, "to" : contractAddress_DAI, // "gasPrice" : "0x" + parseInt("21270894680").toString(16), // "gas" : "0x" + parseInt("21000").toString(16), "data" : "0x" + data, } var blockNumber = "latest" var ret = exchange.IO("api", "eth", "eth_call", transactionObject, blockNumber) Log("ret:", ret) }

この例のコードはまずapprove(address,uint256)メソッドとパラメータはエンコードされます。approveメソッドパラメータ値0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff承認の最大数を示します。スマートコントラクト、アドレスを承認する0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45今すぐUniswap V3ルーティング契約。最後にEthereum RPCメソッドを呼び出すeth_callシミュレーションを実行します。見ることができますtransactionObjectパラメータgasPricegasフィールドは省略できます。

デバッグ ツールが実行され、approve メソッドの呼び出しによる正常な承認をシミュレートします (ただし、実際には承認されません)。

run
2023-06-09 11:58:39 信息 ret: 0x0000000000000000000000000000000000000000000000000000000000000001 2023-06-09 11:58:39 信息 ERC20 token DAI approve encode, data: 095ea7b300000000000000000000000068b3465833fb72a70ecdf485e0e4c7bd8665fc45ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff

失敗のシナリオをシミュレーションすることもできます。gasPriceそしてgasパラメータを設定する際に、ウォレット内の ETH がガス料金を支払うのに十分でない場合はエラーが報告されます。

insufficient funds

ガス料金が低すぎると、エラーが報告されます。

intrinsic gas too low: have 21000, want 21944 (supplied gas 21000)

通話転送をシミュレートする

ERC20の場合transferこの方法も私たちもよく知っています。この方法では、ERC20トークンを特定のウォレットアドレスに転送できます。1,000 DAIをVitalik Buterinに転送するシミュレーションを試みます。

javascript
function toInnerAmount(n, decimals) { return (BigDecimal(n) * BigDecimal(Math.pow(10, decimals))).toFixed(0) } function main() { var walletVitalik = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" var contractAddress_DAI = "0x6b175474e89094c44da98b954eedeac495271d0f" var wallet = exchange.IO("address") // 转账给V神 var decimals_DAI = exchange.IO("api", contractAddress_DAI, "decimals") var transferAmount = toInnerAmount(1000, decimals_DAI) Log("转账金额:", 1000, "DAI, 使用 toInnerAmount 转换为:", transferAmount) // encode transfer var data = exchange.IO("encode", contractAddress_DAI, "transfer(address,uint256)", walletVitalik, transferAmount) var transactionObject = { "from" : wallet, "to" : contractAddress_DAI, "data" : "0x" + data, } var blockNumber = "latest" var ret = exchange.IO("api", "eth", "eth_call", transactionObject, blockNumber) return ret }

私のテストウォレットには DAI トークンがないので、デバッグツールで実行した結果は予想どおりで、エラーが報告されます。

execution reverted: Dai/insufficient-balance

Vitalikのウォレットアドレスを確認してください:0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045このウォレットにはDAIトークンが含まれていることがわかります。次に、シミュレートされた通話の転送方向を交換し、Vitalik が 1,000 DAI を私たちに転送することをシミュレートしてみましょう。

コードを変更し、変更した箇所にコメントを追加します。

javascript
function toInnerAmount(n, decimals) { return (BigDecimal(n) * BigDecimal(Math.pow(10, decimals))).toFixed(0) } function main() { var walletVitalik = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" var contractAddress_DAI = "0x6b175474e89094c44da98b954eedeac495271d0f" var wallet = exchange.IO("address") var decimals_DAI = exchange.IO("api", contractAddress_DAI, "decimals") var transferAmount = toInnerAmount(1000, decimals_DAI) Log("转账金额:", 1000, "DAI, 使用 toInnerAmount 转换为:", transferAmount) // encode transfer var data = exchange.IO("encode", contractAddress_DAI, "transfer(address,uint256)", wallet, transferAmount) // 使用wallet变量作为参数,转账接收方地址改为我自己 var transactionObject = { "from" : walletVitalik, // 使用walletVitalik变量作为from字段的值,模拟这个调用是由V神钱包地址发出 "to" : contractAddress_DAI, "data" : "0x" + data, } var blockNumber = "latest" var ret = exchange.IO("api", "eth", "eth_call", transactionObject, blockNumber) Log(ret) }

デバッグツールテスト:

javascript
2023-06-09 13:34:31 信息 0x0000000000000000000000000000000000000000000000000000000000000001 2023-06-09 13:34:31 信息 转账金额: 1000 DAI, 使用 toInnerAmount 转换为: 1000000000000000000000

Inventor Quantitative Trading Platform を使用すると、トランザクションの結果を簡単にシミュレートし、失敗する可能性のあるトランザクションの送信によって発生する不必要なガス料金の損失を回避できます。この章のサンプル コードを使用して、Vitalik のウォレットへの送金と Vitalik のウォレットから私たちに送金する呼び出しをシミュレートします。もちろん、これはeth_callメソッドにはさらに多くの用途があります。想像力を働かせればeth_callこの方法はどこで使用されていますか?

ERC721コントラクトを識別する

ETH や BTC などのトークンはすべて同質のトークンであることはわかっています。あなたの手にあるトークンは、私の手にあるトークンと何ら変わりません。しかし、世の中には不動産や骨董品、仮想アート作品など、均質なトークンで抽象的に表現することができない、性質の異なるものが数多く存在します。そこで、非均質なオブジェクトを抽象化するためにERC721規格が作成され、NFTや関連する概念が誕生しました。
では、Ethereum に展開されている多数のスマート コントラクトの中で、どのスマート コントラクトが ERC721 標準のスマート コントラクトであるかをどのように識別するのでしょうか?

ERC721 を識別するには、まず ERC165 標準を理解する必要があります。

ERC165

ERC165 標準を通じて、スマート コントラクトは、他のコントラクトがチェックできるようにサポートするインターフェイスを宣言できます。 ERC165 インターフェース コントラクトには 1 つの機能しかありません。supportsInterface(bytes4 interfaceId)、パラメータinterfaceId照会するインターフェース ID。コントラクトがインターフェース Id を実装している場合はブール値の true 値を返し、そうでない場合は false 値を返します。

次はこれについてお話ししますinterfaceId具体的に計算してエンコードする方法。

ERC165 標準例を挙げます。

solidity
pragma solidity ^0.4.20; interface Solidity101 { function hello() external pure; function world(int) external pure; } contract Selector { function calculateSelector() public pure returns (bytes4) { Solidity101 i; return i.hello.selector ^ i.world.selector; } }

インターフェースの関数シグネチャ(関数名とパラメータ型リストで構成)に対して XOR 演算を実行します。関数が 1 つだけの ERC165 インターフェース コントラクトの場合:

solidity
pragma solidity ^0.4.20; interface ERC165 { /// @notice Query if a contract implements an interface /// @param interfaceID The interface identifier, as specified in ERC-165 /// @dev Interface identification is specified in ERC-165. This function /// uses less than 30,000 gas. /// @return `true` if the contract implements `interfaceID` and /// `interfaceID` is not 0xffffffff, `false` otherwise function supportsInterface(bytes4 interfaceID) external view returns (bool); }

The interface identifier for this interface is 0x01ffc9a7. You can calculate this by running bytes4(keccak256('supportsInterface(bytes4)')); or using the Selector contract above.

関数シグネチャを直接計算し、最初の4バイトを取得してinterfaceId

javascript
function main() { var ret = Encode("keccak256", "string", "hex", "supportsInterface(bytes4)") Log("supportsInterface(bytes4) interfaceId:", "0x" + ret.slice(0, 8)) }

デバッガーでテストを実行できます。

run
2023-06-13 14:53:35 信息 supportsInterface(bytes4) interfaceId: 0x01ffc9a7

計算結果を見ることができ、ERC165 標準文書内の説明は一貫しています。

ERC721

次に、ERC721 コントラクト標準のインターフェース定義を見てみましょう。

solidity
interface ERC721 /* is ERC165 */ { event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId); event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId); event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved); function balanceOf(address _owner) external view returns (uint256); function ownerOf(uint256 _tokenId) external view returns (address); function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external payable; function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable; function transferFrom(address _from, address _to, uint256 _tokenId) external payable; function approve(address _approved, uint256 _tokenId) external payable; function setApprovalForAll(address _operator, bool _approved) external; function getApproved(uint256 _tokenId) external view returns (address); function isApprovedForAll(address _owner, address _operator) external view returns (bool); }

スマート コントラクトが ERC721 コントラクトであるかどうかを判断するには、まず ERC721 コントラクトを知る必要があります。interfaceId、使用する前にsupportsInterface(bytes4 interfaceId)方法の判断。前回のコースでは、ERC165 標準のいくつかの概念と計算について学習しました。interfaceIdアルゴリズムを計算するコードを直接記述することができます。

javascript
function calcSelector(arrSelector) { var ret = null if (Array.isArray(arrSelector)) { if (arrSelector.length == 1) { ret = Encode("keccak256", "string", "hex", arrSelector[0]) } else if (arrSelector.length == 0) { throw "错误:数组中元素个数为0" } else { var viewEncodeData = null for (var i = 0; i < arrSelector.length; i++) { if (i == 0) { ret = new Uint8Array(Encode("keccak256", "string", "raw", arrSelector[i])) } else { viewData = new Uint8Array(Encode("keccak256", "string", "raw", arrSelector[i])) if (viewData.length != ret.length) { throw "错误:TypeArray view长度不同" } for (var index = 0; index < ret.length; index++) { ret[index] ^= viewData[index] } } } ret = Encode("raw", "raw", "hex", ret.buffer) } } else { throw "错误:参数需要数组类型。" } return "0x" + ret.slice(0, 8) } function main() { // supportsInterface(bytes4): 0x01ffc9a7 // var ret = calcSelector(["supportsInterface(bytes4)"]) // ERC721Metadata: 0x5b5e139f /* var arrSelector = [ "name()", "symbol()", "tokenURI(uint256)" ] var ret = calcSelector(arrSelector) */ // ERC721: 0x80ac58cd // /* var arrSelector = [ "balanceOf(address)", "ownerOf(uint256)", "safeTransferFrom(address,address,uint256,bytes)", "safeTransferFrom(address,address,uint256)", "transferFrom(address,address,uint256)", "approve(address,uint256)", "setApprovalForAll(address,bool)", "getApproved(uint256)", "isApprovedForAll(address,address)", ] var ret = calcSelector(arrSelector) // */ Log(ret) }

コードではEncode()この関数は関数シグネチャの計算を実行します(keccak256アルゴリズム)、上記のコード例の計算では、次のように指定します。Encode()関数の出力パラメータは"raw"関数はJavaScript言語的ArrayBufferタイプ。
2つにしたい場合ArrayBuffer物体^(XOR)演算は、ArrayBufferオブジェクトの作成TypedArray次に、ビューはデータに対して反復処理され、各データに対して XOR 演算が実行されます。

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

run
2023-06-13 15:04:09 信息 0x80ac58cd

計算結果を見ることができ、eip-721で説明したものと同じです。

solidity
pragma solidity ^0.4.20; /// @title ERC-721 Non-Fungible Token Standard /// @dev See https://eips.ethereum.org/EIPS/eip-721 /// Note: the ERC-165 identifier for this interface is 0x80ac58cd. interface ERC721 /* is ERC165 */ { /// @dev This emits when ownership of any NFT changes by any mechanism. /// This event emits when NFTs are created (`from` == 0) and destroyed /// (`to` == 0). Exception: during contract creation, any number of NFTs /// may be created and assigned without emitting Transfer. At the time of /// any transfer, the approved address for that NFT (if any) is reset to none. event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId); ...

ERC721 インターフェース ID を使用すると、コントラクトが ERC721 標準コントラクトであるかどうかを判断できます。私たちはBAYCテストを行うには、ERC721に準拠したコントラクトが必要です。まず、ABIを登録する必要があります。次の3つのメソッドのみを呼び出すため、これらの3つのメソッドのみを登録できます。

  • supportsInterface(interfaceId)
  • symbol()
  • name()

具体的なコードは次のとおりです。

javascript
function main() { // ERC721的合约地址,这里用的BAYC var testContractAddress = "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d" var testABI = `[{ "inputs": [{ "internalType": "bytes4", "name": "interfaceId", "type": "bytes4" }], "name": "supportsInterface", "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "symbol", "outputs": [{ "internalType": "string", "name": "", "type": "string" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "name", "outputs": [{ "internalType": "string", "name": "", "type": "string" }], "stateMutability": "view", "type": "function" }]` // ERC721接口Id,在之前的课程中计算得出 var interfaceId = "0x80ac58cd" // 注册ABI exchange.IO("abi", testContractAddress, testABI) // 调用supportsInterface方法 var isErc721 = exchange.IO("api", testContractAddress, "supportsInterface", interfaceId) // 输出信息 Log("合约地址:", testContractAddress) Log("合约名称:", exchange.IO("api", testContractAddress, "name")) Log("合约代号:", exchange.IO("api", testContractAddress, "symbol")) Log("合约是否为ERC721标准:", isErc721) }

デバッガーでテストを実行できます。

run
2023-06-13 16:32:57 信息 合约是否为ERC721标准: true 2023-06-13 16:32:57 信息 合约代号: BAYC 2023-06-13 16:32:57 信息 合约名称: BoredApeYachtClub 2023-06-13 16:32:57 信息 合约地址: 0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d

住所を決定する0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d契約はERC721規格です。

この講義では、ERC721コントラクトの識別方法を紹介しました。ERC165規格に対応していないERC20コントラクトの場合は、他の方法で識別する必要があります。契約が ERC20 標準かどうかを確認する方法を知っていますか?

呼び出しデータのエンコード

何ですかcalldata?著者の理解によれば、ここでのシンプルで一般的な説明は次のとおりです。

「Calldata」は、Ethereum の関数呼び出しとパラメータのエンコードです。「Calldata」は、コントラクトの ABI (アプリケーション バイナリ インターフェイス) 仕様に従ってエンコードされます。

例えば、前回のコースで学んだERC20コントラクトを使うことができますbalanceOftransferメソッド呼び出しは、呼び出しで使用されるパラメータとともに、calldata。たとえば、いくつかのアプリケーション シナリオでは次のようになります。契約間の相互作用このシナリオで使用されるcalldataもちろん、ここに一つ一つ挙げていない他のアプリケーション シナリオも多数あります。

スマートコントラクト関数呼び出しをコーディングして取得する方法calldata

Inventor定量取引プラットフォームで使用できますexchange.IO("encode", ...)スマート コントラクト関数呼び出しのエンコードも非常に簡単に使用できます。exchange.IO("encode", ...)関数の最初のパラメータは固定文字列です"encode"; 2 番目のパラメーターはスマート コントラクトのアドレスです。3 番目のパラメーターはエンコードするスマート コントラクト メソッドの名前です。残りのパラメーターは、エンコードするスマート コントラクト メソッドの特定のパラメーター値を渡します。

eth_sendRawTransaction

スマートコントラクトのメソッド呼び出しをエンコードし、対応するcalldataデータを生成する際、スマートコントラクトメソッドがWriteメソッド(書き込み操作)である場合は、calldataデータはトランザクションのデータフィールドとして使用され、その後EthereumのRPCメソッドが使用されます。eth_sendRawTransactionトランザクションの生データを含むリクエストを Ethereum ネットワークに送信します。

eth_sendRawTransactionこのメソッドにはパラメータが1つだけありますdata

data: The signed transaction (typically signed with a library, using your private key)

これdataパラメータはトランザクションデータの署名計算後のデータです。Ethereum のトランザクションデータ構造には主に以下のフィールドがあります。

javascript
{ "nonce": "0x1", // 交易发送方的账户交易次数 "gasPrice": "0x12a05f200", // 交易的Gas价格 "gasLimit": "0x5208", // 交易的Gas限制 "to": "0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2", // 目标合约地址或接收方地址 "value": "0x4563918244F40000", // 转账的以太币数量 "data": "0x0123456789ABCDEF", // 要发送给合约的数据 }

Ethereum トランザクションに署名するにはどうすればいいですか?

Inventor定量取引プラットフォームでは、Encode()署名計算を行う関数。具体的な例は後続の講座「Writeメソッドcalldataの実行」で書きます。

Readメソッドcalldataを実行する

読み取りメソッドの場合calldata実行するには、前に学習した RPC メソッドを使用します。eth_call実行するために、前に説明したeth_callこのEthereum RPC方式はスマートコントラクトのみを実行するWriteこの章を使用して方法のデモンストレーションcalldata次の例は、スマート コントラクトの Read メソッドを呼び出す方法を示しています。 WETH契約を使ってみましょうbalanceOf現在のウォレットの WETH トークン残高を読み取るメソッド。

Ethereum メインネットでのテストにはデバッグ ツールを使用します。

javascript
function toAmount(s, decimals) { return Number((BigDecimal(BigInt(s)) / BigDecimal(Math.pow(10, decimals))).toString()) } function main() { // WETH合约的ABI var abiWETH = `[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"guy","type":"address"},{"name":"wad","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"src","type":"address"},{"name":"dst","type":"address"},{"name":"wad","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"wad","type":"uint256"}],"name":"withdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"dst","type":"address"},{"name":"wad","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"deposit","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"src","type":"address"},{"indexed":true,"name":"guy","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"src","type":"address"},{"indexed":true,"name":"dst","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"dst","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"src","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Withdrawal","type":"event"}]` // WETH合约地址 var wethAddress = "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2" // 注册WETH合约的ABI exchange.IO("abi", wethAddress, abiWETH) // 当前配置的交易所对象的钱包地址 var walletAddress = exchange.IO("address") // 编码WETH合约的deposit方法调用 var calldataForDeposit = exchange.IO("encode", wethAddress, "balanceOf(address)", walletAddress) Log("calldataForDeposit:", "0x" + calldataForDeposit) // 构造transaction,作为eth_call的第一个参数 var transaction = { "from" : walletAddress, "to" : wethAddress, "data" : "0x" + calldataForDeposit, } // eth_call的第二个参数 var blockNumber = "latest" // 使用eth_call调用 var ret = exchange.IO("api", "eth", "eth_call", transaction, blockNumber) var wethBalance = exchange.IO("decode", "uint256", ret) // 可以使用exchange.IO("decode", ...) 函数解码 Log("wethBalance:", toAmount(wethBalance, 18)) // 从以wei为单位,换算成WETH个数为单位 }

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

run
2023-06-15 11:51:31 信息 wethBalance: 0.015 2023-06-15 11:51:31 信息 calldataForDeposit: 0x70a082310000000000000000000000006b3f11d807809b0b1e5e3243df04a280d9f94bf4

スマートコントラクトメソッドに戻り値がある場合は、exchange.IO("decode", ...)関数のデコード。通過することで、calldataスマートコントラクトへのメソッドと直接呼び出しbalanceOf方法は同じで、私のテストウォレットのWETH残高は0.015WETHです。

Writeメソッドcalldataを実行する

Write メソッドの calldata 実行には、RPC メソッドを使用する必要があります。eth_sendRawTransaction

Ethereum メインネットでのテストにはデバッグ ツールを使用します。

javascript
function toAmount(s, decimals) { return Number((BigDecimal(BigInt(s)) / BigDecimal(Math.pow(10, decimals))).toString()) } function toInnerAmount(s, decimals) { return (BigDecimal(s)*BigDecimal(Math.pow(10, decimals))).toFixed(0) } function main() { // WETH合约的ABI var abiWETH = `[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"guy","type":"address"},{"name":"wad","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"src","type":"address"},{"name":"dst","type":"address"},{"name":"wad","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"wad","type":"uint256"}],"name":"withdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"dst","type":"address"},{"name":"wad","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"deposit","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"src","type":"address"},{"indexed":true,"name":"guy","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"src","type":"address"},{"indexed":true,"name":"dst","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"dst","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"src","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Withdrawal","type":"event"}]` // WETH合约地址 var wethAddress = "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2" // 注册WETH合约的ABI exchange.IO("abi", wethAddress, abiWETH) // 当前配置的交易所对象的钱包地址 var walletAddress = exchange.IO("address") // 编码WETH合约的deposit方法调用 var calldataForDeposit = exchange.IO("encode", wethAddress, "deposit") Log("calldataForDeposit:", "0x" + calldataForDeposit) // 获取nonce var nonce = exchange.IO("api", "eth", "eth_getTransactionCount", walletAddress, "pending") // 获取gasPrice var gasPrice = exchange.IO("api", "eth", "eth_gasPrice") // 调用deposit方法把ETH换为WETH,需要转账ETH,这里把0.01ETH转换为以wei为单位的十六进制数值 var innerAmount = BigInt(Number(toInnerAmount(0.005, 18))).toString(16) // The transaction call object: var obj = { "from" : walletAddress, "to" : wethAddress, "gasPrice" : gasPrice, "value" : "0x" + innerAmount, "data" : "0x" + calldataForDeposit, } // 计算gasLimit var gasLimit = exchange.IO("api", "eth", "eth_estimateGas", obj) // 构造交易 var transaction = { "to": wethAddress, "value": toAmount("0x" + innerAmount, 0), // 转换为10进制 "data": "0x" + calldataForDeposit, "gasLimit": toAmount(gasLimit, 0), // 转换为10进制 "gasPrice": toAmount(gasPrice, 0), // 转换为10进制 "nonce": toAmount(nonce, 0), // 转换为10进制 "chainId": 1, // 以太坊主网Id } Log("transaction:", transaction) // 签名,your key 替换为你的私钥 var signedTx = Encode("signTx", "string", "hex", JSON.stringify(transaction), "hex", "0x" + "your key") Log("signedTx:", "0x" + signedTx) // 调用eth_sendRawTransaction发送交易 var ret = exchange.IO("api", "eth", "eth_sendRawTransaction", "0x" + signedTx) return ret }

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

run
2023-06-15 09:58:50 信息 signedTx: 0xf86f4f8504202067888... 2023-06-15 09:58:50 信息 transaction: {"to":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2","value":5000000000000000,"data":"0xd0e30db0","gasLimit":27938,"gasPrice":17718863752,"nonce":79,"chainId":1} 2023-06-15 09:58:50 信息 calldataForDeposit: 0xd0e30db0

埋め込むvar ret = exchange.IO("api", "eth", "eth_sendRawTransaction", "0x" + signedTx)関数の場合、返されるトランザクション ハッシュは次のようになります。0x2ff585504b0fe59b0122f696e8808abfe2f3ce263448066533f3bb8a4f55e8e6。これeth_sendRawTransactioncalldata は WETH コントラクトを実行するために呼び出されます。depositこの方法では、送信された 0.005 ETH を WETH に交換します。

メモリプールの監視

イーサリアム上のユーザーのトランザクションがマイナーによってイーサリアムブロックチェーンにパッケージ化される前に、すべてのトランザクションはMempoolトランザクション メモリ プールでは、「マイナー」は手数料の高いトランザクションを探し、最初にパッケージ化してマイニングの利益を最大化します。したがって、一般的に言えば、トランザクションのガス価格を高く設定するほど、パッケージ化されやすくなります。

一部のトランザクションスクリプトでは、Mempool儲かる取引が見つかることを期待して、周囲を嗅ぎ回っています。たとえば、トランザクションが高すぎる交換スリッページを設定すると、トランザクションはこれらのトランザクション スクリプトによる「サンドイッチ攻撃」を受ける可能性があります。では、これらのスクリプトはどのように監視するのでしょうかMempoolpending(保留中、パッケージ化予定) 取引はどうなりましたか?

RESTプロトコルを使用してリッスンする

先ほど学んだ RPC メソッドを使用します。eth_getBlockByNumberですが、今回は詳細は掲載しません。blockNumber、私たちは"pending"ラベル。

javascript
function main() { var data = exchange.IO("api", "eth", "eth_getBlockByNumber", "pending", true) if (Array.isArray(data.transactions)) { for (var i = 0; i < data.transactions.length; i++) { Log(data.transactions[i]) } } }

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

run
2023-06-18 19:23:05 信息 {"blockNumber":"0x10b2027","type":"0x2","accessList":[],"blockHash":"0xf833ed36435c53d63bd7109bb1e85383075534410c14573881bf26d912f46a89","from":"0xd50521974d62f1fa34b8e81cb742ccf6147d05ff","gasPrice":"0x32ea2db37","hash":"0xf8f10f8f473c340b021298feb48d0affe529e8737a309c4cc1902e8989ef0914","input":"0xa22cb4650000000000000000000000001e0049783f008a0085193e00003d00cd54003c710000000000000000000000000000000000000000000000000000000000000001","v":"0x0","value":"0x0","maxFeePerGas":"0x48a413364","maxPriorityFeePerGas":"0x5f5e100","nonce":"0x8","r":"0x8c1cc36f43b02c9e9e454153588cc9d38757f1da69ec49d3cfdda74ab69e06a8","s":"0x2f3dd3e5ddf9e5d42c128a8e900026aca7568fa83c68cf332e1328066ee8d03a","transactionIndex":"0x3a","chainId":"0x1","gas":"0x1142d","to":"0x8c3c0274c33f263f0a55d129cfc8eaa3667a9e8b"} 2023-06-18 19:23:05 信息 {"input":"0x646174613a2c7b2270223a226572632d3230222c226f70223a226d696e74222c227469636b223a2265746873222c226964223a223139323732222c22616d74223a2231303030227d","nonce":"0x1d","blockHash":"0xf833ed36435c53d63bd7109bb1e85383075534410c14573881bf26d912f46a89","from":"0xe7fa86855af674837cea1b58f88b5352543ca27b","gas":"0x81cc","gasPrice":"0x32ea2db37","to":"0xe7fa86855af674837cea1b58f88b5352543ca27b","chainId":"0x1","transactionIndex":"0x39","type":"0x2","value":"0x0","accessList":[],"blockNumber":"0x10b2027","hash":"0x55702f5d14736fc9d0c58fdac2d2052a602db171c46b5e1fa9ff6af5c277f9a2","maxFeePerGas":"0x48a413364","maxPriorityFeePerGas":"0x5f5e100","r":"0x5a703d389d23b51adf8ef0f55db8876e7392636797b68a4be6afe73e76d7e1f2","s":"0x4b4bb11257c4434a0acc2672357f8793476e4bfdf98bc30d2389ce335e7de64e","v":"0x1"} 2023-06-18 19:23:05 信息 {"gas":"0x186a0","nonce":"0x46533","r":"0xfeea052a4ac2283ca058a657a806ba0916d8e7d52d2a577f150c40eb1dfbec65","s":"0x5bf0089a3c060ba787b67a205b44e1065a0d11d132b41737ab9adf0f55066811","transactionIndex":"0x38","value":"0x78f0975742c400","blockHash":"0xf833ed36435c53d63bd7109bb1e85383075534410c14573881bf26d912f46a89","chainId":"0x1","hash":"0x56bdf1b38e23db66e8d1c4014d1e9f690a9217d8a0232489210325fc69e25cf9","v":"0x25","input":"0x","type":"0x0","blockNumber":"0x10b2027","gasPrice":"0x4a817c800","from":"0x97b9d2102a9a65a26e1ee82d59e42d1b73b68689","to":"0xcb513e99c020e9d15a6eafef873fef5d9f078221"} ...

データの 1 つを抽出します。

javascript
{ "blockNumber": "0x10b2027", "type": "0x2", "accessList": [], "blockHash": "0xf833ed36435c53d63bd7109bb1e85383075534410c14573881bf26d912f46a89", "from": "0xd50521974d62f1fa34b8e81cb742ccf6147d05ff", "gasPrice": "0x32ea2db37", "hash": "0xf8f10f8f473c340b021298feb48d0affe529e8737a309c4cc1902e8989ef0914", "input": "0xa22cb4650000000000000000000000001e0049783f008a0085193e00003d00cd54003c710000000000000000000000000000000000000000000000000000000000000001", "v": "0x0", "value": "0x0", "maxFeePerGas": "0x48a413364", "maxPriorityFeePerGas": "0x5f5e100", "nonce": "0x8", "r": "0x8c1cc36f43b02c9e9e454153588cc9d38757f1da69ec49d3cfdda74ab69e06a8", "s": "0x2f3dd3e5ddf9e5d42c128a8e900026aca7568fa83c68cf332e1328066ee8d03a", "transactionIndex": "0x3a", "chainId": "0x1", "gas": "0x1142d", "to": "0x8c3c0274c33f263f0a55d129cfc8eaa3667a9e8b" }

WebSocket プロトコルを使用したリスニング

Inventor定量取引プラットフォームでは、Dial作成する機能WebSocket表示に接続FMZ APIドキュメントDial関数。

この章のテストコードは、Ethereum メインネット環境で実行されます。通信には WebSocket プロトコルを使用するため、Inventor Quantitative リアルタイム テストを使用する方が便利です。 Websocket プロトコルのサブスクリプション メッセージは次のとおりです。

javascript
{"jsonrpc": "2.0", "id": 1, "method": "eth_subscribe", "params": ["newPendingTransactions"]}

とは別にnewPendingTransactions購読することもできますnewHeadslogs

受け取るWebSocketプッシュデータに接続します:

javascript
{ "jsonrpc": "2.0", "method": "eth_subscription", "params": { "subscription": "0x2c5c087b4aa188e008f4747828ef4e61", "result": "0x69c4251cecb814e17cfe7a5ee41742a616f9a4d1bbf245c49b186b1006fd14d3" } }

次に、次のようにします。"result": "0x69c4251cecb814e17cfe7a5ee41742a616f9a4d1bbf245c49b186b1006fd14d3"、さらに詳しい問い合わせtransaction。特定のtransactionEthereum RPC方式を使用しますeth_getTransactionByHash問い合わせる。

javascript
var ws = null function main () { // {"jsonrpc": "2.0", "id": 1, "method": "eth_subscribe", "params": ["xxxxx"]} , "xxxxx" 是订阅的具体消息 var payload = {"jsonrpc": "2.0", "id": 1, "method": "eth_subscribe", "params": ["newPendingTransactions"]} // wss://mainnet.infura.io/ws/v3/xxxxx , "xxxxx" 是你的infura key var infuraKey = "your key" ws = Dial("wss://mainnet.infura.io/ws/v3/" + infuraKey + "|reconnect=true&payload=" + JSON.stringify(payload)) if (!ws) { throw "websocket链接infura失败!" } // eth_getTransactionByHash 调用计数 var getTransactionCounter = 0 var beginTS = new Date().getTime() // 循环获取消息 while (true) { // 接收推送的消息 var data = ws.read() if (data) { var ts = new Date().getTime() if (ts - beginTS >= 1000) { getTransactionCounter = 0 beginTS = ts } // 根据txHash查询交易详情 if (ts - beginTS < 1000 && getTransactionCounter >= 100) { Sleep(1000) getTransactionCounter = 0 beginTS = ts } var obj = JSON.parse(data) if (obj["params"] && obj["params"]["result"]) { var transcationInfo = exchange.IO("api", "eth", "eth_getTransactionByHash", obj["params"]["result"]) Log(obj["params"]["result"], "transcationInfo:", transcationInfo) } getTransactionCounter++ } LogStatus(_D()) } } function onexit() { Log("断开WS连接") ws.close() }

実際のディスクを作成し、上記のコードを実行すると、WebSocket 接続によってプッシュされたデータを受信できます。データは継続的にプッシュされます。そのうちの 1 つを抽出してみましょう。transaction

javascript
{ "maxPriorityFeePerGas": "0x5f5e100", "nonce": "0x1a9", "accessList": [], "blockNumber": "0x10b1c9f", "from": "0x5888700be02f52c8adf85890886ef84a6b8a7829", "blockHash": "0x92c3d77ea218cdc0967ab74b6005bb393b92355047f206c7e2d59d41828e7fa9", "chainId": "0x1", "gasPrice": "0x34fdbf43d", "s": "0x7d86ae29a786a61b9e74a7a9e2cc4b39b7913aa3d4c3816ccb07528fed82048a", "to": "0xfc2068c3d47b575a60f6a4a7bf60dea0ac368e01", "type": "0x2", "v": "0x1", "value": "0x0", "gas": "0x1aad3", "hash": "0x2c77c0704aefbb26db460cbb71efdb488df968ad53d2c2b3f1e1172056b40b22", "input": "0x42842e0e0000000000000000000000005888700be02f52c8adf85890886ef84a6b8a7829000000000000000000000000d2d07e4d1bb0f40ac3e4aa7cc3ad05d348bfd2c3000000000000000000000000000000000000000000000000000000000000180b", "maxFeePerGas": "0x4712d1273", "r": "0x8ec58f95f6d9729a6eee075e6976658b6c5346cbc90eb68ac361a40af073b10e", "transactionIndex": "0xc1" }

ログデータの抜粋(一部省略):

run
2023-06-18 16:20:07 信息 断开WS连接 2023-06-18 16:20:07 信息 0xba07ca903f9eafbfa7d494bb26197713034b9ca2dd3c19bc0898af3f35b59343 transcationInfo: {"accessList":[],"from":"0xe2977d60182da068dfd78693f96362ee7a2e9644","nonce":"0xf","value":"0x0","blockHash":"0x92c3d77ea218cdc0967ab74b6005bb393b92355047f206c7e2d59d41828e7fa9","blockNumber":"0x10b1c9f","chainId":"0x1","hash":"0xba07ca903f9eafbfa7d494bb26197713034b9ca2dd3c19bc0898af3f35b59343","maxFeePerGas":"0x530c30b70","r":"0xf28bfdf372a5401a2e00675c6ebe8d5e73f2c955db44b1aa56240b9197d6cbc7","type":"0x2","v":"0x0","gas":"0x21079","gasPrice":"0x367b3783d","input":"0x657bb1130000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000001e0300000000000000000000000033c6eec1723b12c46732f7ab41398de45641fa42000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000041976bd7d021a5b94cbba72b291093b50a0ecf21d1c6cd8193fbfcd685c4723ce068feb249bdcace58c28eb3b6cc647e8c839b0826c84f8dfe4c31d57d1ac1f0111b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000648ebef50000000000000000000000000000000000000000000000000000000000000000","maxPriorityFeePerGas":"0x1dcd6500","s":"0x71d51246bb60e792f963a3c75c46fd8f557921ce6face7224c944e1768a76ca","to":"0x0b51eb9d0e54c562fedc07ceba453f05b70c4b79","transactionIndex":"0x40"} 2023-06-18 16:20:07 信息 0x2c77c0704aefbb26db460cbb71efdb488df968ad53d2c2b3f1e1172056b40b22 transcationInfo: {"maxPriorityFeePerGas":"0x5f5e100","nonce":"0x1a9","accessList":[],"blockNumber":"0x10b1c9f","from":"0x5888700be02f52c8adf85890886ef84a6b8a7829","blockHash":"0x92c3d77ea218cdc0967ab74b6005bb393b92355047f206c7e2d59d41828e7fa9","chainId":"0x1","gasPrice":"0x34fdbf43d","s":"0x7d86ae29a786a61b9e74a7a9e2cc4b39b7913aa3d4c3816ccb07528fed82048a","to":"0xfc2068c3d47b575a60f6a4a7bf60dea0ac368e01","type":"0x2","v":"0x1","value":"0x0","gas":"0x1aad3","hash":"0x2c77c0704aefbb26db460cbb71efdb488df968ad53d2c2b3f1e1172056b40b22","input":"0x42842e0e0000000000000000000000005888700be02f52c8adf85890886ef84a6b8a7829000000000000000000000000d2d07e4d1bb0f40ac3e4aa7cc3ad05d348bfd2c3000000000000000000000000000000000000000000000000000000000000180b","maxFeePerGas":"0x4712d1273","r":"0x8ec58f95f6d9729a6eee075e6976658b6c5346cbc90eb68ac361a40af073b10e","transactionIndex":"0xc1"} 2023-06-18 16:20:07 信息 0xbc42d5db10e5cb2e888c76005c522cb2474a0c0a7325feb867b618f69ff26f2a transcationInfo: {"accessList":[],"blockNumber":"0x10b1c9f","gas":"0x1cc12b","hash":"0xbc42d5db10e5cb2e888c76005c522cb2474a0c0a7325feb867b618f69ff26f2a","maxFeePerGas":"0x6ab262e5c","value":"0x0","v":"0x1","chainId":"0x1","from":"0xc1b634853cb333d3ad8663715b08f41a3aec47cc","input":"0x8f111f3c000000000000000000000000000000000000000000000000000000000003b83700000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000e0fa2000000000000000000000000e64a54e2533fd126c2e452c5fab544d80e2e4eb50000000000000000000000000000000000000000000000000000000004c6ff1c0000000000000000000000000000000000000000000000000000000004c70029000000000000000000000000000000000000000000000000000000000001822d005b1979341221e80ed20b20d832de88a8a4b535fe9990a90c165f3c95ad085ab9445c0a998c70edff76f1c2de3f4263d7e4fe3c3fb73fe7dcfbdede92371842fb883267f5408c8aaf08ba2f6c22463f19da98183d2302735615460d7380d6f9ff5e764e75bcaca9a93946cf644cd4d4448f314c4cf60cd0353f085aa0562d70e16a510b8bc4c2a09b5e7fafcd43f07dc1b5dd1782962af8f6fff7a6965bfc127e11501a72c64913d58e624333f9ec51687c7cb1bb4a9850541f1e03b2790ed4ee508052910dfe22542d900548d5243ca238811427491d49e98cf269ccab5b1724f0f9698120e406c00910c4090c0e84e0400e2706822d2a001a3964a0ca8101700a547342c2c1fff8934a988416f020a0c98f0909c7f529875f8443914e10b58145c79d38914d1fafbc9ee57ebcb377e4ac1cd252bdebe3c59e8e917fea7dbc7bf66dfc1846482a858645b95555b3ecc9ab4f9e2b0e3e78d68379b009e606a1cefe675670a5eabd5f5a2efa5d77a1084288480c98d01c70a3d8c6b854496e2a966dc9051b13b872b7c6c2c5d82676fd8e82c680514333db21db2006d23f42074021de7e61c54d88b01824d40f03d1505eb6ec6d0cb7ccd38deb821517a5e63d0e89f6bf0385f109c81ea36dd00e7a903a100290f5b47a940ed146ae9338ff8bc17a2b5bc457614d0831e743e485c0de84636b034400bf6bd192ff723045cc170e109aabf273dc9de19c9987038515b6613249f471f9ddeb31331cc1643902212d20241c417532ad7e4a9ac742b4b5f68e1019795cf9386dcf36037502c13ff51f50a2202b2c1cac1c0b38a21ec798deff778c9a6b679d16d0521d2df89c439f4f8f9425ed378f4194d03d00 2023-06-18 16:20:06 信息 0xff0945c3d682a37e18ee433d56c8bedbb93d9ac368af968ed8d53b655575e8e5 transcationInfo: {"gas":"0x5208","s":"0x63572e1fa060841b939cea0849154e55781fe0efcbdfe5ce6979b44ce0980e4a","transactionIndex":"0xa7","value":"0x113e9d515e400","blockHash":"0x92c3d77ea218cdc0967ab74b6005bb393b92355047f206c7e2d59d41828e7fa9","hash":"0xff0945c3d682a37e18ee433d56c8bedbb93d9ac368af968ed8d53b655575e8e5","nonce":"0x2","r":"0x698fe26331ad39ba89c4d30985b707792ea4ab09b25205727f8fac2a6120b54a","gasPrice":"0x35458af00","from":"0x228d93af92d03184c07aa9e39b3d2d61b666686d","input":"0x","to":"0x0246177b98a5e42835cdcfaac1c274d3e6c39486","v":"0x26","blockNumber":"0x10b1c9f","type":"0x0","chainId":"0x1"} ...

取引の詳細を解読する

前回のコースでは、Ethereum 上の保留中のトランザクションを監視し、WebSocket プロトコルを介してプッシュされたトランザクション ハッシュを取得し、トランザクション ハッシュに基づいて特定のトランザクションの詳細を照会する監視プログラムを作成しました。

次に、inputフィールド データがさらに解析されます。inputフィールド データはランダムな 16 進データのように見えますが、実際には呼び出された関数や入力パラメータなど、トランザクションの内容をエンコードします。

繰り返し広範囲に渡るテストの結果、WebSocket接続を通じてプッシュされるデータの適時性と量は、現在使用されているRPCノードと密接に関係していることがわかりました。2つの異なるRPCノードサービス(infuraやALCHEMYなど)が、同時に、受信したプッシュ データはまったく同じではありません。現在のシナリオでは大量のリクエストが生成されるため、より安定して高速な RPC サービスを使用する必要があります。 WebSocket 接続では、長時間保留されていた多くのトランザクション ハッシュもプッシュされます。eth_getTransactionByHashクエリを実行すると、多くの場合 null 値が返されます (FMZ および node.js でテスト済み)。

今回はalchemyRPC ノード:wss://eth-mainnet.g.alchemy.com/v2/oKmOQKbneVkxgHZfibs-iFhIlIAl6HDN。このノードは、WebSocket プロトコルと REST プロトコルの両方をサポートします。

Uniswap分散型取引所のルーティングスマートコントラクトを監視しますmulticall(uint256,bytes[])メソッドなので、まずこのメソッドの関数シグネチャ ハッシュを計算する必要があります。

// 取完整哈希值的前8个字符 // multicall: 0x5ae401dc var sigHash = "0x" + Encode("keccak256", "string", "hex", "multicall(uint256,bytes[])").slice(0, 8)

前回のレッスンの例に基づいて、いくつか変更を加えました。 WebSocket接続経由でプッシュされたメッセージを受信する場合は、var data = ws.read(-2)最新のデータを受信します。read()関数パラメータを -2 に設定すると、最新のデータがすぐに返されます。私たちが関心を持っているのは、multicall呼ばれたTransaction 、使用if (tx && tx.input.indexOf(sigHash) !== -1)判断フィルタリング。

2 つのカスタム関数を設計する必要があります。

  • calcAllFuncSigHash(): ABI に基づいてすべてのメソッドの署名ハッシュを計算します。
  • decodeCall(): デコード機能。

次に検出multicall呼び出されると、デコード操作を開始できます。最初のデコードmulticallメソッドパラメータ:deadlineそしてdatadeadlineタイムスタンプが分かりやすくなります。dataこれは別のエンコードされた呼び出しデータなので、引き続き使用する必要があります。decodeCall()関数のデコード。

完全な実装例:

javascript
var ws = null var arrLog = [] const ABI_Route = '[{"inputs":[{"internalType":"address","name":"_factoryV2","type":"address"},{"internalType":"address","name":"factoryV3","type":"address"},{"internalType":"address","name":"_positionManager","type":"address"},{"internalType":"address","name":"_WETH9","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"WETH9","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"approveMax","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"approveMaxMinusOne","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"approveZeroThenMax","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"approveZeroThenMaxMinusOne","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"callPositionManager","outputs":[{"internalType":"bytes","name":"result","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"paths","type":"bytes[]"},{"internalType":"uint128[]","name":"amounts","type":"uint128[]"},{"internalType":"uint24","name":"maximumTickDivergence","type":"uint24"},{"internalType":"uint32","name":"secondsAgo","type":"uint32"}],"name":"checkOracleSlippage","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"path","type":"bytes"},{"internalType":"uint24","name":"maximumTickDivergence","type":"uint24"},{"internalType":"uint32","name":"secondsAgo","type":"uint32"}],"name":"checkOracleSlippage","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"path","type":"bytes"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMinimum","type":"uint256"}],"internalType":"struct IV3SwapRouter.ExactInputParams","name":"params","type":"tuple"}],"name":"exactInput","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMinimum","type":"uint256"},{"internalType":"uint160","name":"sqrtPriceLimitX96","type":"uint160"}],"internalType":"struct IV3SwapRouter.ExactInputSingleParams","name":"params","type":"tuple"}],"name":"exactInputSingle","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"path","type":"bytes"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMaximum","type":"uint256"}],"internalType":"struct IV3SwapRouter.ExactOutputParams","name":"params","type":"tuple"}],"name":"exactOutput","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMaximum","type":"uint256"},{"internalType":"uint160","name":"sqrtPriceLimitX96","type":"uint160"}],"internalType":"struct IV3SwapRouter.ExactOutputSingleParams","name":"params","type":"tuple"}],"name":"exactOutputSingle","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"factoryV2","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"getApprovalType","outputs":[{"internalType":"enum IApproveAndCall.ApprovalType","name":"","type":"uint8"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"amount0Min","type":"uint256"},{"internalType":"uint256","name":"amount1Min","type":"uint256"}],"internalType":"struct IApproveAndCall.IncreaseLiquidityParams","name":"params","type":"tuple"}],"name":"increaseLiquidity","outputs":[{"internalType":"bytes","name":"result","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"int24","name":"tickLower","type":"int24"},{"internalType":"int24","name":"tickUpper","type":"int24"},{"internalType":"uint256","name":"amount0Min","type":"uint256"},{"internalType":"uint256","name":"amount1Min","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"internalType":"struct IApproveAndCall.MintParams","name":"params","type":"tuple"}],"name":"mint","outputs":[{"internalType":"bytes","name":"result","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"previousBlockhash","type":"bytes32"},{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"positionManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"pull","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"refundETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"selfPermit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"selfPermitAllowed","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"selfPermitAllowedIfNecessary","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"selfPermitIfNecessary","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"}],"name":"swapExactTokensForTokens","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"}],"name":"swapTokensForExactTokens","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepToken","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountMinimum","type":"uint256"}],"name":"sweepToken","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"uint256","name":"feeBips","type":"uint256"},{"internalType":"address","name":"feeRecipient","type":"address"}],"name":"sweepTokenWithFee","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"feeBips","type":"uint256"},{"internalType":"address","name":"feeRecipient","type":"address"}],"name":"sweepTokenWithFee","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"int256","name":"amount0Delta","type":"int256"},{"internalType":"int256","name":"amount1Delta","type":"int256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"uniswapV3SwapCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"unwrapWETH9","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountMinimum","type":"uint256"}],"name":"unwrapWETH9","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"feeBips","type":"uint256"},{"internalType":"address","name":"feeRecipient","type":"address"}],"name":"unwrapWETH9WithFee","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"uint256","name":"feeBips","type":"uint256"},{"internalType":"address","name":"feeRecipient","type":"address"}],"name":"unwrapWETH9WithFee","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"wrapETH","outputs":[],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]' function calcAllFuncSigHash(jsonABI) { var mapSigHash = {} for (var i in jsonABI) { var ele = jsonABI[i] if (typeof(ele["name"]) != "undefined") { if (ele["inputs"]) { var funcName = ele["name"] if (ele["inputs"].length == 0) { var methodId = "0x" + Encode("keccak256", "string", "hex", funcName + "()").slice(0, 8) mapSigHash[methodId] = {"argsTypeList": [], "argsNameList": [], "funcName": funcName} } else { var arr = [] var arrName = [] var argPrototype = [] for (var j in ele["inputs"]) { var inputType = ele["inputs"][j]["type"] if (inputType == "tuple") { var components = ele["inputs"][j]["components"] var tupleType = [] var protoType = [] for (var componentsIdx = 0; componentsIdx < components.length; componentsIdx++) { tupleType.push(components[componentsIdx]["type"]) protoType.push(components[componentsIdx]["name"] + " " + components[componentsIdx]["type"]) } arr.push("(" + tupleType.join() + ")") arrName.push(ele["inputs"][j]["name"]) // 原型 argPrototype.push("tuple" + "(" + protoType.join() + ")") } else { arr.push(inputType) arrName.push(ele["inputs"][j]["name"]) // 原型 argPrototype.push(inputType) } } var functionSignature = funcName + "(" + arr.join() + ")" var methodId = "0x" + Encode("keccak256", "string", "hex", functionSignature).slice(0, 8) mapSigHash[methodId] = {"argsTypeList": arr, "argsNameList": arrName, "funcName": funcName, "argPrototype": argPrototype} } } } } return mapSigHash } function decodeCall(input, abi) { var mapSigHash = calcAllFuncSigHash(JSON.parse(abi)) var methodId = input.slice(0, 10) var data = input.slice(10) var decodedArgs = {} var infoMethod = mapSigHash[methodId] if (typeof(infoMethod) == "undefined") { return [methodId, mapSigHash] } var arr = [] for (var i = 0; i < infoMethod["argsTypeList"].length; i++) { if (infoMethod["argsTypeList"][i].startsWith("(")) { arr.push(infoMethod["argPrototype"][i]) } else { arr.push(infoMethod["argsTypeList"][i]) } } if (arr.length == 0) { return {"funcName": infoMethod["funcName"], "args": decodedArgs} } var args = exchange.IO("decode", arr.join(), data) if (!Array.isArray(args)) { args = [args] } if (args.length != infoMethod["argsNameList"].length) { Log("args:", args) Log("infoMethod:", infoMethod) throw "解码后的args与argsNameList不等" } for (var i = 0; i < infoMethod["argsNameList"].length; i++) { var key = infoMethod["argsNameList"][i] var value = args[i] decodedArgs[key] = value } return {"funcName": infoMethod["funcName"], "args": decodedArgs} } function main () { // {"jsonrpc": "2.0", "id": 1, "method": "eth_subscribe", "params": ["xxxxx"]} , "xxxxx" 是订阅的具体消息 var payload = {"jsonrpc": "2.0", "id": 1, "method": "eth_subscribe", "params": ["newPendingTransactions"]} // 使用alchemy服务 ws = Dial("wss://eth-mainnet.g.alchemy.com/v2/oKmOQKbneVkxgHZfibs-iFhIlIAl6HDN" + "|reconnect=true&payload=" + JSON.stringify(payload)) if (!ws) { throw "websocket链接alchemy失败!" } // eth_getTransactionByHash 调用计数 var getTransactionCounter = 0 // 起始时间戳 var beginTS = new Date().getTime() // 计算函数签名哈希 var sigHash = "0x" + Encode("keccak256", "string", "hex", "multicall(uint256,bytes[])").slice(0, 8) Log("sigHash:", sigHash) // 循环获取消息 while (true) { var msg = "" var recv = null // 接收推送的消息,使用read参数-2,立即返回最新数据 var data = ws.read(-2) if (data && data != "") { var ts = new Date().getTime() if (ts - beginTS >= 1000) { getTransactionCounter = 0 beginTS = ts } // 根据txHash查询交易详情 if (ts - beginTS < 1000 && getTransactionCounter >= 100) { Sleep(1000) getTransactionCounter = 0 beginTS = ts } var obj = JSON.parse(data) if (obj["params"] && obj["params"]["result"]) { var txHash = obj["params"]["result"] var tx = exchange.IO("api", "eth", "eth_getTransactionByHash", txHash) if (tx && tx.input.indexOf(sigHash) !== -1) { // 解码交易详情 arrLog = [] var decodedInput = decodeCall(tx.input, ABI_Route) // Log("----------------", txHash, "/", decodedInput["funcName"], "----------------", "#FF0000") arrLog.push("----------------" + txHash + "/" + decodedInput["funcName"] + "----------------" + "#FF0000") arrLog.push(tx.from + " -> " + tx.to) for (var i = 0; i < decodedInput["args"]["data"].length; i++) { var calldata = "0x" + decodedInput["args"]["data"][i] var decodedCalldata = decodeCall(calldata, ABI_Route) // Log("----------------", decodedCalldata["funcName"], "----------------", "#FF0000") arrLog.push("----------------" + decodedCalldata["funcName"] + "----------------" + "#FF0000") for (var key in decodedCalldata["args"]) { // Log(key, decodedCalldata["args"][key]) arrLog.push(key + ": " + JSON.stringify(decodedCalldata["args"][key])) } } // 输出日志 for (var logIdx = arrLog.length - 1; logIdx >= 0; logIdx--) { Log(arrLog[logIdx]) } } getTransactionCounter++ } recv = obj } else if (data == null) { msg = "缓冲区队列空了,时间:" + _D() } LogStatus(_D(), ", msg:", msg, ", recv:", recv) } } function onexit() { Log("断开WS连接") ws.close() } function onerror() { Log("断开WS连接") ws.close() for (var logIdx = arrLog.length - 1; logIdx >= 0; logIdx--) { Log(arrLog[logIdx]) } }

テストを実行するために実際のディスクを作成します。

run
2023-06-20 17:01:00 信息 ----------------0x5288a7bd6e0f57162ca763df722de73793e542734d7d2b7af5755664e2e67910/multicall---------------- 2023-06-20 17:01:00 信息 0x851b594033d57c98af753bcb3a7d0237a615de32 -> 0x68b3465833fb72a70ecdf485e0e4c7bd8665fc45 2023-06-20 17:01:00 信息 ----------------exactInputSingle---------------- 2023-06-20 17:01:00 信息 params: {"tokenOut":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2","fee":"10000","recipient":"0x0000000000000000000000000000000000000002","amountIn":"8952087000296027130940868","amountOutMinimum":"41638694112306829","sqrtPriceLimitX96":"0","tokenIn":"0xe1283567345349942acdfad3692924a1b16cf3cc"} 2023-06-20 17:01:00 信息 ----------------unwrapWETH9---------------- 2023-06-20 17:01:00 信息 amountMinimum: "41638694112306829" 2023-06-20 17:01:00 信息 recipient: "0x851b594033d57c98af753bcb3a7d0237a615de32" 2023-06-20 16:59:03 信息 ----------------0x55e0c4a38a17d3aa6e8f558a66c77e9defa9f8f6e347536363ac1b921de9aaf3/multicall---------------- 2023-06-20 16:59:03 信息 0x27457ada2dd725c7d0f28e1737bdd0bf583c0f0b -> 0x68b3465833fb72a70ecdf485e0e4c7bd8665fc45 2023-06-20 16:59:03 信息 ----------------swapExactTokensForTokens---------------- 2023-06-20 16:59:03 信息 amountIn: "816769666850161" 2023-06-20 16:59:03 信息 amountOutMin: "40404501509302321" 2023-06-20 16:59:03 信息 path: ["0x7863e06bca47ded821fcb53ab788eeb371243eda","0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"] 2023-06-20 16:59:03 信息 to: "0x27457ada2dd725c7d0f28e1737bdd0bf583c0f0b" 2023-06-20 16:58:25 信息 sigHash: 0x5ae401dc

スクリーンショット:

img

トランザクションハッシュは0x5288a7bd6e0f57162ca763df722de73793e542734d7d2b7af5755664e2e67910このトランザクションでは、入力データにはコールが含まれていますmulticallメソッド呼び出し。トランザクションの方向は次のとおりです: 0x851b594033d57c98af753bcb3a7d0237a615de32 -> 0x68b3465833fb72a70ecdf485e0e4c7bd8665fc45。0x68b3465833fb72a70ecdf485e0e4c7bd8665fc45つまり、Uniswapのルーティングコントラクトアドレスです。

img

分析multicallパッケージがコントラクトを呼び出すexactInputSingleそしてunwrapWETH9メソッド、およびこれらのメソッドの特定のパラメータ。

----------------exactInputSingle---------------- params: { "tokenOut":"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "fee":"10000", "recipient":"0x0000000000000000000000000000000000000002", "amountIn":"8952087000296027130940868", "amountOutMinimum":"41638694112306829", "sqrtPriceLimitX96":"0", "tokenIn":"0xe1283567345349942acdfad3692924a1b16cf3cc" } ----------------unwrapWETH9---------------- amountMinimum: "41638694112306829" recipient: "0x851b594033d57c98af753bcb3a7d0237a615de32"

興味のある学生は、この例を変更および拡張して、より多くのトランザクションを監視し、これらのオンチェーン操作を分析できます。

Comment
All comments (0)
No data
No data
  • 1
iPhone Download
Forums
PINE Language
© 2015 - ∞ INVENTOR PTE LTD (SG)