Type/to search
8
Follow
1364
Followers
Gunakan FMZ untuk memulai pengembangan web3 berbasis Ethereum dengan mudah
Original
Created 2023-03-28 13:32:48  Updated 2024-11-11 22:28:24
 0
 4375

img

Panduan EtherEaseWithFMZ

Gunakan FMZ untuk memulai pengembangan web3 berbasis Ethereum dengan mudah

Ethereum adalah platform kontrak pintar berdasarkan teknologi blockchain, yang menyediakan cara terdesentralisasi untuk menulis dan menyebarkan kontrak pintar. Kontrak pintar adalah program komputer khusus yang dapat dieksekusi secara otomatis pada blockchain dan dapat menerapkan berbagai logika bisnis tanpa perlu mempercayai pihak ketiga.

Platform Perdagangan Kuantitatif Inventor (FMZ.COM) menyediakan API yang mudah digunakan yang memudahkan pengembang untuk berinteraksi dengan blockchain Ethereum dan ekosistemnya. Mewujudkan fungsi seperti akses ke bursa terdesentralisasi (DEX), memperoleh data on-chain, dan mengirimkan transaksi.

Contoh dalam tutorial ini menggunakanJavaScriptPenulisan bahasa, penggunaan lingkungan pengujianJaringan Utama EthereumJaringan Uji Goerli. Anda juga dapat melihat antarmuka API yang digunakan dalam tutorial serta deskripsi terkait dan contoh kode dalam dokumentasi API platform FMZ.


Memulai dengan FMZ

Sebelum mempelajari cara menggunakan platform perdagangan kuantitatif FMZ, kita perlu memahami beberapa konsep dasar:

1. Arsitektur platform perdagangan kuantitatif FMZ

Setelah mendaftar dan masuk ke situs web resmi platform perdagangan kuantitatif FMZ (https://www.fmz.com), Anda dapat menggunakan berbagai fungsi platform. Situs web FMZ merupakan ujung tombak manajemen keseluruhan sistem, dan program-program yang ditulis oleh pengguna benar-benar dijalankan di host. Host adalah program perangkat lunak yang dapat digunakan pada berbagai perangkat, seperti server, komputer, dan lain-lain. Saat pengguna menulis program dan membuat contoh yang berjalan di situs web FMZ, platform FMZ akan berkomunikasi dengan host dan memulai contoh program di host.

img

2. Tuan rumah

Jika Anda ingin menjalankan program, Anda harus memasang host. Pemasangan host juga sangat mudah, dan ada tutorial pemasangan di platform. Anda juga dapat menggunakan "host penerapan satu-klik" yang disediakan di FMZ untuk menerapkan secara otomatis menggunakan server yang disewa oleh FMZ.

  • Menyebarkan host pada perangkat pribadi

    Program kustodian dapat disebarkan dan dijalankan di server, komputer pribadi, dan perangkat lain, selama jaringannya normal (target terkait harus dapat diakses, seperti antarmuka pertukaran, alamat node, dll.). Langkah-langkah utama penyebaran adalah:

    1. Masuk atau buka perangkat tempat Anda ingin menyebarkan program host, sepertiMasuk ke serveratauNyalakan komputer dan masuk ke sistem operasi
    2. Unduh versi program host yang sesuai (tergantung pada sistem operasi perangkat), halaman unduhan: https://www.fmz.com/m/add-node
      img
    3. File yang diunduh adalah paket terkompresi, yang perlu didekompresi.
    4. Jalankan program host. Program host adalah program yang disebutrobotberkas yang dapat dieksekusi. Konfigurasikan alamat komunikasi kustodian. Alamat komunikasi ini unik untuk setiap akun FMZ. Setelah masuk ke FMZ,https://www.fmz.com/m/add-nodeHalaman tersebut dapat melihat alamatnya sendiri (misalnya:./robot -s node.fmz.com/xxxxxRangkaian alamat ini, di sinixxxxxKonten lokasi ditampilkan berbeda untuk setiap akun FMZ). Terakhir, Anda perlu memasukkan kata sandi akun FMZ. Setelah mengonfigurasinya, jalankan program host.
  • Gunakan fungsi "penempatan kustodian satu klik" dari platform FMZ

    Tambahkan halaman kustodian pada platform FMZ, alamat:https://www.fmz.com/m/add-node

    img

3. Alat Debugging

Platform perdagangan kuantitatif FMZ menyediakan alat debugging gratis yang mendukungJavaScriptTypeScriptHalamannya adalah: https://www.fmz.com/m/debug, karena membuat instance dan menjalankannya ditagih. Alat debugging ini dapat digunakan untuk pengujian dan pembelajaran selama periode pembelajaran awal. Alat debugging tidak berbeda dengan pembuatan instance, kecuali waktu berjalannya dibatasi hingga 3 menit.

menggunakanTypeScriptSaat menggunakan bahasa tersebut, Anda perlu menuliskannya di baris pertama kode// @ts-checkUntuk beralih keTypeScriptMode, jika tidak diubah, defaultnya adalahJavaScriptbahasa.

4. Pertukaran

Di FMZ, "pertukaran" merupakan konsep umum. Untuk pertukaran CEX, ini merujuk pada konfigurasi akun pertukaran tertentu. Untuk web3, pertukaran ini mengacu pada informasi konfigurasi, termasuk alamat node dan konfigurasi kunci privat.

Saat masuk ke platform FMZ,https://www.fmz.com/m/add-platformHalaman, Anda dapat mengonfigurasikan informasi pertukaran, di mana pertukaran merupakan konsep umum.

img

memilihWeb3, konfigurasikan alamat simpul RPC dan kunci privat. Anda dapat mengeklik "Informasi sensitif dienkripsi dan disimpan menggunakan kunci privat independen" di sudut kanan bawah untuk melihat mekanisme keamanan.

Node dapat dibangun sendiri atau disediakan oleh penyedia layanan node. Ada banyak penyedia layanan node, seperti:Infura. Setelah mendaftar, Anda dapat melihat alamat node akun Anda. Ada mainnet dan testnet, yang mana lebih praktis. Konfigurasikan alamat node ini pada gambar di atas.Rpc Addressdalam kontrol. Tag dapat diberi nama sendiri untuk membedakan objek pertukaran yang dikonfigurasi.

img

Pada gambarhttps://mainnet.infura.io/v3/xxxxxxxxxxxxxIni adalah alamat node RPC mainnet ETH Infura yang bersifat pribadi.


Menggunakan FMZ untuk berinteraksi dengan Ethereum

Setelah menerapkan program kustodian dan mengonfigurasi objek pertukaran, Anda dapat menggunakan "alat debugging" FMZ.COM untuk pengujian. Panggil metode Ethereum RPC untuk berinteraksi dengan Ethereum. Selain beberapa metode RPC yang tercantum dalam bab ini, Anda dapat merujuk ke dokumentasi untuk metode RPC lainnya, sepertihttps://www.quicknode.com/docs

Mari kita ambil beberapa contoh sederhana dan mulai dengan dasar-dasarnya. Ada cara untuk mengakses web3 untuk berbagai bahasa dan alat, seperti yang ditunjukkan pada gambar:

img

Panggilan metode RPC juga dienkapsulasi pada FMZ. Fungsi-fungsi ini dienkapsulasi dalam fungsi API FMZexchange.IOtengah. Metode pemanggilannya adalahexchange.IO("api", "eth", ...). Parameter pertama sudah diperbaiki."api", parameter kedua sudah diperbaiki"eth", parameter lainnya bergantung pada metode RPC spesifik yang dipanggil.

Untuk mengeluarkan informasi, kami menggunakan platform FMZLogfungsi,LogFungsi ini dapat memasukkan beberapa parameter dan kemudian menampilkannya di area log pada halaman "Debug Tool" atau "Real Trading" di platform FMZ. Halaman "Debug Tool" akan menjadi alat utama untuk pengujian kami.

eth_getBalance

Etereumeth_getBalanceMetode ini digunakan untuk memeriksa saldo ETH suatu alamat di Ethereum. Metode ini memerlukan dua parameter yang harus dimasukkan.

  • Alamat yang akan ditanyakan.
  • Tag, biasanya "terbaru".

Yuk cek siapa pendiri EthereumV神Alamat dompet ETH, alamat yang diketahui adalah:0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045

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

Kustodian telah diterapkan (pada gambar: linux/amd64 ...) dan objek pertukaran telah dikonfigurasi (pada gambar: uji Web3). Uji kode pada alat debugging:

img

Klik tombol "Execute" untuk menjalankan kode ini dan menampilkan hasilnya:

ethBalance: 0x117296558f185bbc4c6

LogFungsi mencetakethBalanceNilai variabelnya adalah:0x117296558f185bbc4c6, yang merupakan tipe string. YaSaldo ETH dalam nilai heksadesimal,olehweiSebagai satu kesatuan,1e18 weiadalah 1ETH. Oleh karena itu, perlu diubah menjadi saldo ETH desimal yang dapat dibaca.

AkanethBalanceUbah menjadi data yang dapat dibaca:

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

Di atashttps://etherscan.io/Pertanyaan:

img

Namun, pemrosesan ini akan memiliki penyimpangan karena keakuratan bahasa itu sendiri, sehingga platform FMZ memiliki dua fungsi bawaan untuk memproses data:

  • BigInt: Mengonversi string heksadesimal menjadi objek BigInt.
  • BigDecimal: Mengonversi objek tipe numerik menjadi objek BigDecimal yang dapat dioperasikan.

Sesuaikan kode lagi:

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_chainIdDannet_versionPenggunaannya serupa, jadi kami mengujinya bersama. Kedua fungsi tersebut mengembalikan ID blockchain yang terhubung dengan node RPC saat ini. Perbedaannya adalahnet_versionMengembalikan Id desimal.eth_chainIdMengembalikan ID heksadesimal.

Nama jaringan sesuai dengan ID rantai

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

Gunakan jaringan uji Ethereum yang dikonfigurasigoerliUji simpul:

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

Panggilaneth_gasPriceMetode untuk menanyakan rantai saat inigas 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)) }

Di sini kita menulis fungsi untuk mengubah string heksadesimal menjadi nilai yang dapat dibaca:toAmount. Hal lain yang perlu diperhatikan adalah bahwa unit harga gas adalahwei, jadi parameternyadecimalsParameter aktual yang terkait dapat dilewatkan sebagai 0.

eth_blockNumbe

eth_blockNumbeDigunakan untuk menanyakan tinggi blok.

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

Jalankan dalam debugger:

img

https://etherscan.io/Pada pertanyaan:

img

eth_getBlockByNumber

Kueri informasi blok.

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

Informasi berikut dapat diperoleh dengan menjalankan "Debug Tool":

img


Baca informasi kontrak

Ada sejumlah besar aplikasi kontrak pintar yang berjalan di Ethereum.ENSadalah salah satunya.ENS, yaitu Ethereum Name Service, adalah layanan resolusi nama domain terdesentralisasi yang berbasis pada blockchain Ethereum.
Ingat contoh dalam tutorial saat kami menanyakan saldo dompet pendiri Ethereum Vitalik Buterin? Salah satu alamat dompet Vitalik adalah:0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045. Jadi bagaimana kita tahu alamat ini? Faktanya, melaluiENSKontrak pintar, menggunakan nama yang intuitifvitalik.eth(vitalik adalah nama Vitalik) untuk melakukan penyelidikan.

Konten berikut dalam bab ini menggunakan lingkungan jaringan utama Ethereum.ENSDokumen tersebut menunjukkan bahwa nama domain Ethereum yang akan ditanyakan perluHashing Names, gunakan kode berikut untukvitalik.ethNamanya diproses.

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

Pada contoh kode di atas, kita melihat fungsi lain yang tidak dikenalEncodeFungsi ini adalah fungsi API dari platform FMZ, yang secara khusus digunakan untuk melakukan operasi pengodean pada platform FMZ. Fungsi ini mendukung beberapa metode pengodean dan beberapa algoritma hash.

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

Menurut dokumentasi ENS, gunakansha3.keccak256Algoritma memproses data.

PanggilannameHashFungsi, misalnya:Log(nameHash("vitalik.eth")), kita bisa mendapatkan:ee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835, Anda perlu menambahkan awalan "0x".0xee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835Sebagai kontrak pintar ENSresolverParameter metode.

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

Menurut dokumen ENS, alamat kontrak aplikasi kontrak pintar ENS adalah:0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e. Dalam menyebut kontrak pintarresolverSebelum kita melanjutkan, kita perlu menyiapkan kontraknyaABI

Mendaftarkan ABI

Setelah mengetahui ini, saya jadi bertanya, apa itu kontrak pintar?ABIKain wol?

desc
ABI,即应用程序二进制接口(Application Binary Interface),是智能合约与外部世界进行通信的接口标准。 智能合约的 ABI 定义了合约的函数接口、参数类型、返回值等信息,以及调用合约的方式和参数传递方式等规范。 智能合约的 ABI 通常以 JSON 格式存储,包含以下信息: 合约的函数接口:函数名、参数列表、返回值等信息。 函数参数类型:如 uint256、bool、string 等。 函数的输入参数和输出参数的编码方式:智能合约使用一种称为 Solidity ABI 的编码方式来编码函数的输入参数和输出参数, 以便与以太坊网络进行交互。 在以太坊网络中,使用智能合约的 ABI 来调用合约的函数。当需要调用合约函数时,需要提供函数名和函数参数,以及将函数参数按照 ABI 编码方式编码后的字节码。 以太坊节点会将这些信息打包成一笔交易,并将交易发送到以太坊网络中执行。 智能合约的 ABI 在 Solidity 语言中可以通过 interface 关键字来定义。以太坊开发工具如 Remix IDE、Truffle 等也提供了 ABI 编辑和生成工具, 使得开发者可以方便地创建和使用智能合约的 ABI。

Ekstrak yang berikut ini dari ENS ABI:resolverABI penuh juga dapat digunakan dihttps://etherscan.io/Anda dapat menanyakan ABI kontrak di GitHub, atau memperoleh ABI melalui cara lain (misalnya, dokumen proyek yang relevan).

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"}]`

Di sini kita harus mempelajari metode pemanggilan baru pada platform FMZ.exchange.IO("abi", address, abiContent), gunakan metode ini untuk mendaftarkan ABI,addressParameternya adalah alamat kontrak pintar.abiContentParameternya adalah ABI kontrak pintar yang sesuai (string).

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智能合约的地址

Memanggil metode kontrak pintar

Selanjutnya, Anda dapat memanggil kontrak pintar ENSresolvermetode yang mengembalikanENS: Public ResolverAlamat kontrak.

img

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

menggunakanENS: Public ResolverKontraktualaddrMetode untuk mendapatkan alamat dompet Vitalik. Untuk meneleponENS: Public ResolverKontrak tersebut masih perlu mendaftarkan ABI terlebih dahulu. Informasi ABI dari kontrak pintar ini masih dapat ditemukan dihttps://etherscan.io/Mendapatkan.

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

Panggilan terakhirENS: Public ResolverKontraktualaddrMetode, parameternya masihensNode

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

Keluaran fungsi log:

img

run
vitalikAddress: 0xd8da6bf26964af9d7eed9e03e53415d37aa96045

Kode lengkap untuk memanggil 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) }

Kirim ETH

Pada bab-bab kursus sebelumnya, kita telah mempelajari cara mengonfigurasi kunci privat. Untuk objek pertukaran yang dikonfigurasi, bagaimana kita mengetahui alamat dompet yang sesuai dengan kunci privat ini? Tersedia di FMZexchange.IO("address")Fungsi ini memperoleh alamat dompet yang sesuai dengan kunci pribadi yang dikonfigurasi.

Karena isi bab berikut ini menggunakanGoerliPengujian lingkungan jaringan, jadi node yang saya gunakan adalah:https://goerli.infura.io/v3/*******Infura menetapkan alamat node yang berbeda untuk setiap pengguna terdaftar.*******Konten spesifik disembunyikan.

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

img

Setelah Anda mengetahui alamat dompet Anda, Anda dapat menggunakan metode RPC Ethereumeth_getTransactionCountMenanyakan jumlah transaksi dari alamat dompet. Jumlah ini sangat umum digunakan di Ethereum. Faktanya, jumlah ini adalah jumlah yang perlu dimasukkan saat mentransfer uang.nonceParameter, Di Ethereum, nonce adalah angka yang digunakan untuk memastikan bahwa setiap transaksi bersifat unik. Ini adalah angka yang terus bertambah dan otomatis bertambah setiap kali transaksi baru dikirim. Oleh karena itu, ketika Anda mengirim transaksi ke kontrak pintar, Anda perlu memberikan nonce untuk memastikan bahwa transaksi tersebut unik dan dalam urutan yang benar. Dalam beberapa data dan dokumen kita dapat menemukan:

https://goethereumbook.org/en/

img

Berikut adalah pustaka Ethereum dalam bahasa GoPendingNonceAtFungsi sebenarnya memanggileth_getTransactionCountmetode. Pada kursus sebelumnya, kita juga mempelajari cara memanggil metode RPC. Kita akan menggunakannya lagi di sini.exchange.IO("api", "eth", ...)fungsi.

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

Sebelum menjelaskan operasi transfer, mari kita pahami beberapa konsep secara singkat. Saat mentransfer uang di Ethereum, sejumlah token ETH akan dikonsumsi (sebagai biaya gas). Biaya gas ditentukan oleh dua parameter:

  • gasPrice

    Namun, biaya gas pada jaringan Ethereum selalu berfluktuasi berdasarkan permintaan pasar dan apa yang bersedia dibayar pengguna, jadi menulis biaya gas tetap ke dalam kode terkadang tidaklah ideal. Kita bisa menggunakan apa yang kita pelajari sebelumnyaeth_gasPriceMetode yang dapat memperoleh harga gas rata-rata.

  • gasLimit

    Batas gas untuk transfer eter standar adalah 21.000 unit.

MengertinoncegasPricegasLimitDengan konsep ini, Anda dapat menguji transfer. Fungsi transfer yang sangat sederhana dan mudah digunakan dienkapsulasi pada FMZ.

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

Ketika digunakan untuk transfer,exchange.IOParameter ketiga selalu "kirim".toAddressParameter adalah alamat yang menerima ETH selama transfer.toAmountJumlah ETH yang ditransfer.

noncegasPricegasLimitParameter ini dapat menggunakan nilai yang diperoleh secara otomatis oleh sistem secara default di FMZ. Anda juga dapat menentukan:

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

Selanjutnya, kami mentransfer sejumlah ETH ke alamat tertentu di jaringan uji 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 }

Karena unit jumlah transfer Ethereum adalahwei, Anda perlu menggunakan fungsi kustomtoInnerAmountDiproses sebagaiweiNilai unit.

adahttps://etherscan.io/Kueri Hash Transaksi:0xa6f9f51b00d8ae850b0f204380b59da98f4bbce34b813577d3d948f61de4734e

img

Anda juga dapat menulis kode untuk menanyakan hash transfer0xa6f9f51b00d8ae850b0f204380b59da98f4bbce34b813577d3d948f61de4734e,menggunakaneth_getTransactionReceiptMetode untuk menanyakan.

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

Hasil kueri:

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": [] }

Deskripsi setiap bidang:

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 - 值的类型

Memanggil kontrak pintar Ethereum

Kami adalahBaca informasi kontrakBagian ini menggunakan contoh lengkap untuk memanggil metode kontrak ENS yang diterapkan pada Ethereum untuk memperoleh alamat dompet Vitalik. Metode ini termasuk dalamReadMetode, memanggil metode ini tidak perlugas(Ingat apa yang kita bicarakan tentang gas sebelumnya?). Pada bagian ini kita akan menyebutkan beberapa kontrak pintar di EthereumWriteMetode dan pembayarangas. Operasi ini akan diverifikasi oleh setiap node dan penambang di seluruh jaringan dan mengubah status blockchain.

ERC20

Untuk kontrak ERC20 (kontrak token ERC20), platform FMZ mencantumkan ABI kontrak ERC20 sebagai ABI yang umum digunakan dan langsung membangunnya ke dalam sistem, sehingga menghilangkan langkah pendaftaran ABI. Kita juga telah mempelajari tentang ABI pada tutorial sebelumnya. Saat kita memanggil metode kontrak ENS, pertama-tama kita mendaftarkan ABI dari kontrak ENS.

Untuk memahami ABI dengan lebih jelas, Anda dapat memeriksanya sebelum menggunakannya. Berikut ini adalah ABI kontrak ERC20:

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"}]

Konten berikut dalam bab ini digunakanGoerliLingkungan Testnet.

balanceOf

Selanjutnya, mari kita berlatih lagi cara menyebut kontrak.ReadMetode untuk membaca informasi kontrak dan memanggil kontrak ERC20balanceOfMetode untuk menanyakan saldo token,balanceOfMetode ini hanya memiliki satu parameter, tetapi tidak diberi nama. Dari tipenya, kita dapat melihat bahwa itu adalah alamat (yaitu, alamat token yang akan ditanyakan). Karena data yang dikembalikan tidak dalam satuan satu token, data presisi token juga diperlukan untuk konversi. Presisi token dapat dihitung menggunakan kontrak ERC20decimalsAkuisisi metode. Kami menggunakan testnet EthereumgoerliUjilah, dan perhatikan bahwa alamat kontrak token mungkin berbeda pada rantai yang berbeda.

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

Dengan menjalankan kode di atas, Anda dapat menanyakan saldo token WETH dan LINK di dompet saat ini:

Presisi WETH: 18 wethBalance: 0
Akurasi LINK: 18 linkSaldo: 51.41374973681053

deposit

Anda dapat melihat bahwa saldo token WETH di dompet ini adalah 0. Selanjutnya, kami terus berinteraksi dengan kontrak pintar ERC20 dari token WETH. Kali ini kami memanggil metode Write type:deposit
depositSederhananya, fungsi metode ini adalah mengubah sejumlah ETH menjadi WETH.depositMetode ini tidak memiliki parameter (yang dapat diamati dengan melihat ABI), dan metode ini memiliki atribut berikut:payableuntuktrueOleh karena itu, Anda perlu menetapkan jumlah transfer ETH (payableAmount) saat memanggil untuk menentukan jumlah ETH yang akan disetorkan.

Catatan saat memanggil metode kontrak pintar:
Jika metode yang dipanggil memiliki atribut payable, Anda perlu menambahkan nilai transfer ETH setelah nama metode (parameter keempat fungsi exchange.IO), yang dapat berupa tipe numerik atau nilai string.

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

Presisi WETH: 18 wethBalance: 0
Ketepatan ETH: 18 ethBalance: 0.14333094664072302
Transaction Hash: 0xaf15b0b0e25a81eda583295e82b249e2d02e4eafebecc906470ccc2c89e23563

img

Tanyakan kembali saldo WETH dan ETH:

Presisi WETH: 18 wethBalance: 0,01
Ketepatan ETH: 18 ethBalance: 0.1333309358060905

PanggilandepositSebelumWETHadalah 0,ETHadalah 0.14333094664072302, memanggildepositsetelahWETHadalah 0,01,ETHYaitu 0,1333309358060905. Anda dapat melihat bahwa 0,01 telah berhasilETHDiganti denganWETH

transfer

Token ERC20 juga dapat ditransfer menggunakantransferMetode untuk mentransfer ke alamat ini0x4D75a08E870674E68cAE611f329A27f446A668130,01 token WETH.transferMetode ini memiliki dua parameter, parameter pertamadstApakah alamat dompet penerima transfer, parameter keduawadIni adalah jumlah transfer.

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

Contoh di atas menggunakan fungsi kustomwaitMinedSebenarnya kita tidak asing lagi dengan fungsi dari fungsi ini. Ingateth_getTransactionReceiptMetode? Fungsi dari fungsi kustom waitMined ini adalah untuk menunggu hasil Hash Transaksi yang diteruskan.

Untuk transfer WETH ini, pembaca yang tertarik juga dapat menanyakan Hash Transaksi0x2fafb62b548a1fffb0f3189429e3c5a4f57ddafb0acbc0678d8b3cf0a2f7c92cuntuk melihat detailnya (perhatikan ini ada di testnet goerli).

withdraw

Kali ini kita menaruhWETHMenukarkanETH,menggunakanwithdrawmetode yang hanya memiliki satu parameterwad, secara sederhana, digunakan untuk mengatur berapa banyak ETH yang akan ditukar kembali.

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

Anda dapat melihat kode di atas dan sebelumnyadepositContoh metode pada dasarnya sama, kecuali metode yang dipanggil pada langkah terakhir diubah menjadiwithdraw, sebelum menelepon:

Presisi WETH: 18 wethBalance: 0,01
Ketepatan ETH: 18 ethBalance: 0.11322979983231546

Tanya lagi:

Presisi WETH: 18 wethBalance: 0
Ketepatan ETH: 18 ethBalance: 0.1231207156449464

Anda dapat melihat bahwa 0,01WETHBeralih kembaliETH

Uniswap V3

Uniswap V3Ini adalah protokol perdagangan terdesentralisasi yang dibangun di atas blockchain Ethereum untuk perdagangan dan penyediaan likuiditas mata uang kripto. Terdiri dari serangkaian kontrak pintar, termasuk kontrak inti, kontrak kumpulan, kontrak pabrik, kontrak perutean, dll.

Sedang digunakanUniswapKontrak-kontrak berikut terutama digunakan untuk menanyakan harga pertukaran terkini dan melakukan operasi pertukaran:

  • Router(Kontrak Rute)
    Ini adalah kontrak yang digunakan untuk mengeksekusi transaksi, yang memungkinkan pengguna untuk melakukan operasi transaksi dengan menentukan jalur dan parameter transaksi.
  • Pool(Kontrak Kolam Renang)
    Kontrak kolam renang adalahUniswapKomponen utama blockchain Ethereum yang digunakan untuk menyimpan dan mengelola likuiditas untuk pasangan aset tertentu. Setiap pasangan aset memiliki kontrak kumpulan yang sesuai, yang berisi informasi seperti dana yang disediakan oleh penyedia likuiditas, kisaran harga, pengaturan biaya, dll. Kontrak pool bertanggung jawab untuk memproses transaksi, menghitung status pool dana, dan memastikan kelancaran pelaksanaan transaksi.
  • Factory(Kontrak Pabrik)
    Kontrak pabrik digunakan untuk membuat dan mengelolaUniswapKontrak kontrak kolam renang. Saat pengguna ingin membuat pasangan aset baru, mereka menerapkan kontrak kumpulan baru dengan berinteraksi dengan kontrak pabrik. Kontrak pabrik bertanggung jawab untuk mengoordinasikan pembuatan dan inisialisasi kontrak kumpulan, yang memungkinkan pengguna membuat pasangan aset baru secara dinamis.

Berdasarkan apa yang telah kita pelajari sebelumnya, mari kita tinjau cara mendaftarkan kontrak pintar dalam kode strategi platform perdagangan kuantitatif FMZ.ABIKami telah menjelaskan cara memperoleh ABI kontrak pintar di kursus sebelumnya, jadi kami tidak akan mengulanginya di sini.
Tiga pendaftaran diperlukanUniswapKontrak CerdasABI, menggunakan mainnet Ethereum sebagai contoh:

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 }

Kode di atas mendaftarkan ABI kontrak pabrik, kontrak perutean, dan kontrak kumpulan, dan melakukan beberapa pengujian. Dapat diamati bahwa kontrak routing dan kontrak poolfactoryMetode kembali0x1F98431c8aD98523631AE4a59f267346ea31F984Alamat ini adalah kontrak pabrik Uniswap (dalam kodecontractV3FactoryAddressvariabel).

javascript
var contractV3FactoryAddress = "0x1F98431c8aD98523631AE4a59f267346ea31F984"

Setelah mendaftarkan ABI kontrak pintar, pertama-tama mari kita lihat penggunaannyaUniswap V3Untuk operasi pertukaran, kami menggunakan konten berikutERC20Pertukaran token (di mainnet Ethereum) digunakan sebagai skenario khusus.

PertanyaanUniswap V3Otorisasi kontrak perutean

adaERC20Dalam kontraknya,allowanceFungsi ini digunakan untuk menanyakan jumlah token yang diotorisasi ke alamat lain. Ia dapat menanyakan jumlah token yang telah diberikan alamat tertentu kepada alamat lain (biasanya alamat kontrak) untuk ditransfer dari akunnya sendiri.
untukUniswap V3Untuk kontrak perutean, jika Anda telah melaksanakanapproveFungsi ini diotorisasi ke alamat kontrak router, maka Anda dapat menggunakanERC20TokenallowanceBerfungsi untuk menanyakan jumlah yang diotorisasi.

Ingat pada tutorial sebelumnya kami menunjukkanERC20Pemanggilan metode kontrak?allowanceapproveKeduanyaERC20Metode kontraknya sama dengan yang telah kami jelaskan sebelumnya.balanceOftransferSemua metode memiliki status yang sama.

Sebelum melakukan penebusan, kita perlu memeriksa terlebih dahulu apakah otorisasi diberikan kepadaUniswapKontrak router memiliki cukup token untuk melakukan pertukaran. Jika tindakan yang ingin kita tukarkan adalah:1INCH->ETH, tarifnya ditetapkan sebesar 10000. Nilai ini ditetapkan sebesar 10000 yang berarti nilai tersebut adalah 1%.UniswapKolam pertukaran mungkin memiliki berbagai macam nilai tukar, umumnyaUniswapBeberapa pilihan disediakan. Misalnya, jika tarifnya ditetapkan sebesar 3000, berarti tarifnya adalah 0,3%. Anda dapat memeriksa spesifiknyaUniswapDokumen dan informasi terkait.

Perlu dicatat di sini bahwa kumpulan pertukaran sebenarnya adalah1INCH/WETH, ETH dan WETH adalah dua token berbeda di Ethereum.

  • ETH (Eter):
    ETH adalah mata uang kripto asli dari blockchain Ethereum dan aset utama serta unit komputasi jaringan Ethereum. ETH adalah token asli Ethereum, yang memiliki sirkulasi dan kegunaan universal. ETH dapat digunakan untuk membayar biaya transaksi, berpartisipasi dalam interaksi kontrak pintar, menyimpan nilai, dll.
  • WETH (Eter Terbungkus):
    WETH adalah bentuk ETH yang dienkapsulasi sebagai token standar ERC20. Ini adalah kontrak pintar pada Ethereum yang bertujuan untuk memungkinkan ETH berinteraksi secara lancar dengan token ERC20 dalam kontrak pintar. WETH dapat dibuat dan diperoleh dengan menyetorkan ETH ke alamat kontrak WETH, dan WETH dapat ditransfer kembali ke ETH kapan saja. Peran utama WETH dalam ekosistem Ethereum adalah menyediakan ETH dengan antarmuka standar dan kompatibilitas yang sama seperti token ERC20 lainnya, memungkinkan ETH untuk berpartisipasi dalam transaksi terdesentralisasi, kumpulan likuiditas, dan protokol DeFi lainnya.

Oleh karena itu, WETH adalah bentuk paket ETH yang memungkinkan ETH berinteraksi dalam bentuk token ERC20 dalam kontrak pintar Ethereum. Biasanya, ketika ETH perlu digunakan dalam kontrak pintar, ETH dapat dikonversi ke WETH, diperdagangkan atau dilibatkan dalam operasi DeFi, dan kemudian WETH dapat dikonversi kembali ke ETH sesuai kebutuhan.

menggunakanERC20dariallowanceMetode untuk mendapatkan jumlah yang diizinkan:

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

Untuk kodetoAmount()Kita harus terbiasa dengan fungsi. Kita telah menggunakan kode fungsi kustom ini berkali-kali pada bab-bab sebelumnya untuk memproses data menjadi nilai numerik yang mudah dibaca manusia.

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

Saat menjalankan kode, kami menemukan bahwa jumlah yang diotorisasi saat ini adalah 0. Oleh karena itu, untuk menebus, kami harus mengotorisasi jumlah yang cukup pada kontrak perutean.

img

OtorisasiUniswap V3Kontrak Perutean

Jika Anda menggunakanallowanceJika jumlah otorisasi tidak mencukupi setelah melakukan kueri, Anda perlu menggunakanapproveOtorisasiUniswap V3Kontrak perutean memungkinkan untuk mengoperasikan sejumlah tertentuERC20Token.

Atau1INCH -> ETHMisalnya, gunakanERC20dariapproveMetodeUniswapKontrak perutean mengizinkan pengoperasian dompet yang dikonfigurasi saat ini1INCHToken.

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

DitambahkantoInnerAmount()Implementasi fungsi kustom. Fungsi ini sudah sering digunakan dalam kursus kami sebelumnya, jadi saya tidak akan membahasnya secara rinci di sini.
Anda dapat melihat catatan otorisasi dan memanggil kode lagi untuk memeriksa status otorisasi:

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

img

Pertukaran token menggunakan Uniswap

Ketika ada cukup token di dompet untuk membayar (misalnya: tokenIn), dan otorisasiUniswapKontrak perutean memiliki operasi yang cukup, dan kemudian pertukaran dapat dieksekusi.
UniswapKontrak perutean memiliki beberapa metode penebusan, yang ditunjukkan di siniexactInputMetode, kumpulan pertukaran sebenarnya adalah1INCH/WETH, tebus dan gunakan lagiunwrapWETH9Metode untuk membongkar WETH menjadi ETH. Kami telah membahas konsep ini dalam bab ERC20 sebelumnya.withdrawDijelaskan dalam deskripsi.

Operasi pertukaran terutama menggunakan tiga metode:exactInputunwrapWETH9multicall, taruh pertamaUniswapKontrak PeruteanexactInputPanggilan metode,unwrapWETH9Kode panggilan metode kemudian digunakan oleh kontrak peruteanmulticallMetode eksekusi batch.

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)
  • menggunakanexchange.IO("encodePacked", ...)Fungsi ini mengodekan dan mengompresi parameter laju.
  • menurutexactInputPersyaratan parameter metode, parameter jalur konstruksipath
  • menggunakanexchange.IO("encode", ...)Pengkodean FungsiexactInputPemanggilan metode.
    Catatan: Jika pertukaran terakhir adalah ETH atau WETH, parameter penerima dari metode exactInput perlu ditentukan sebagai "0x0000000000000000000000000000000000000000000000000000002"
  • menggunakanexchange.IO("encode", ...)Pengkodean FungsiunwrapWETH9(uint256,address)Pemanggilan metode.
  • menggunakanmulticall(uint256,bytes[])metode mengeksekusi pemanggilan fungsi yang dikodekan di atas.

Tanyakan hasil pertukaran:

img

Kode lengkap:

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

Dapatkan harga pertukaran di kolam renang

Seperti yang sudah kami jelaskan sebelumnya, ketika kita menggunakan alamat token (ada dua, tokenIn dan tokenOut) dan pengaturan rate, kita bisaUniswapdariFactoryKontraktualgetPoolMetode untuk memperoleh alamat kumpulan pertukaran (kontrak pintar) dari kombinasi pertukaran ini.
Setelah memperoleh alamat kumpulan pertukaran, daftarkan ABI kontrak kumpulan tersebut. Kemudian Anda dapat memanggil kontrak kolam renangslot0Metode untuk memperoleh data terkait harga pertukaran saat ini dan menguraikan lebih lanjut harga pertukaran tersebut.

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

Dapatkan informasi harga kumpulan pertukaran dan cetak kodenyaslot0variabel:

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

Data informasi harga utama dicatat dalamsqrtPriceX96lapangan, harga terkini dari kumpulan bursa perlu dihitung berdasarkan data presisi token dari kombinasi bursa.UniswapSeperti yang dijelaskan dalam dokumen, kami mengimplementasikan fungsi untuk menghitung:

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

Gunakan fungsi ini untuk menghitung kombinasi token sebagai1INCH/WETH, harga kumpulan pertukaran saat ini dengan biaya 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) }

Mencetak variabelpricemenunjukkan:price: 0.000203(1 1INCH ditukar dengan 0,000203 WETH).

Perpustakaan Perdagangan Uniswap V3

Penemu platform perdagangan kuantitatif telah merilis paketUniswaptemplat, yang telah merealisasikan fungsi seperti pertukaran, akuisisi harga, dan permintaan saldo dompet. Anda tidak perlu menulis ulang kode sesuai dengan penjelasan di atas. Anda dapat membaca kode sumber templat ini untuk mempelajari lebih dalam dan mengembangkan aplikasi Web3.
Ada banyak detail yang layak dipelajari dalam pustaka templat ini:

  • Dapatkan informasi token secara otomatis
    Ambil bagian kode untuk menjelaskan, ketika parameter templateAutoFetchTokensBila diatur ke benar, program templat akan secara otomatis mengakseshttps://tokens.coingecko.com/uniswap/all.jsonMenghubungkan, memperoleh, dan memproses semua informasi token secara otomatis. Dengan cara ini Anda tidak perlu menambahkan token secara manual ke kode strategi (jika tidak, Anda perlu menggunakanaddToken(name, address)Tambahkan token).

    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 } } }) }
  • Sesuaikan alamat kontrak yang berbeda sesuai dengan pengaturan rantai
    Template ini mengaturChainTypeParameter, mendukung peralihan beberapa rantai:

    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',

    Kode kutipan:

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

    Memanggil metode RPC Ethereumeth_chainIdKueri saat inichainId, dan kemudian menurutchainIdUntuk mengadaptasi alamat WETH,UniswapSerangkaian alamat kontrak,USDTAlamat kontrak dari kontrak pintar mungkin berbeda pada rantai yang berbeda.

    Kode kutipan:

    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") }
  • Menggunakan "Perpustakaan Perdagangan Uniswap V3"

    Dalam template ini$.testUniswap()Fungsi ini adalah fungsi yang menguji fungsionalitas templat. Kodenya memberikan contoh cara menggunakan panggilan templat:

    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)) // ... }

    Ketika suatu strategi merujuk pada "Uniswap V3 Trading Library" (untuk informasi tentang cara merujuk pada pustaka templat, silakan lihat dokumentasi platform FMZ), Anda dapat memanggil fungsi yang dienkapsulasi dalam pustaka templat ini.

    Buat file bernamaexVariabel, panggil fungsi antarmuka yang dienkapsulasi oleh templat "Perpustakaan Perdagangan Uniswap V3"$.NewUniswapV3()Buat objek dan tetapkan keex

    javascript
    let ex = $.NewUniswapV3()

    menggunakanexFungsi anggota suatu objekaddToken()Tambahkan (daftarkan) informasi token.

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

    Jika Anda ingin mendapatkan dan mencetak harga kumpulan pertukaran pasangan perdagangan tertentu, Anda dapat menggunakanexFungsi anggota suatu objekgetPrice(), Anda dapat menulis:

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

    Jika Anda ingin melakukan operasi penebusan, Anda dapat menggunakanexFungsi anggota suatu objekswapToken(), jalankan pertukaran:

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

Ambil kembali acara

Dalam bab ini, kita akan mempelajari cara menggunakan Inventor Quantitative Trading Platform untuk membaca peristiwa yang dirilis oleh kontrak pintar. Peristiwa yang dirilis oleh kontrak pintar disimpan dalam log mesin virtual Ethereum.

eth_getLogs

Untuk menanyakan peristiwa yang dirilis oleh kontrak pintar, Anda perlu menggunakan metode RPC Ethereumeth_getLogs, dapatkan data log on-chain. Kami telah menjelaskan cara memanggil node Ethereum RPC di kursus kami sebelumnya.
Misalnya saja kita memperolehWETHPeristiwa kontrak dapat dikodekan menggunakan FMZAlat DebuggingUji, node RPC yang dikonfigurasi oleh objek pertukaran adalah node jaringan utama Ethereum, saat memanggileth_getLogsKami menentukan tiga parameter saat menggunakan metode inifromBlocktoBlockaddress, kami menggunakan parameter fromBlock dan toBlock untuk membatasi kueri ke data dalam satu blok:

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 }

Kami mendapatkan data log. Karena datanya besar, kami menghilangkan beberapa konten:

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" }]

Anda dapat melihat bahwa ada berbagai peristiwa dalam data log. Jika kita hanya peduli tentangTransferPeristiwa ini perlu mengubah data ini menjadiTransferPeristiwa disaring.

Ambil log

Log Ethereum dibagi menjadi dua bagian: 1. Topiktopics2. Datadata

  • tematopics
    oleheth_getLogsAmbil kode yang menjalankan hasil pengujian bab sebagai contoh.topicsData lapangannya adalah:

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

    initopicsNilai bidang (topik) adalah struktur array yang menggambarkan peristiwa. Ditetapkan bahwa panjangnya (array) tidak boleh melebihi 4, dan elemen pertama adalah nilai hash tanda tangan dari peristiwa tersebut.
    Dalam Platform Perdagangan Kuantitatif Inventor, kami menggunakanEncodeFungsi ini dapat menghitung nilai hash tanda tangan menggunakan kode berikut:

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

    DihitungTransfer(address,address,uint256)darikeccak256Nilai hash (pengkodean hex) adalah0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef

    topicsNilai bidang adalah struktur array, elemen kedua dan elemen ketiga adalah:

    • Alamat pengirimanfrom
    • Alamat Penerimato
  • datadata

    dataData lapangannya adalah:

    desc
    "data": "0x0000000000000000000000000000000000000000000000000164f2434262e1cc",

    Beberapa parameter dalam acara (parameter tanpa deklarasi terindeks dalam kode Solidity dari kontrak pintar) akan disimpan didatabagian.

    Mengurai data ini0x0000000000000000000000000000000000000000000000000164f2434262e1cc

    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 }

    Datanya adalah: 0.10047146239950075,dataData sesuai dengan jumlah transfer.


Setelah menjelaskan dan mempraktikkan konten di atas, Anda siap. Kita dapat mulai mengambil log:

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++ } } }

adahttps://etherscan.io/Pada pertanyaan:

img

Hasil menjalankan kode pengujian di alat debugging FMZ:

img

Sesuai dengan kebutuhan pengambilan, dapat juga diuraifromtoData lapangan, misalnya:

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

Hasil operasi:

address: 0x12b791bb27b3a4ee958b5a435fea7d49ec076e9c

Memantau peristiwa kontrak

KarenaAlat DebuggingKode hanya dapat diuji dalam waktu singkat, dan konten hanya dikeluarkan setelah kode dijalankan. Tidak mungkin untuk menampilkan dan mengeluarkan log secara real time. Di bagian ini, kami menggunakan Platform Perdagangan Kuantitatif Inventor untuk membuat akun nyata untuk pengujian.

Di sini kami menggunakan mainnet Ethereum, mari kita pantauUSDTKontrak mata uang iniTransfer(address,address,uint256)Peristiwa, berdasarkan apa yang kita pelajari di kelas terakhir, kami merancang dan menulis contoh pemantauan berkelanjutan terhadap peristiwa kontrak pintar:

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]) } } */

Operasi disk nyata:

img

Untuk hasil eksekusi, bagian verifikasi (TODO: test) juga ditulis dalam kode. Setelah verifikasi sederhana, kita dapat melihat bahwa kontrak USDT terus dipantau.TransferPeristiwa dicatat dan data dicatat. Dengan membandingkan data ini dengan data peristiwa yang diperoleh sekali, dapat diamati bahwa data tersebut konsisten:

img

Penyaringan Peristiwa

Berdasarkan pelajaran sebelumnya "Memantau Peristiwa Kontrak", kami akan memperluasnya dengan menambahkan filter ke proses pemantauan untuk memantau transfer masuk dan keluar dari alamat yang ditentukan. Ketika kontrak pintar membuat log (misalnya merilis suatu peristiwa), data logtopicsBerisi hingga 4 pesan. Jadi kami merancang aturan penyaringan untuk[[A1, A2, ...An], null, [C1], D]Misalnya.

1、[A1, A2, ...An]sesuaitopics[0]Data lokasi.
2、nullsesuaitopics[1]Data lokasi.
3、[C1]sesuaitopics[2]Data lokasi.
4、Dsesuaitopics[3]Data lokasi.

  • Jika elemen dalam struktur Kasus diaturnullMenunjukkan bahwa itu tidak difilter, misalnyanullsesuaitopics[1], nilai apa pun cocok.
  • Jika suatu elemen dalam struktur kasus menetapkan satu nilai, ini menunjukkan bahwa posisi harus cocok, misalnya[C1]sesuaitopics[2]atauDsesuaitopics[3], log yang tidak cocok disaring.
  • Jika elemen dalam struktur kondisional adalah array, berarti setidaknya satu elemen dalam array harus cocok, misalnya[A1, A2, ...An]sesuaitopics[0][A1, A2, ...An]Siapa pun dantopics[0]Jika kecocokan ditemukan, log tidak akan disaring.

Pantau transfer USDT di bursa

Pantau transfer dari dan ke BinanceUSDTTransaksi:

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

Kode di atas dijalankan pada disk nyata:

img

img

Dalam pelajaran ini, kami memperkenalkan cara merancang filter peristiwa. Dan menggunakannya untuk memantau dompet panas Binance ExchangeUSDTberdagang. Anda dapat memodifikasi dan memperluas contoh program ini untuk mendengarkan kejadian apa pun yang Anda minati.smart moneyTransaksi baru apa yang dilakukan?NFTProyek baru apa yang sedang dikerjakan oleh orang-orang besar, dll.

Konversi satuan

Dalam banyak perhitungan terkait Ethereum, nilainya melebihiJavaScriptBilangan bulat maksimum yang aman untuk bahasa tersebut. Oleh karena itu, diperlukan beberapa metode untuk memproses angka besar pada Inventor Quantitative Trading Platform. Kami telah menggunakan metode ini dalam kursus sebelumnya tetapi belum menjelaskannya secara rinci. Bab ini akan membahas aspek ini secara rinci.

MencetakJavaScriptBilangan bulat aman terbesar yang didefinisikan dalam bahasa:

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

Hasil operasi:

Number.MAX_SAFE_INTEGER: 9007199254740991

BigInt

Unit terkecil yang didefinisikan dalam Ethereum adalah1wei,definisi1Gweisetara1000000000 wei1GweiFaktanya, angka tersebut bukanlah angka yang sangat besar dalam kalkulasi terkait Ethereum. Beberapa data jauh lebih besar dari itu. Maka data dengan nilai yang sangat besar tersebut dapat dengan mudah melampauiNumber.MAX_SAFE_INTEGER: 9007199254740991

Dalam Platform Perdagangan Kuantitatif Inventor, kami menggunakan platformBigIntObjek digunakan untuk merepresentasikan data integer yang sangat besar ini. Menggunakan KonstruktorBigInt()Untuk membangunBigIntobyek. Dapat dibangun menggunakan nilai numerik atau string numerik heksadesimal sebagai parameterBigIntobyek. menggunakanBigIntObyektoString()Metode ini mengeluarkan data yang direpresentasikan oleh objek sebagai sebuah string.

BigIntOperasi yang didukung oleh objek:

  • Operasi penambahan:+
  • Pengurangan:-
  • Perkalian:*
  • Operasi pembagian:/
  • Operasi modulo:%
  • Operasi daya:**

Lihat contoh kode berikut:

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

Uji alat debug:

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

BigFloatObjek danBigIntObjek tersebut digunakan dengan cara yang sama, dan digunakan untuk merepresentasikan angka floating-point dengan nilai yang lebih besar. Objek tersebut juga mendukung operasi penjumlahan, pengurangan, perkalian, dan pembagian.
BigFloatDukungan objektoFixed()metode.

Lihat contoh kode berikut:

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

Uji alat debug:

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

BigDecimalObjek ini kompatibel dengan nilai integer dan floating-point dan mendukung penggunaanBigIntObjek,BigFloatInisialisasi objek juga mendukung operasi penjumlahan, pengurangan, perkalian dan pembagian.

Lihat contoh kode berikut:

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

Jalankan dalam debugger:

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

Konversi satuan

Dua fungsi berikut:toAmount()toInnerAmount()Kita telah menggunakan kedua fungsi ini berkali-kali dalam kursus sebelumnya. Fungsi-fungsi ini terutama digunakan untuk konversi presisi 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) }

toAmount()Fungsi ini mengonversi variabels, sesuai dengan parameter akurasidecimalsLakukan konversi (pengurangan). Dalam pengembangan web3 aktual, sering kali diperlukan pemrosesan beberapa data heksadesimal pada rantai.
Kita sering menjumpai hal ini di kursus kita sebelumnya, seperti kontrak pintar.Transfer(address,address,uint256)Dalam acara tersebutdataData lapangan:

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

Mengolah data"data": "0x00000000000000000000000000000000000000000000000001c1a55000000000", kali ini gunakantoAmount()fungsi. Desain pemrosesan ini dapat dengan baikdataMengubah data lapangan menjadi nilai numerik yang dapat dibaca.

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 }

1 token ETH yang kami tahu adalah1e18 weiJika kita mendapatkanweiData dalam satuan126564027559051260Bagaimana cara mengubahnya menjadi jumlah token ETH?
menggunakantoAmount(, 18)Fungsi dapat dikonversi dengan mudah.toInnerAmount()Fungsinya adalahtoAmount()Operasi kebalikan dari fungsi (menurut presisi, amplifikasi), menggunakan kedua fungsi ini, sangat mudah untuk mengkonversi data.

Perlu diketahui bahwa rentang aman nilai integer dalam bahasa JavaScript adalahNumber.MAX_SAFE_INTEGER, contoh berikut menggambarkan masalah yang lebih tersembunyi dalam konversi 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() { 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)) }

Anda dapat menjalankannya di debugger:

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

Melalui pengamatan kami menemukan bahwa:

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

Keluaran log yang sesuai dengan baris kode ini adalah:转换 10000000000000000 为十六进制: 10000000000000000, tetapi tidak dikonversi dengan benar. Alasannya tentu saja karena 1000000000000000000 melebihiNumber.MAX_SAFE_INTEGER

Namun, ketika nilai desimal berada dalam kisaran aman, yaitu kurang dariNumber.MAX_SAFE_INTEGERjam,toString(16)Konversi fungsi normal lagi, misalnya:

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

Di bidang blockchain, bahkan0.01ETH dikonversi keweiNilai unit10000000000000000Ini juga akan melampauiNumber.MAX_SAFE_INTEGER, jadi konversi yang lebih aman untuk situasi ini adalah:BigInt(10000000000000000).toString(16)

Simulasikan panggilan

Menjalankan transaksi dan memanggil kontrak pintar di EthereumWriteMetode ini menghabiskan sejumlah gas dan kadang-kadang berisiko gagal. Penting untuk mengetahui transaksi mana yang mungkin gagal sebelum mengirimnya atau memanggilnya. Ada metode panggilan simulasi pada Ethereum untuk pengujian.

eth_call

Metode RPC Ethereumeth_call:Dapat mensimulasikan transaksi dan mengembalikan kemungkinan hasil transaksi, tetapi tidak akan benar-benar mengeksekusi transaksi pada blockchain.

eth_callMetode ini memiliki dua parameter, parameter pertama adalah struktur kamus,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 }

Parameter kedua adalahblockNumber: Anda dapat melewati taglatest/pending/earliestTunggu:

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 */

Selanjutnya, kita menggunakan tokenDAIMetode Kontrak CerdasapprovetransferPanggilan tersebut merupakan panggilan simulasi, misalnya. Lingkungan pengujian berikut adalah jaringan utama Ethereum.

Simulasikan panggilan persetujuan

Untuk kontrak ERC20approveKita sudah familier dengan metode ini dan sudah mempraktikkannya pada kursus sebelumnya. Karena kontrak ERC20 sudah dibangun dalam ABI platform FMZ, tidak perlu lagi mendaftarkan ABI kontrak pintar yang akan disimulasikan.

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

Kode dalam contoh pertama-tama mengonversiapprove(address,uint256)Metode dan parameter dikodekan.approveNilai parameter metode0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffMenunjukkan jumlah maksimum otorisasi. Otorisasi kontrak pintar, alamat0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45SekarangUniswap V3Kontrak perutean. Akhirnya memanggil metode Ethereum RPCeth_callLakukan simulasi. Kamu bisa melihattransactionObjectParametergasPricegasKolom dapat dihilangkan.

Alat debugging berjalan dan mensimulasikan otorisasi yang berhasil dalam memanggil metode approve (namun sebenarnya tidak mengotorisasi):

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

Kita juga dapat mensimulasikan beberapa skenario kegagalan. Saat kita menyesuaikangasPriceDangasSaat mengatur parameter, jika ETH di dompet tidak cukup untuk membayar biaya gas, kesalahan akan dilaporkan:

insufficient funds

Jika biaya gas ditetapkan terlalu rendah, kesalahan akan dilaporkan:

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

Simulasikan transfer panggilan

Untuk ERC20transferKami juga familier dengan metode ini. Metode ini dapat mentransfer token ERC20 ke alamat dompet tertentu. Kami akan mencoba simulasi transfer 1.000 DAI ke 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 }

Karena dompet pengujian saya tidak memiliki token DAI, hasil menjalankannya di alat debugging sesuai dengan yang diharapkan, kesalahan dilaporkan:

execution reverted: Dai/insufficient-balance

Lihat alamat dompet Vitalik:0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045Dapat dilihat bahwa dompet ini memiliki token DAI. Lalu mari kita tukar arah transfer panggilan simulasi dan simulasikan Vitalik mentransfer 1.000 DAI kepada kita.

Ubah kode dan berikan komentar di bagian yang dimodifikasi:

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

Uji alat debug:

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

Dengan menggunakan Platform Perdagangan Kuantitatif Inventor, Anda dapat dengan mudah mensimulasikan hasil transaksi dan menghindari kerugian biaya gas yang tidak perlu yang disebabkan oleh pengiriman transaksi yang mungkin gagal. Kami menggunakan kode contoh dalam bab ini untuk mensimulasikan panggilan transfer uang ke dompet Vitalik dan dompet Vitalik mentransfer uang kepada kami. Tentu saja inieth_callMetode memiliki lebih banyak kegunaan. Gunakan imajinasi Anda dan Anda akaneth_callDi mana metode ini digunakan?

Identifikasi kontrak ERC721

Kita tahu bahwa token seperti ETH dan BTC semuanya adalah token yang homogen. Token di tangan Anda tidak berbeda dengan token di tangan saya. Namun, ada banyak hal di dunia yang sifatnya berbeda-beda, seperti real estat, barang antik, karya seni virtual, dll., yang tidak dapat direpresentasikan secara abstrak oleh token homogen. Oleh karena itu, standar ERC721 diciptakan untuk mengabstraksi objek yang tidak homogen, dan NFT serta konsep terkait pun muncul.
Jadi di antara banyak kontrak pintar yang digunakan di Ethereum, bagaimana kita mengidentifikasi kontrak pintar mana yang merupakan kontrak pintar berstandar ERC721?

Untuk mengidentifikasi ERC721, Anda harus terlebih dahulu memahami standar ERC165.

ERC165

Melalui standar ERC165, kontrak pintar dapat mendeklarasikan antarmuka yang didukungnya untuk diperiksa oleh kontrak lain. Kontrak antarmuka ERC165 hanya memiliki satu fungsi:supportsInterface(bytes4 interfaceId),parameterinterfaceIdID antarmuka yang akan ditanyakan. Jika kontrak mengimplementasikan Id antarmuka, maka ia akan mengembalikan nilai Boolean true, jika tidak maka ia akan mengembalikan nilai false.

Selanjutnya kita akan membicarakan hal iniinterfaceIdCara menghitung dan mengkodekannya secara spesifik.

Standar ERC165Contohnya diberikan:

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; } }

Lakukan operasi XOR pada tanda tangan fungsi antarmuka (yang terdiri dari nama fungsi dan daftar tipe parameter). Untuk kontrak antarmuka ERC165 dengan hanya satu fungsi:

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.

Hitung langsung tanda tangan fungsi dan ambil 4 byte pertama untuk mendapatkannyainterfaceId

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

Anda dapat menjalankan pengujian di debugger:

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

Anda dapat melihat hasil perhitungan danStandar ERC165Deskripsi dalam dokumen tersebut konsisten.

ERC721

Selanjutnya, mari kita lihat definisi antarmuka standar kontrak 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); }

Jika kita ingin menentukan apakah kontrak pintar adalah kontrak ERC721, pertama-tama kita harus mengetahui kontrak ERC721 tersebut.interfaceId, sebelum Anda dapat mencoba menggunakannyasupportsInterface(bytes4 interfaceId)Penilaian metode. Pada kursus sebelumnya, kita telah mengenal beberapa konsep dan perhitungan standar ERC165.interfaceIdKita dapat langsung menulis kode untuk menghitung algoritmanya:

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

Kode tersebut menggunakanEncode()Fungsi ini melakukan perhitungan tanda tangan fungsi (keccak256Algoritma), untuk perhitungan pada contoh kode di atas, tentukanEncode()Parameter keluaran fungsi tersebut adalah"raw", fungsi mengembalikanJavaScriptBahasa LinguistikArrayBufferjenis.
Jika Anda ingin duaArrayBufferObyek^Operasi (XOR), berdasarkanArrayBufferPembuatan objekTypedArrayTampilan tersebut kemudian diulangi atas data, melakukan operasi XOR pada setiap data.

Jalankan dalam debugger:

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

Anda dapat melihat hasil perhitungan daneip-721Sama seperti yang dijelaskan dalam .

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); ...

Dengan ID antarmuka ERC721, kita dapat menentukan apakah suatu kontrak merupakan kontrak standar ERC721. Kami menggunakanBAYCUntuk melakukan pengujian, ini adalah kontrak yang mematuhi ERC721. Pertama, kita perlu mendaftarkan ABI. Karena kita hanya memanggil tiga metode berikut, kita hanya dapat mendaftarkan ketiga metode ini:

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

Kode spesifiknya adalah sebagai berikut:

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

Anda dapat menjalankan pengujian di debugger:

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

Tentukan alamatnya0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13dKontraknya berstandar ERC721.

Dalam kuliah ini, kami memperkenalkan cara mengidentifikasi kontrak ERC721. Untuk kontrak ERC20 yang tidak mendukung standar ERC165, metode lain harus digunakan untuk mengidentifikasinya. Tahukah Anda cara memeriksa apakah suatu kontrak berstandar ERC20?

Pengkodean panggilan data

Apacalldata.... Menurut pemahaman penulis, uraian sederhana dan populer di sini adalah:

"Calldata" adalah penyandian panggilan fungsi dan parameter di Ethereum. "Calldata" disandikan menurut spesifikasi ABI (Application Binary Interface) kontrak.

Misalnya, kita dapat menggunakan kontrak ERC20 yang kita pelajari di kursus sebelumnyabalanceOftransferPemanggilan metode, bersama dengan parameter yang digunakan dalam pemanggilan, dikodekan sebagaicalldata. Dalam beberapa skenario aplikasi, misalnya:Interaksi antar kontrak, yang akan digunakan dalam skenario inicalldataTentu saja, masih banyak skenario aplikasi lainnya yang tidak tercantum di sini satu per satu.

Cara membuat kode panggilan fungsi kontrak pintar untuk mendapatkancalldata

Anda dapat menggunakannya di Platform Perdagangan Kuantitatif Inventorexchange.IO("encode", ...)Pengkodean panggilan fungsi kontrak pintar juga sangat mudah digunakan.exchange.IO("encode", ...)Parameter pertama dari fungsi ini adalah string tetap"encode"; Parameter kedua adalah alamat kontrak pintar; parameter ketiga adalah nama metode kontrak pintar yang akan dikodekan; parameter yang tersisa meneruskan nilai parameter spesifik dari metode kontrak pintar yang akan dikodekan.

eth_sendRawTransaction

Ketika kita mengkodekan panggilan metode kontrak pintar dan menghasilkan yang sesuaicalldataSaat menghasilkan data, jika metode kontrak pintar adalah metode Tulis (yaitu, operasi tulis), kita perlu menghasilkancalldataData tersebut digunakan sebagai bidang data transaksi, kemudian digunakan metode RPC Ethereumeth_sendRawTransactionKirim permintaan ke jaringan Ethereum yang berisi data mentah transaksi.

eth_sendRawTransactionMetode ini hanya memiliki satu parameterdata

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

inidataParameter adalah data setelah kalkulasi tanda tangan dari data transaksi. Struktur data transaksi Ethereum terutama memiliki bidang-bidang berikut:

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

Bagaimana cara menandatangani transaksi Ethereum?

Dalam Platform Perdagangan Kuantitatif Inventor kami menggunakanEncode()Fungsi untuk melakukan kalkulasi tanda tangan. Kami akan menulis contoh spesifik dalam kursus berikutnya "Menjalankan pemanggilan metode Write".

Jalankan panggilan metode Baca data

Untuk metode BacacalldataUntuk mengeksekusinya, kami menggunakan metode RPC yang telah kami pelajari sebelumnya:eth_callUntuk mengeksekusinya, kami sudah menjelaskan sebelumnyaeth_callMetode RPC Ethereum ini hanya melakukan kontrak pintarWriteDemonstrasi metode, menggunakan bab inicalldataContoh berikut memperagakan cara memanggil metode Read pada kontrak pintar. Mari kita gunakan kontrak WETHbalanceOfMetode untuk membaca saldo token WETH pada dompet saat ini.

Kami menggunakan alat debugging untuk menguji pada mainnet 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个数为单位 }

Jalankan dalam debugger:

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

Jika metode kontrak pintar memiliki nilai pengembalian, Anda dapat menggunakanexchange.IO("decode", ...)Fungsi decoding. Dapat dilihat bahwa dengan melewaticalldataMetode dan panggilan langsung ke kontrak pintarbalanceOfMetodenya sama, dan saldo WETH dompet pengujian saya adalah 0,015 WETH.

Jalankan panggilan metode Write

Untuk eksekusi calldata metode Write, Anda perlu menggunakan metode RPC:eth_sendRawTransaction.

Kami menggunakan alat debugging untuk menguji pada mainnet 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 }

Jalankan dalam debugger:

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

melaksanakanvar ret = exchange.IO("api", "eth", "eth_sendRawTransaction", "0x" + signedTx)Fungsi, Hash Transaksi yang dikembalikan adalah:0x2ff585504b0fe59b0122f696e8808abfe2f3ce263448066533f3bb8a4f55e8e6. inieth_sendRawTransactionCalldata dipanggil untuk mengeksekusi kontrak WETH.depositMetode ini menukar 0,005 ETH yang dikirim dengan WETH.

Mempool pemantauan

Sebelum transaksi pengguna di Ethereum dikemas ke dalam blockchain Ethereum oleh penambang, semua transaksi dikumpulkan dalamMempoolDi kumpulan memori transaksi, “penambang” juga mencari transaksi dengan biaya tinggi dan mengemasnya terlebih dahulu untuk memaksimalkan manfaat penambangan. Oleh karena itu, secara umum, semakin tinggi harga gas suatu transaksi ditetapkan, semakin mudah transaksi tersebut dikemas.

Beberapa skrip transaksi juga akanMempoolMengendus-endus dengan harapan menemukan beberapa transaksi yang menguntungkan. Misalnya, jika suatu transaksi menetapkan selisih kurs yang terlalu tinggi, transaksi tersebut dapat menjadi sasaran "serangan sandwich" oleh skrip transaksi ini. Jadi bagaimana skrip ini memonitorMempoolDi dalampending(tertunda, akan dikemas) Bagaimana dengan kesepakatannya?

Dengarkan menggunakan protokol REST

Menggunakan metode RPC yang kita pelajari sebelumnya:eth_getBlockByNumber, tetapi kami tidak akan memposting secara spesifik kali ini.blockNumber, kami menggunakan"pending"Label.

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

Jalankan dalam debugger:

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"} ...

Ekstrak salah satu data:

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" }

Mendengarkan menggunakan protokol WebSocket

Dalam Platform Perdagangan Kuantitatif Inventor, kami menggunakanDialFungsi untuk membuatWebSocketHubungkan untuk melihatFMZ APIDokumentasiDialfungsi.

Kode pengujian dalam bab ini berjalan di lingkungan mainnet Ethereum. Karena menggunakan protokol WebSocket untuk komunikasi, akan lebih mudah untuk menggunakan pengujian real-time Inventor Quantitative. Pesan langganan protokol Websocket adalah:

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

Selain darinewPendingTransactionsAnda juga dapat berlangganannewHeadslogs

menerimaWebSocketHubungkan ke data push:

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

Kemudian menurut:"result": "0x69c4251cecb814e17cfe7a5ee41742a616f9a4d1bbf245c49b186b1006fd14d3", penyelidikan lebih lanjuttransaction. Untuk hal tertentutransactionKami menggunakan metode Ethereum RPCeth_getTransactionByHashUntuk menanyakan.

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

Buat disk sungguhan dan jalankan kode di atas. Anda dapat menerima data yang dikirim melalui koneksi WebSocket. Data dikirim secara terus-menerus. Mari kita ekstrak salah satunya.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" }

Kutipan (sebagian dihilangkan) data log:

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"} ...

Menguraikan rincian transaksi

Pada kursus terakhir, kita menulis program pemantauan untuk memantau transaksi yang tertunda di Ethereum, memperoleh hash transaksi yang dikirim melalui protokol WebSocket, lalu menanyakan detail transaksi spesifik berdasarkan hash transaksi.

Selanjutnya, kita perluinputData lapangan diurai lebih lanjut.inputData lapangan tampak seperti data heksadesimal acak, tetapi sebenarnya mengkodekan konten transaksi: termasuk fungsi yang dipanggil dan parameter input, dll.

Setelah pengujian berulang dan ekstensif, ditemukan bahwa ketepatan waktu dan kuantitas data yang didorong melalui koneksi WebSocket terkait erat dengan node RPC yang saat ini digunakan. Ketika dua layanan node RPC yang berbeda (seperti infura dan ALCHEMY) membuat koneksi WebSocket di Pada saat yang sama, data push yang diterima tidak sama persis. Karena skenario saat ini akan menghasilkan sejumlah besar permintaan, masih perlu menggunakan layanan RPC yang lebih stabil dan cepat. Koneksi WebSocket juga akan mendorong banyak hash transaksi yang telah tertunda lama.eth_getTransactionByHashSaat membuat kueri, Anda sering mendapatkan nilai null (diuji pada FMZ dan node.js).

Kami menggunakan waktu inialchemysimpul RPC:wss://eth-mainnet.g.alchemy.com/v2/oKmOQKbneVkxgHZfibs-iFhIlIAl6HDN. Node ini mendukung protokol WebSocket dan protokol REST.

Kami memantau kontrak pintar perutean pertukaran terdesentralisasi Uniswapmulticall(uint256,bytes[])metode, jadi pertama-tama kita perlu menghitung hash tanda tangan fungsi dari metode ini.

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

Berdasarkan contoh di pelajaran sebelumnya, kami membuat beberapa modifikasi. Saat menerima pesan yang dikirim melalui koneksi WebSocket, gunakanvar data = ws.read(-2)Terima data terbaru.read()Menetapkan parameter fungsi ke -2 berarti segera mengembalikan data terkini. Kami hanya peduli tentang penyertaanmulticallDiteleponTransaction ,menggunakanif (tx && tx.input.indexOf(sigHash) !== -1)Penyaringan penilaian.

Perlu mendesain 2 fungsi khusus:

  • calcAllFuncSigHash(): Menghitung hash tanda tangan untuk semua metode berdasarkan ABI.
  • decodeCall(): Fungsi dekode.

Selanjutnya dideteksimulticallKetika dipanggil, operasi decoding dapat dimulai. Decoding pertamamulticallParameter metode:deadlineDandatadeadlineLebih mudah untuk memahami cap waktu.dataIni adalah panggilan data terkode lainnya, jadi kita perlu terus menggunakannya.decodeCall()Fungsi decoding.

Contoh implementasi lengkap:

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

Buat disk nyata untuk menjalankan pengujian:

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

tangkapan layar:

img

Anda dapat melihat bahwa Hash Transaksi adalah0x5288a7bd6e0f57162ca763df722de73793e542734d7d2b7af5755664e2e67910Untuk transaksi ini, data input berisi panggilanmulticallPemanggilan metode. Arah transaksi adalah: 0x851b594033d57c98af753bcb3a7d0237a615de32 -> 0x68b3465833fb72a70ecdf485e0e4c7bd8665fc45.0x68b3465833fb72a70ecdf485e0e4c7bd8665fc45Yaitu, alamat kontrak perutean Uniswap.

img

DianalisismulticallPaket memanggil kontrakexactInputSingleDanunwrapWETH9metode, dan parameter spesifik dari metode tersebut.

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

Siswa yang tertarik dapat memodifikasi dan memperluas contoh ini untuk memantau lebih banyak transaksi dan menganalisis operasi on-chain ini.

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