Type/to search
8
Follow
1364
Followers
Utilisez FMZ pour démarrer facilement avec le développement Web3 basé sur Ethereum
Original
Created 2023-03-28 13:32:48  Updated 2024-11-11 22:28:24
 0
 4375

img

Tutoriel EtherEaseWithFMZ

Utilisez FMZ pour démarrer facilement avec le développement Web3 basé sur Ethereum

Ethereum est une plateforme de contrats intelligents basée sur la technologie blockchain, qui fournit un moyen décentralisé d'écrire et de déployer des contrats intelligents. Un contrat intelligent est un programme informatique spécial qui peut être exécuté automatiquement sur la blockchain et peut mettre en œuvre diverses logiques commerciales sans avoir besoin de faire confiance à un tiers.

La plateforme de trading quantitative Inventor (FMZ.COM) fournit une API facile à utiliser qui permet aux développeurs d'interagir plus facilement avec la blockchain Ethereum et son écosystème. Réalisez des fonctions telles que l'accès aux échanges décentralisés (DEX), l'obtention de données en chaîne et l'envoi de transactions.

Les exemples de ce tutoriel utilisentJavaScriptRédaction de langage, utilisation d'environnement de testRéseau principal EthereumRéseau de test Goerli. Vous pouvez également consulter les interfaces API utilisées dans le didacticiel ainsi que les descriptions et exemples de code associés dans la documentation API de la plateforme FMZ.


Premiers pas avec FMZ

Avant d'apprendre à utiliser la plateforme de trading quantitative FMZ, nous devons nous familiariser avec plusieurs concepts de base :

1. Architecture de la plateforme de trading quantitative FMZ

Après vous être inscrit et connecté au site officiel de la plateforme de trading quantitatif FMZ (https://www.fmz.com), vous pouvez utiliser les différentes fonctions de la plateforme. Le site Web FMZ est l'extrémité de gestion de l'ensemble du système, et les programmes écrits par les utilisateurs sont réellement exécutés sur l'hôte. L'hôte est un logiciel qui peut être déployé sur divers appareils, tels que des serveurs, des ordinateurs, etc. Lorsqu'un utilisateur écrit un programme et crée une instance en cours d'exécution sur le site Web FMZ, la plate-forme FMZ communique avec l'hôte et démarre une instance de programme sur l'hôte.

img

2. Hôte

Si vous souhaitez exécuter une instance de programme, vous devez déployer un hôte. Le déploiement de l'hôte est également très simple et il existe un didacticiel de déploiement sur la plateforme. Vous pouvez également utiliser « l'hôte de déploiement en un clic » fourni sur FMZ pour déployer automatiquement à l'aide du serveur loué par FMZ.

  • Déployer un hôte sur un appareil personnel

    Le programme de garde peut être déployé et exécuté sur des serveurs, des ordinateurs personnels et d'autres appareils, à condition que le réseau soit normal (la cible correspondante doit être accessible, comme une interface d'échange, une adresse de nœud, etc.). Les principales étapes du déploiement sont :

    1. Connectez-vous ou ouvrez l'appareil sur lequel vous souhaitez déployer le programme hôte, par exempleConnectez-vous au serveurouAllumez l'ordinateur et entrez dans le système d'exploitation
    2. Téléchargez la version correspondante du programme hôte (selon le système d'exploitation de l'appareil), page de téléchargement : https://www.fmz.com/m/add-node
      img
    3. Le fichier téléchargé est un package compressé, qui doit être décompressé.
    4. Exécutez le programme hôte. Le programme hôte est un programme appelérobotfichier exécutable. Configurez l'adresse de communication du dépositaire. Cette adresse de communication est unique pour chaque compte FMZ. Après vous être connecté à FMZ,https://www.fmz.com/m/add-nodeLa page peut afficher sa propre adresse (c'est-à-dire./robot -s node.fmz.com/xxxxxCette chaîne d'adresses, icixxxxxLe contenu de l'emplacement est affiché différemment pour chaque compte FMZ). Enfin, vous devez saisir le mot de passe du compte FMZ. Après avoir configuré ces derniers, exécutez le programme hôte.
  • Utilisez la fonction « déploiement des dépositaires en un clic » de la plateforme FMZ

    Ajoutez une page dépositaire sur la plateforme FMZ, adresse :https://www.fmz.com/m/add-node

    img

3. Outils de débogage

La plateforme de trading quantitative FMZ fournit un outil de débogage gratuit qui prend en chargeJavaScriptTypeScriptLa page est : https://www.fmz.com/m/debug, car la création d'une instance et son exécution sont facturées. Cet outil de débogage peut être utilisé pour tester et apprendre pendant la période d'apprentissage initiale. L'outil de débogage n'est pas différent de la création d'une instance, sauf que le temps d'exécution est limité à 3 minutes.

utiliserTypeScriptLorsque vous utilisez le langage, vous devez l'écrire dans la première ligne de code// @ts-checkPour passer àTypeScriptMode, s'il n'est pas commuté, la valeur par défaut estJavaScriptlangue.

4. Échanges

Sur FMZ, le terme « échange » est un concept général. Pour un échange CEX, il fait référence à une configuration de compte d'échange spécifique. Pour le Web3, cet échange fait référence à une information de configuration, notamment l'adresse du nœud et la configuration de la clé privée.

Une fois connecté à la plateforme FMZ,https://www.fmz.com/m/add-platformPage, vous pouvez configurer les informations d'échange, où l'échange est un concept général.

img

choisirWeb3, configurez l'adresse du nœud RPC et la clé privée. Vous pouvez cliquer sur « Les informations sensibles sont cryptées et enregistrées à l'aide d'une clé privée indépendante » dans le coin inférieur droit pour afficher le mécanisme de sécurité.

Les nœuds peuvent être auto-construits ou fournis par des fournisseurs de services de nœuds. Il existe de nombreux fournisseurs de services de nœuds, tels que :Infura. Après inscription, vous pouvez visualiser l'adresse du nœud de votre compte. Il existe à la fois un réseau principal et un réseau de test, ce qui est plus pratique. Configurez cette adresse de nœud dans la figure ci-dessus.Rpc Addressdans les commandes. Les balises peuvent être nommées par elles-mêmes pour distinguer les objets d'échange configurés.

img

Dans la figurehttps://mainnet.infura.io/v3/xxxxxxxxxxxxxIl s'agit de l'adresse du nœud RPC du réseau principal privé Infura ETH.


Utiliser FMZ pour interagir avec Ethereum

Après avoir déployé le programme de conservation et configuré l'objet d'échange, vous pouvez utiliser « l'outil de débogage » de FMZ.COM pour les tests. Appelez les méthodes RPC d'Ethereum pour interagir avec Ethereum. En plus des nombreuses méthodes RPC répertoriées dans ce chapitre, vous pouvez vous référer à la documentation d'autres méthodes RPC, telles quehttps://www.quicknode.com/docs

Prenons quelques exemples simples et commençons par les bases. Il existe des moyens d'accéder à Web3 pour différentes langues et outils, comme le montre la figure :

img

Les appels de méthode RPC sont également encapsulés sur FMZ. Ces fonctions sont encapsulées dans la fonction API FMZexchange.IOmilieu. La méthode d'appel estexchange.IO("api", "eth", ...). Le premier paramètre est fixe."api", le deuxième paramètre est fixe"eth", d'autres paramètres dépendent de la méthode RPC spécifique appelée.

Pour la sortie des informations, nous utilisons la plateforme FMZLogfonction,LogLa fonction peut transmettre plusieurs paramètres puis les afficher dans la zone de journal de la page « Debug Tool » ou « Real Trading » de la plateforme FMZ. La page « Debug Tool » sera l'outil principal pour nos tests.

eth_getBalance

Ethereumeth_getBalanceCette méthode permet d'interroger le solde ETH d'une adresse sur Ethereum. Cette méthode nécessite la transmission de deux paramètres.

  • L'adresse à interroger.
  • Balise, généralement « la plus récente ».

Vérifions le fondateur d’EthereumV神Adresse du portefeuille ETH, les adresses connues sont :0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045

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

Le dépositaire a été déployé (dans la figure : linux/amd64 ...) et l'objet d'échange a été configuré (dans la figure : test Web3). Testez le code dans l'outil de débogage :

img

Cliquez sur le bouton « Exécuter » pour exécuter ce code et afficher les résultats :

ethBalance: 0x117296558f185bbc4c6

LogLa fonction imprimeethBalanceLes valeurs des variables sont :0x117296558f185bbc4c6, qui est un type de chaîne. OuiSolde ETH en valeur hexadécimale,parweiEn tant qu'unité,1e18 weiest 1ETH. Il doit donc être converti en un solde ETH décimal lisible.

VolontéethBalanceConvertir en données lisibles :

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

En hauthttps://etherscan.io/Requête:

img

Cependant, ce traitement comportera des écarts dus à la précision de la langue elle-même, c'est pourquoi la plateforme FMZ dispose de deux fonctions intégrées pour le traitement des données :

  • BigInt : convertit une chaîne hexadécimale en objet BigInt.
  • BigDecimal : convertit un objet de type numérique en un objet BigDecimal sur lequel il est possible d'opérer.

Ajustez à nouveau le code :

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_chainIdetnet_versionLes usages sont similaires, nous les avons donc testés ensemble. Les deux fonctions renvoient l'ID de la blockchain à laquelle le nœud RPC actuel est connecté. La différence estnet_versionRenvoie l'ID décimal.eth_chainIdRenvoie l'ID hexadécimal.

Le nom du réseau correspondant à l'ID de la chaîne

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

Utiliser le réseau de test Ethereum configurégoerliTest de nœud :

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

Appeleth_gasPriceMéthode pour interroger la chaîne actuellegas 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)) }

Ici, nous écrivons une fonction pour convertir une chaîne hexadécimale en une valeur lisible :toAmount. Une autre chose à noter est que l'unité du prix du gaz estwei, donc le paramètredecimalsLe paramètre réel correspondant peut être transmis comme valeur 0.

eth_blockNumbe

eth_blockNumbeUtilisé pour interroger la hauteur du bloc.

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

Exécuter dans le débogueur :

img

https://etherscan.io/Sur demande :

img

eth_getBlockByNumber

Informations sur le bloc de requête.

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

Les informations suivantes peuvent être obtenues en exécutant l'outil de débogage :

img


Lire les informations du contrat

Il existe un grand nombre d'applications de contrats intelligents exécutées sur Ethereum.ENSest l'un d'entre eux.ENS, à savoir Ethereum Name Service, est un service décentralisé de résolution de noms de domaine basé sur la blockchain Ethereum.
Vous vous souvenez de l’exemple du tutoriel où nous avons interrogé le solde du portefeuille du fondateur d’Ethereum, Vitalik Buterin ? L'une des adresses de portefeuille de Vitalik est :0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045. Alors comment connaissons-nous cette adresse ? En fait, à traversENSContrat intelligent, utilisant un nom intuitifvitalik.eth(vitalik est le nom de Vitalik) pour mener la requête.

Le contenu suivant de ce chapitre utilise l’environnement du réseau principal Ethereum.ENSLe document montre que le nom de domaine Ethereum à interroger doit êtreHashing Names, utilisez le code suivant pourvitalik.ethLe nom est traité.

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

Dans l'exemple de code ci-dessus, nous voyons une autre fonction inconnueEncodeCette fonction est la fonction API de la plateforme FMZ, qui est spécifiquement utilisée pour effectuer des opérations d'encodage sur la plateforme FMZ. Cette fonction prend en charge plusieurs méthodes d'encodage et plusieurs algorithmes de hachage.

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

Selon la documentation ENS, utilisezsha3.keccak256Les algorithmes traitent les données.

AppelnameHashFonctions, par exemple :Log(nameHash("vitalik.eth")), nous pouvons obtenir :ee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835, vous devez ajouter le préfixe « 0x ».0xee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835En tant que contrat intelligent ENSresolverLes paramètres de la méthode.

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

Selon le document ENS, l'adresse du contrat de l'application de contrat intelligent ENS est :0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e. En appelant le contrat intelligentresolverAvant de continuer, nous devons préparer le contratABI

Enregistrement de l'ABI

Après avoir appris cela, je ne peux pas m’empêcher de demander : qu’est-ce qu’un contrat intelligent ?ABIÉtoffe de laine?

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

Extraire les éléments suivants de l'ENS ABI :resolverL'ABI complet peut également être utilisé dans lehttps://etherscan.io/Vous pouvez interroger l'ABI du contrat sur GitHub ou obtenir l'ABI par d'autres moyens (par exemple, des documents de projet pertinents).

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

Ici, nous devons apprendre une nouvelle méthode d'appel sur la plateforme FMZ.exchange.IO("abi", address, abiContent), utilisez cette méthode pour enregistrer ABI,addressLe paramètre est l'adresse du contrat intelligent.abiContentLe paramètre est l'ABI du contrat intelligent correspondant (chaîne).

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

Appel de méthodes de contrats intelligents

Ensuite, vous pouvez appeler le contrat intelligent ENSresolverméthode, qui renvoieENS: Public ResolverL'adresse du contrat.

img

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

utiliserENS: Public ResolverContractueladdrMéthode pour obtenir l’adresse du portefeuille de Vitalik. Pour appelerENS: Public ResolverLe contrat doit encore d’abord enregistrer l’ABI. Les informations ABI de ce contrat intelligent peuvent toujours être trouvées à l'adressehttps://etherscan.io/Obtenir.

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

Dernier appelENS: Public ResolverContractueladdrMéthode, les paramètres sont toujoursensNode

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

Sortie de la fonction log :

img

run
vitalikAddress: 0xd8da6bf26964af9d7eed9e03e53415d37aa96045

Code complet pour appeler 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) }

Envoyer de l'ETH

Dans les chapitres précédents du cours, nous avons appris à configurer des clés privées. Pour l'objet d'échange configuré, comment connaissons-nous l'adresse du portefeuille correspondant à cette clé privée ? Disponible sur FMZexchange.IO("address")La fonction obtient l'adresse du portefeuille correspondant à la clé privée configurée.

Étant donné que le contenu suivant de ce chapitre utiliseGoerliEnvironnement réseau de test, donc le nœud que j'utilise est :https://goerli.infura.io/v3/*******Infura attribue des adresses de nœud différentes à chaque utilisateur enregistré.*******Le contenu spécifique est caché.

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

img

Une fois que vous connaissez l'adresse de votre portefeuille, vous pouvez utiliser la méthode RPC d'Ethereumeth_getTransactionCountInterroger le nombre de transactions d'une adresse de portefeuille. Ce nombre est très couramment utilisé dans Ethereum. En fait, c'est ce qui doit être transmis lors d'un transfert d'argent.nonceParamètres, dans Ethereum, nonce est un nombre utilisé pour garantir que chaque transaction est unique. Il s'agit d'un nombre croissant qui est automatiquement incrémenté à chaque fois qu'une nouvelle transaction est envoyée. Par conséquent, lorsque vous envoyez une transaction à un contrat intelligent, vous devez fournir un nonce pour garantir que la transaction est unique et dans le bon ordre. Dans certaines données et documents, nous pouvons trouver :

https://goethereumbook.org/en/

img

Voici la bibliothèque Ethereum en langage GoPendingNonceAtLa fonction appelle en faiteth_getTransactionCountméthode. Dans le cours précédent, nous avons également appris à appeler des méthodes RPC. Nous l'utiliserons à nouveau ici.exchange.IO("api", "eth", ...)fonction.

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

Avant d'expliquer le fonctionnement du transfert, comprenons brièvement quelques concepts. Lors du transfert d'argent sur Ethereum, une certaine quantité de jetons ETH sera consommée (en tant que frais de gaz). Le tarif du gaz est déterminé par deux paramètres :

  • gasPrice

    Cependant, les frais de gaz sur le réseau Ethereum fluctuent toujours en fonction de la demande du marché et de ce que les utilisateurs sont prêts à payer, donc écrire des frais de gaz fixes dans le code n'est parfois pas idéal. Nous pouvons utiliser ce que nous avons appris auparavanteth_gasPriceMéthode permettant d'obtenir le prix moyen du gaz.

  • gasLimit

    La limite de gaz pour un transfert d'éther standard est de 21 000 unités.

J'ai comprisnoncegasPricegasLimitAvec ces concepts, vous pouvez tester le transfert. Une fonction de transfert très simple et facile à utiliser est encapsulée sur FMZ.

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

Lorsqu'il est utilisé pour le transfert,exchange.IOLe troisième paramètre est toujours « envoyer ».toAddressLe paramètre est l'adresse qui reçoit l'ETH lors du transfert.toAmountLe montant d'ETH transféré.

noncegasPricegasLimitCes paramètres peuvent utiliser les valeurs obtenues automatiquement par le système par défaut sur FMZ. Vous pouvez également spécifier :

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

Ensuite, nous transférons une certaine quantité d'ETH vers une certaine adresse sur le réseau de test 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 }

Parce que l'unité du montant du transfert Ethereum estwei, vous devez utiliser une fonction personnaliséetoInnerAmountTraité commeweiLa valeur de l'unité.

existerhttps://etherscan.io/Requête de hachage de transaction :0xa6f9f51b00d8ae850b0f204380b59da98f4bbce34b813577d3d948f61de4734e

img

Vous pouvez également écrire du code pour interroger le hachage de transfert0xa6f9f51b00d8ae850b0f204380b59da98f4bbce34b813577d3d948f61de4734e,utilisereth_getTransactionReceiptMéthode à interroger.

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

Résultats de la requête :

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

Description de chaque champ :

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

Appel du contrat intelligent Ethereum

Nous sommesLire les informations du contratCette section utilise un exemple complet pour appeler le contrat ENS déployé sur Ethereum pour obtenir l'adresse du portefeuille de Vitalik. Ces méthodes appartiennent àReadMéthodes, l'appel de ces méthodes n'est pas nécessairegas(Vous vous souvenez de ce dont nous avons parlé à propos du gaz avant ?). Dans cette section, nous appellerons certains contrats intelligents sur EthereumWriteMode et paiementgas. Ces opérations seront vérifiées par chaque nœud et mineur sur l’ensemble du réseau et modifieront l’état de la blockchain.

ERC20

Pour les contrats ERC20 (contrats de jetons ERC20), la plateforme FMZ répertorie l'ABI du contrat ERC20 comme un ABI couramment utilisé et l'intègre directement dans le système, éliminant ainsi l'étape d'enregistrement de l'ABI. Nous avons également découvert l'ABI dans le tutoriel précédent. Lorsque nous appelons la méthode du contrat ENS, nous enregistrons d'abord l'ABI du contrat ENS.

Pour mieux comprendre l'ABI, vous pouvez le vérifier avant de l'utiliser. Voici l'ABI du contrat 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"}]

Le contenu suivant de ce chapitre est utiliséGoerliEnvironnement de testnet.

balanceOf

Ensuite, pratiquons à nouveau comment appeler le contrat.ReadMéthode pour lire les informations du contrat et appeler le contrat ERC20balanceOfMéthode pour interroger le solde du jeton,balanceOfLa méthode n'a qu'un seul paramètre, mais il n'est pas nommé. D'après le type, nous pouvons voir qu'il s'agit d'une adresse (c'est-à-dire l'adresse du jeton à interroger). Étant donné que les données renvoyées ne sont pas exprimées en unités d'un jeton, les données de précision du jeton sont également nécessaires pour la conversion. La précision du jeton peut être calculée à l'aide du contrat ERC20decimalsAcquisition de méthode. Nous utilisons le testnet EthereumgoerliTestez-le et notez que l’adresse du contrat de jeton peut être différente sur différentes chaînes.

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

En exécutant le code ci-dessus, vous pouvez interroger les soldes des jetons WETH et LINK dans le portefeuille actuel :

Précision WETH : 18 wethBalance : 0
Précision du LIEN : 18 lienÉquilibre : 51,41374973681053

deposit

Vous pouvez voir que le solde du jeton WETH dans ce portefeuille est de 0. Ensuite, nous continuons à interagir avec le contrat intelligent ERC20 du jeton WETH. Cette fois, nous appelons la méthode de type Write :deposit
depositEn termes simples, la fonction de cette méthode est de convertir une certaine quantité d’ETH en WETH.depositLa méthode n'a pas de paramètres (ce qui peut être observé en regardant l'ABI), et la méthode a les attributs suivants :payablepourtruePar conséquent, vous devez définir le montant du transfert ETH (payableAmount) lors de l'appel pour spécifier le montant d'ETH à déposer.

Remarque lors de l'appel des méthodes de contrat intelligent :
Si la méthode appelée possède l'attribut payable, vous devez ajouter une valeur de transfert ETH après le nom de la méthode (le quatrième paramètre de la fonction exchange.IO), qui peut être un type numérique ou une valeur de chaîne.

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

Précision WETH : 18 wethBalance : 0
Précision ETH : 18 ethBalance : 0,14333094664072302
Transaction Hash: 0xaf15b0b0e25a81eda583295e82b249e2d02e4eafebecc906470ccc2c89e23563

img

Interrogez à nouveau les soldes de WETH et ETH :

Précision WETH : 18 wethBalance : 0,01
Précision ETH : 18 ethBalance : 0,1333309358060905

AppeldepositAvantWETHest 0,ETHest 0,14333094664072302, appelantdepositaprèsWETHest de 0,01,ETHC'est 0,1333309358060905. Vous pouvez voir que 0,01 a été correctementETHRemplacé parWETH

transfer

Les jetons ERC20 peuvent également être transférés à l'aide detransferMéthode pour transférer vers cette adresse0x4D75a08E870674E68cAE611f329A27f446A668130,01 jetons WETH.transferLa méthode a deux paramètres, le premier paramètredstEst l'adresse du portefeuille du destinataire du transfert, le deuxième paramètrewadIl s'agit du montant du transfert.

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

L'exemple ci-dessus utilise une fonction personnaliséewaitMinedEn fait, nous ne sommes pas étrangers à la fonction de cette fonction. Rappelez-vouseth_getTransactionReceiptMéthode? La fonction de cette fonction personnalisée waitMined est d'attendre le résultat du hachage de transaction transmis.

Pour ce transfert WETH, les lecteurs intéressés peuvent également interroger le hachage de transaction0x2fafb62b548a1fffb0f3189429e3c5a4f57ddafb0acbc0678d8b3cf0a2f7c92cpour voir les détails (notez que c'est sur le testnet goerli).

withdraw

Cette fois-ci nous avons misWETHÉchangeETH,utiliserwithdrawméthode, qui n'a qu'un seul paramètrewad, en termes simples, il est utilisé pour définir la quantité d'ETH à échanger.

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

Vous pouvez voir le code ci-dessus et le précédentdepositLes exemples de méthodes sont fondamentalement les mêmes, sauf que la méthode appelée à la dernière étape est modifiée enwithdraw, avant d'appeler :

Précision WETH : 18 wethBalance : 0,01
Précision ETH : 18 ethBalance : 0,11322979983231546

Requête à nouveau :

Précision WETH : 18 wethBalance : 0
Précision ETH : 18 ethBalance : 0,1231207156449464

Vous pouvez voir que 0,01WETHRevenu en arrièreETH

Uniswap V3

Uniswap V3Il s'agit d'un protocole de trading décentralisé construit sur la blockchain Ethereum pour le trading et la fourniture de liquidités de crypto-monnaies. Il se compose d'une série de contrats intelligents, notamment des contrats de base, des contrats de pool, des contrats d'usine, des contrats de routage, etc.

UtiliséUniswapLes contrats suivants sont principalement utilisés pour interroger le prix de change actuel et effectuer des opérations de change :

  • Router(Contrat de routage)
    Il s'agit d'un contrat utilisé pour exécuter des transactions, permettant aux utilisateurs d'effectuer des opérations de transaction en spécifiant des chemins et des paramètres de transaction.
  • Pool(Contrat de piscine)
    Le contrat de piscine estUniswapUn composant clé de la blockchain Ethereum utilisé pour stocker et gérer la liquidité de paires d'actifs spécifiques. À chaque paire d'actifs correspond un contrat de pool, qui contient des informations telles que les fonds fournis par le fournisseur de liquidité, la fourchette de prix, les paramètres de frais, etc. Le contrat de pool est responsable du traitement des transactions, du calcul du statut du pool de fonds et de la garantie du bon déroulement des transactions.
  • Factory(Contrat d'usine)
    Les contrats d'usine sont utilisés pour créer et gérerUniswapLe contrat du contrat de piscine. Lorsqu'un utilisateur souhaite créer une nouvelle paire d'actifs, il déploie un nouveau contrat de pool en interagissant avec le contrat d'usine. Le contrat d'usine est chargé de coordonner la création et l'initialisation du contrat de pool, permettant aux utilisateurs de créer dynamiquement de nouvelles paires d'actifs.

Sur la base de ce que nous avons appris auparavant, examinons comment enregistrer des contrats intelligents dans le code de stratégie de la plateforme de trading quantitatif FMZ.ABINous avons déjà expliqué comment obtenir l'ABI d'un contrat intelligent dans les cours précédents, nous ne le répéterons donc pas ici.
Trois inscriptions sont requisesUniswapContrats intelligentsABI, en utilisant le réseau principal Ethereum comme exemple :

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 }

Le code ci-dessus enregistre l'ABI du contrat d'usine, du contrat de routage et du contrat de pool, et effectue quelques tests. On peut observer que le contrat de routage et le contrat de poolfactoryLa méthode renvoie0x1F98431c8aD98523631AE4a59f267346ea31F984Cette adresse est le contrat d'usine Uniswap (dans le codecontractV3FactoryAddressvariable).

javascript
var contractV3FactoryAddress = "0x1F98431c8aD98523631AE4a59f267346ea31F984"

Après avoir enregistré l’ABI du contrat intelligent, examinons d’abord son utilisationUniswap V3Pour l'opération d'échange, nous utilisons le contenu suivantERC20L'échange de jetons (sur le réseau principal Ethereum) est utilisé comme scénario spécifique.

RequêteUniswap V3Autorisation de contrat de routage

existerERC20Dans le contrat,allowanceLa fonction permet d'interroger le nombre de jetons autorisés sur d'autres adresses. Il peut interroger le nombre de jetons qu'une adresse spécifique a autorisé une autre adresse (généralement une adresse de contrat) à transférer depuis son propre compte.
pourUniswap V3Pour le contrat de routage, si vous avez exécutéapproveLa fonction est autorisée à l'adresse du contrat du routeur, vous pouvez alors l'utiliserERC20JetonallowanceFonction permettant d'interroger la quantité autorisée.

Rappelez-vous que dans le tutoriel précédent, nous avons démontréERC20L'appel de la méthode du contrat ?allowanceapproveLes deuxERC20Les modalités du contrat sont similaires à celles que nous avons expliquées précédemment.balanceOftransferToutes les méthodes ont le même statut.

Avant de procéder à l'échange, nous devons d'abord vérifier si l'autorisation est donnée àUniswapLe contrat du routeur dispose de suffisamment de jetons pour effectuer l'échange. Si l'action que nous souhaitons échanger est :1INCH->ETH, le taux est fixé à 10 000. Ce taux est fixé à 10 000, ce qui signifie que le taux est de 1 %.UniswapLe pool d'échange peut avoir une variété de taux, généralementUniswapPlusieurs options sont proposées. Par exemple, si le taux est fixé à 3000, cela signifie que le taux est de 0,3 %. Vous pouvez vérifier le taux spécifiqueUniswapDocuments et informations connexes.

Il convient de noter ici que le pool d'échange réel est1INCH/WETH, ETH et WETH sont deux jetons différents dans Ethereum.

  • ETH (Éther) :
    ETH est la crypto-monnaie native de la blockchain Ethereum et le principal actif et unité de calcul du réseau Ethereum. ETH est le jeton natif d'Ethereum, qui a une circulation et une utilisation universelles. Il peut être utilisé pour payer les frais de transaction, participer à des interactions de contrats intelligents, stocker de la valeur, etc.
  • WETH (éther enveloppé) :
    WETH est une forme d'ETH encapsulée sous la forme d'un jeton standard ERC20. Il s'agit d'un contrat intelligent sur Ethereum qui vise à permettre à ETH d'interagir de manière transparente avec les jetons ERC20 dans les contrats intelligents. WETH peut être créé et obtenu en déposant ETH dans l'adresse du contrat WETH, et WETH peut être transféré à nouveau en ETH à tout moment. Le rôle principal de WETH dans l'écosystème Ethereum est de fournir à ETH la même interface standard et la même compatibilité que les autres jetons ERC20, permettant à ETH de participer à des transactions décentralisées, des pools de liquidités et d'autres protocoles DeFi.

Par conséquent, WETH est une forme packagée d'ETH qui permet à ETH d'interagir sous la forme de jetons ERC20 dans les contrats intelligents Ethereum. En règle générale, lorsque l'ETH doit être utilisé dans un contrat intelligent, l'ETH peut être converti en WETH, échangé ou impliqué dans des opérations DeFi, puis le WETH peut être reconverti en ETH selon les besoins.

utiliserERC20deallowanceMéthode pour obtenir la quantité autorisée :

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

Pour le codetoAmount()Nous devrions être familiers avec les fonctions. Nous avons utilisé ce code de fonction personnalisé à de nombreuses reprises dans les chapitres précédents pour traiter les données en valeurs numériques faciles à lire pour les humains.

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

Lors de l'exécution du code, nous constatons que la quantité autorisée actuelle est de 0. Par conséquent, pour pouvoir échanger, nous devons autoriser une quantité suffisante au contrat de routage.

img

AutorisationUniswap V3Contrat de routage

Si vous utilisezallowanceSi le nombre d'autorisations est insuffisant après l'interrogation, vous devez utiliserapproveAutorisationUniswap V3Les contrats de routage lui permettent d'exploiter un certain nombre deERC20Jetons.

Ou1INCH -> ETHPar exemple, utilisezERC20deapproveMéthodesUniswapLe contrat de routage autorise le fonctionnement du portefeuille actuellement configuré1INCHJetons.

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

Ajouté untoInnerAmount()L'implémentation de la fonction personnalisée. Cette fonction a été fréquemment utilisée dans nos cours précédents, je n'entrerai donc pas dans les détails ici.
Vous pouvez voir l'enregistrement d'autorisation et appeler à nouveau le code pour vérifier l'état de l'autorisation :

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

img

Échange de jetons avec Uniswap

Lorsqu'il y a suffisamment de jetons dans le portefeuille pour payer (c'est-à-dire : tokenIn) et l'autorisationUniswapLe contrat de routage comporte suffisamment d’opérations, et l’échange peut alors être exécuté.
UniswapLes contrats de routage ont plusieurs méthodes de rachat, qui sont présentées iciexactInputMéthode, le pool d'échange réel est1INCH/WETH, échanger et utiliser à nouveauunwrapWETH9Méthode pour décompresser WETH en ETH. Nous avons discuté de ce concept dans le chapitre précédent de l’ERC20.withdrawExpliqué dans la description.

L'opération d'échange utilise principalement 3 méthodes, à savoirexactInputunwrapWETH9multicall, d'abord misUniswapContrat de routageexactInputAppel de méthode,unwrapWETH9Le code d'appel de la méthode est ensuite utilisé par le contrat de routagemulticallExécution par lots de méthodes.

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)
  • utiliserexchange.IO("encodePacked", ...)La fonction encode et compresse les paramètres de débit.
  • selonexactInputExigences relatives aux paramètres de la méthode, paramètres du chemin de constructionpath
  • utiliserexchange.IO("encode", ...)Codage de fonctionexactInputAppel de méthode.
    Remarque : si l'échange final est ETH ou WETH, le paramètre destinataire de la méthode exactInput doit être spécifié comme « 0x00000000000000000000000000000000000000000000002 »
  • utiliserexchange.IO("encode", ...)Codage de fonctionunwrapWETH9(uint256,address)Appel de méthode.
  • utilisermulticall(uint256,bytes[])la méthode exécute l'appel de fonction codé ci-dessus.

Interroger les résultats de l'échange :

img

Code complet:

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

Obtenez le prix d'échange dans le pool

Comme nous l'avons expliqué précédemment, lorsque nous utilisons l'adresse du jeton (il y en a deux, tokenIn et tokenOut) et le paramètre de débit, nous pouvonsUniswapdeFactoryContractuelgetPoolMéthode pour obtenir l'adresse du pool d'échange (contrat intelligent) de cette combinaison d'échange.
Après avoir obtenu l'adresse du pool d'échange, enregistrez l'ABI du contrat de pool. Ensuite, vous pouvez appeler le contrat de piscineslot0Méthode permettant d'obtenir des données relatives au prix de change actuel et d'analyser ultérieurement le prix de change.

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

Obtenez les informations sur les prix du pool d'échange et imprimez le codeslot0variable:

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

Les principales données d'information sur les prix sont enregistrées danssqrtPriceX96sur le terrain, le prix actuel du pool d'échange doit être calculé sur la base des données de précision du jeton de la combinaison d'échange.UniswapComme décrit dans le document, nous implémentons une fonction pour calculer :

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

Utilisez cette fonction pour calculer la combinaison de jetons1INCH/WETH, le prix actuel du pool d'échange avec des frais de 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) }

Variables d'impressionpricemontrer:price: 0.000203(1 1INCH est échangé contre 0,000203 WETH).

Bibliothèque de trading Uniswap V3

L'inventeur de la plateforme de trading quantitative a publié un packageUniswapmodèle, qui a réalisé des fonctions telles que l'échange, l'acquisition de prix et la requête de solde de portefeuille. Vous n'avez pas besoin de répéter le code selon le contenu expliqué ci-dessus. Vous pouvez lire le code source de ce modèle pour en savoir plus et développer des applications Web3 .
Il y a de nombreux détails qui méritent d'être appris dans cette bibliothèque de modèles :

  • Obtenir automatiquement les informations sur les jetons
    Prenez une section du code pour expliquer, lorsque les paramètres du modèleAutoFetchTokensLorsqu'il est défini sur vrai, le programme de modèle accédera automatiquementhttps://tokens.coingecko.com/uniswap/all.jsonLiez, obtenez et traitez automatiquement toutes les informations du jeton. De cette façon, vous n'avez pas besoin d'ajouter manuellement un jeton au code de stratégie (sinon vous devrez utiliseraddToken(name, address)(Ajouter un jeton).

    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 } } }) }
  • Adapter différentes adresses de contrat en fonction des paramètres de la chaîne
    Ce modèle définitChainTypeParamètres, prise en charge de la commutation de plusieurs chaînes :

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

    Extrait du code :

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

    Appel de la méthode RPC d'Ethereumeth_chainIdRequête actuellechainId, et puis selonchainIdPour adapter l'adresse WETH,UniswapUne série d'adresses contractuelles,USDTL'adresse du contrat d'un contrat intelligent peut être différente sur différentes chaînes.

    Extrait du code :

    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") }
  • Utilisation de la « Bibliothèque de trading Uniswap V3 »

    Dans ce modèle$.testUniswap()La fonction est une fonction qui teste la fonctionnalité du modèle. Son code donne un exemple d'utilisation de l'appel de modèle :

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

    Lorsqu'une stratégie fait référence à la « Bibliothèque de trading Uniswap V3 » (pour plus d'informations sur la manière de référencer la bibliothèque de modèles, veuillez vous référer à la documentation de la plateforme FMZ), vous pouvez appeler les fonctions encapsulées dans cette bibliothèque de modèles.

    Créez un fichier appeléexVariables, appelez la fonction d'interface encapsulée par le modèle « Uniswap V3 Trading Library »$.NewUniswapV3()Créer un objet et l'assigner àex

    javascript
    let ex = $.NewUniswapV3()

    utiliserexFonctions membres d'un objetaddToken()Ajouter (enregistrer) des informations sur le jeton.

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

    Si vous souhaitez obtenir et imprimer le prix du pool d'échange d'une certaine paire de négociation, vous pouvez utiliserexFonctions membres d'un objetgetPrice(), vous pouvez écrire :

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

    Si vous souhaitez effectuer une opération de rachat, vous pouvez utiliserexFonctions membres d'un objetswapToken(), exécuter l'échange :

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

Récupérer les événements

Dans ce chapitre, nous allons apprendre à utiliser la plateforme de trading quantitative Inventor pour lire les événements émis par les contrats intelligents. Les événements émis par les contrats intelligents sont stockés dans le journal de la machine virtuelle Ethereum.

eth_getLogs

Pour interroger les événements publiés par les contrats intelligents, vous devez utiliser la méthode RPC d'Ethereumeth_getLogs, obtenez les données du journal en chaîne. Nous avons déjà expliqué comment appeler le nœud RPC Ethereum dans notre cours précédent.
Par exemple, nous obtenonsWETHLes événements contractuels peuvent être codés à l'aide de FMZOutils de débogageTest, le nœud RPC configuré par l'objet d'échange est le nœud du réseau principal Ethereum, lors de l'appeleth_getLogsNous avons spécifié trois paramètres lors de l'utilisation de la méthodefromBlocktoBlockaddress, nous utilisons les paramètres fromBlock et toBlock pour limiter la requête aux données d'un bloc :

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 }

Nous obtenons les données des journaux. Comme les données sont volumineuses, nous omettons une partie du contenu :

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

Vous pouvez voir qu'il y a divers événements dans les données du journal. Si nous nous intéressons uniquement àTransferL'événement doit convertir ces données enTransferLes événements sont filtrés.

Récupérer les journaux

Les journaux Ethereum sont divisés en deux parties : 1. Sujettopics2. Donnéesdata

  • thèmetopics
    pareth_getLogsPrenons comme exemple le code exécutant les résultats du test du chapitre.topicsLes données du champ sont :

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

    cetopicsLa valeur du champ (sujet) est une structure de tableau qui décrit l'événement. Il est stipulé que sa longueur (de tableau) ne peut pas dépasser 4, et le premier élément est la valeur de hachage de signature de l'événement.
    Dans la plateforme de trading quantitative Inventor, nous utilisonsEncodeLa fonction peut calculer la valeur de hachage de la signature à l'aide du code suivant :

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

    CalculéTransfer(address,address,uint256)dekeccak256La valeur de hachage (codage hexadécimal) est0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef

    topicsLa valeur du champ est une structure de tableau, le deuxième élément et le troisième élément sont :

    • Adresse d'envoifrom
    • Adresse de réceptionto
  • donnéesdata

    dataLes données du champ sont :

    desc
    "data": "0x0000000000000000000000000000000000000000000000000164f2434262e1cc",

    Certains paramètres de l'événement (paramètres sans déclaration indexée dans le code Solidity du contrat intelligent) seront stockés dansdatapartie.

    Analyse de ces données0x0000000000000000000000000000000000000000000000000164f2434262e1cc

    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 }

    Les données sont : 0,10047146239950075,dataLes données correspondent au montant du transfert.


Après avoir expliqué et pratiqué le contenu ci-dessus, vous êtes prêt. Nous pouvons commencer à récupérer les journaux :

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

existerhttps://etherscan.io/Sur demande :

img

Les résultats de l'exécution du code de test dans l'outil de débogage FMZ :

img

Selon les besoins de récupération, il peut également être analyséfromtoLes données du champ, par exemple :

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

Résultats de l'opération :

address: 0x12b791bb27b3a4ee958b5a435fea7d49ec076e9c

Surveiller les événements contractuels

parce queOutils de débogageLe code ne peut être testé que pendant une courte période et le contenu n'est affiché qu'après l'exécution du code. Il est impossible d'afficher et de générer des journaux en temps réel. Dans cette section, nous utilisons la plateforme de trading quantitative Inventor pour créer un compte réel à des fins de test.

Ici, nous utilisons le réseau principal Ethereum, surveillonsUSDTCe contrat de changeTransfer(address,address,uint256)Événements, sur la base de ce que nous avons appris lors du dernier cours, nous avons conçu et écrit un exemple de surveillance continue d'un événement de contrat intelligent :

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

Fonctionnement du disque réel :

img

Pour les résultats d'exécution, une partie de vérification (TODO : test) est également écrite dans le code. Après une simple vérification, nous pouvons voir que le contrat USDT est surveillé en permanence.TransferLes événements sont enregistrés et les données sont enregistrées. En comparant ces données avec les données d'événements obtenues une fois, on peut observer que les données sont cohérentes :

img

Filtrage des événements

Sur la base de la leçon précédente « Surveillance des événements de contrat », nous allons développer ceci en ajoutant des filtres au processus de surveillance pour surveiller les transferts entrants et sortants des adresses spécifiées. Lorsqu'un contrat intelligent crée un journal (c'est-à-dire publie un événement), les données du journaltopicsContient jusqu'à 4 messages. Nous concevons donc une règle de filtrage pour[[A1, A2, ...An], null, [C1], D]Par exemple.

1、[A1, A2, ...An]correspondretopics[0]Données de localisation.
2、nullcorrespondretopics[1]Données de localisation.
3、[C1]correspondretopics[2]Données de localisation.
4、Dcorrespondretopics[3]Données de localisation.

  • Si les éléments de la structure Case sont définisnullIndique qu'il n'est pas filtré, par exemplenullcorrespondretopics[1], toute valeur correspond.
  • Si un élément dans une structure de cas définit une valeur unique, cela indique que la position doit correspondre, par exemple[C1]correspondretopics[2]ouDcorrespondretopics[3], les journaux non correspondants sont filtrés.
  • Si l'élément de la structure conditionnelle est un tableau, cela signifie qu'au moins un élément du tableau doit être mis en correspondance, par exemple[A1, A2, ...An]correspondretopics[0][A1, A2, ...An]L'un d'entre euxtopics[0]Si une correspondance est trouvée, le journal ne sera pas filtré.

Surveiller les transferts USDT sur les échanges

Surveiller les transferts depuis et vers BinanceUSDTTransaction:

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

Le code ci-dessus est exécuté sur un disque réel :

img

img

Dans cette leçon, nous avons présenté comment concevoir des filtres d’événements. Et je l'ai utilisé pour surveiller le portefeuille chaud de Binance ExchangeUSDTcommerce. Vous pouvez modifier et étendre cet exemple de programme pour écouter tous les événements qui vous intéressent.smart moneyQuelles nouvelles transactions ont été réalisées ?NFTSur quels nouveaux projets travaillent les grands noms, etc.

Conversion d'unités

Dans de nombreux calculs liés à Ethereum, les valeurs dépassentJavaScriptL'entier maximal sûr pour la langue. Par conséquent, certaines méthodes sont nécessaires pour traiter de grands nombres sur la plateforme de trading quantitatif Inventor. Nous avons utilisé ces méthodes dans des cours précédents, mais nous ne les avons pas expliquées en détail. Ce chapitre traitera cet aspect en détail.

ImprimerJavaScriptLe plus grand entier sûr défini dans le langage :

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

Résultats de l'opération :

Number.MAX_SAFE_INTEGER: 9007199254740991

BigInt

La plus petite unité définie dans Ethereum est1wei,définition1Gweiégal1000000000 wei1GweiEn fait, ce n'est pas un nombre très important dans les calculs liés à Ethereum. Certaines données sont bien plus volumineuses que cela. Ensuite, ces données avec des valeurs très importantes peuvent facilement dépasserNumber.MAX_SAFE_INTEGER: 9007199254740991

Dans la plateforme de trading quantitative Inventor, nous utilisons la plateformeBigIntLes objets sont utilisés pour représenter ces très grandes données entières. Utilisation des constructeursBigInt()ConstruireBigIntobjet. Peut être construit en utilisant des valeurs numériques ou des chaînes numériques hexadécimales comme paramètresBigIntobjet. utiliserBigIntObjettoString()La méthode génère les données représentées par l'objet sous forme de chaîne.

BigIntOpérations prises en charge par l'objet :

  • Opération d'addition :+
  • Soustraction:-
  • Multiplication:*
  • Opération de division :/
  • Opération modulo :%
  • Fonctionnement électrique :**

Reportez-vous à l’exemple de code suivant :

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

Test de l'outil de débogage :

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

BigFloatObjets etBigIntL'objet est utilisé de la même manière et permet de représenter des nombres à virgule flottante avec des valeurs plus grandes. Il prend également en charge les opérations d'addition, de soustraction, de multiplication et de division.
BigFloatSupport d'objettoFixed()méthode.

Reportez-vous à l’exemple de code suivant :

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

Test de l'outil de débogage :

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

BigDecimalL'objet est compatible avec les valeurs entières et à virgule flottante et prend en charge l'utilisation deBigIntObjets,BigFloatL'initialisation d'objet prend également en charge les opérations d'addition, de soustraction, de multiplication et de division.

Reportez-vous à l’exemple de code suivant :

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

Exécuter dans le débogueur :

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

Conversion d'unités

Les deux fonctions suivantes :toAmount()toInnerAmount()Nous avons déjà utilisé ces deux fonctions à plusieurs reprises dans les cours précédents. Elles sont principalement utilisées pour la conversion de précision des données.

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()La fonction convertit une variables, selon le paramètre de précisiondecimalsEffectuer une conversion (réductrice). Dans le développement actuel du web3, il est souvent nécessaire de traiter certaines données hexadécimales sur la chaîne.
Nous rencontrons souvent cela dans nos cours précédents, comme sur les contrats intelligents.Transfer(address,address,uint256)Dans l'événementdataDonnées de terrain :

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

Traitement des données"data": "0x00000000000000000000000000000000000000000000000001c1a55000000000", cette fois, utiliseztoAmount()fonction. Cette conception de traitement peut très biendataConvertissez les données de champ en valeurs numériques lisibles.

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 jeton ETH que nous connaissons est1e18 weiSi nous obtenons unweiDonnées en unités126564027559051260Comment le convertir en nombre de jetons ETH ?
utilisertoAmount(, 18)Les fonctions peuvent être facilement converties.toInnerAmount()La fonction esttoAmount()L'opération inverse de la fonction (selon la précision, l'amplification), en utilisant ces deux fonctions, il est très pratique de convertir les données.

Il convient de noter que la plage de sécurité des valeurs entières dans le langage JavaScript estNumber.MAX_SAFE_INTEGER, l'exemple suivant illustre un problème plus caché dans la conversion de données :

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

Vous pouvez l'exécuter dans le débogueur :

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

Grâce à l'observation, nous avons constaté que :

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

La sortie du journal correspondant à cette ligne de code est :转换 10000000000000000 为十六进制: 10000000000000000, mais il n'a pas été converti correctement. La raison est naturellement que 100000000000000000 dépasseNumber.MAX_SAFE_INTEGER

Cependant, lorsque la valeur décimale se situe dans la plage de sécurité, c'est-à-dire inférieure àNumber.MAX_SAFE_INTEGERheure,toString(16)La conversion de fonction est à nouveau normale, par exemple :

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

Dans le domaine de la blockchain, même0.01ETH converti enweiLa valeur de l'unité10000000000000000Il dépassera égalementNumber.MAX_SAFE_INTEGER, donc une conversion plus sûre pour cette situation est :BigInt(10000000000000000).toString(16)

Simuler un appel

Exécutez des transactions et appelez des contrats intelligents sur EthereumWriteCette méthode consomme une certaine quantité de gaz et comporte parfois des risques d'échec. Il est important de savoir quelles transactions peuvent échouer avant de les envoyer ou de les appeler. Il existe des méthodes d'appel simulées sur Ethereum à des fins de test.

eth_call

Méthode RPC d'Ethereumeth_call:Peut simuler une transaction et renvoyer les résultats de transaction possibles, mais n'exécutera pas réellement la transaction sur la blockchain.

eth_callLa méthode a deux paramètres, le premier paramètre est une structure de dictionnaire,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 }

Le deuxième paramètre estblockNumber:Vous pouvez passer des tagslatest/pending/earliestattendez:

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

Ensuite, nous utilisons des jetonsDAIMéthode de contrat intelligentapprovetransferL'appel est un appel simulé par exemple. L'environnement de test suivant est le réseau principal Ethereum.

Simuler l'appel d'approbation

Pour les contrats ERC20approveNous connaissons déjà la méthode et nous l’avons pratiquée lors de cours précédents. Étant donné que le contrat ERC20 est déjà intégré dans l'ABI de la plateforme FMZ, il n'est pas nécessaire d'enregistrer l'ABI du contrat intelligent à simuler.

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

Le code de l'exemple convertit d'abordapprove(address,uint256)Les méthodes et les paramètres sont codés.approveValeurs des paramètres de la méthode0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffIndique le nombre maximum d'autorisations. Autoriser le contrat intelligent, l'adresse0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45Tout de suiteUniswap V3Contrat de routage. Appelez enfin la méthode Ethereum RPCeth_callEffectuer une simulation. Tu peux voirtransactionObjectParamètresgasPricegasLes champs peuvent être omis.

L'outil de débogage exécute et simule l'autorisation réussie de l'appel de la méthode approve (mais n'autorise pas réellement) :

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

Nous pouvons également simuler certains scénarios de défaillance. Lorsque nous ajustonsgasPriceetgasLors de la définition des paramètres, une erreur sera signalée si l'ETH dans le portefeuille n'est pas suffisant pour payer les frais de gaz :

insufficient funds

Lorsque les frais de gaz sont trop bas, une erreur sera signalée :

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

Simuler un transfert d'appel

Pour ERC20transferNous connaissons également cette méthode. Cette méthode permet de transférer des jetons ERC20 vers une certaine adresse de portefeuille. Nous allons essayer de simuler le transfert de 1 000 DAI vers 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 }

Étant donné que mon portefeuille de test ne contient pas de jetons DAI, le résultat de son exécution dans l'outil de débogage est celui attendu, une erreur est signalée :

execution reverted: Dai/insufficient-balance

Consultez l’adresse du portefeuille de Vitalik :0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045On peut voir que ce portefeuille contient des jetons DAI. Ensuite, échangeons le sens de transfert de l'appel simulé et simulons que Vitalik nous transfère 1 000 DAI.

Modifiez le code et ajoutez des commentaires là où vous l'avez modifié :

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

Test de l'outil de débogage :

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

En utilisant la plateforme de trading quantitative Inventor, vous pouvez facilement simuler les résultats des transactions et éviter les pertes de frais de gaz inutiles causées par l'envoi de transactions susceptibles d'échouer. Nous utilisons l'exemple de code de ce chapitre pour simuler l'appel de transfert d'argent vers le portefeuille de Vitalik et le portefeuille de Vitalik qui nous transfère de l'argent. Bien sûr, cecieth_callLes méthodes ont plus d’utilités. Utilisez votre imagination et vous le ferezeth_callOù la méthode est-elle utilisée ?

Identifier les contrats ERC721

Nous savons que les jetons tels que l'ETH et le BTC sont tous des jetons homogènes. Le jeton que vous avez en main n'est pas différent du jeton que j'ai en main. Cependant, il existe de nombreuses choses dans le monde qui sont de nature différente, comme l’immobilier, les antiquités, les œuvres d’art virtuelles, etc., qui ne peuvent pas être représentées de manière abstraite par des jetons homogènes. C'est ainsi que la norme ERC721 a été créée pour abstraire les objets non homogènes, et que les NFT et les concepts associés ont vu le jour.
Alors, parmi les nombreux contrats intelligents déployés sur Ethereum, comment identifier quels contrats intelligents sont des contrats intelligents standard ERC721 ?

Pour identifier ERC721, vous devez d’abord comprendre la norme ERC165.

ERC165

Grâce à la norme ERC165, un contrat intelligent peut déclarer les interfaces qu'il prend en charge afin que d'autres contrats puissent les vérifier. Le contrat d'interface ERC165 n'a qu'une seule fonction :supportsInterface(bytes4 interfaceId),paramètreinterfaceIdL'ID de l'interface à interroger. Si le contrat implémente l'ID d'interface, il renvoie une valeur booléenne true, sinon il renvoie une valeur false.

Ensuite, nous allons parler de celainterfaceIdComment le calculer et le coder spécifiquement.

Norme ERC165Un exemple est donné :

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

Effectuez une opération XOR sur la signature de fonction de l'interface (composée du nom de la fonction et de la liste des types de paramètres). Pour un contrat d'interface ERC165 avec une seule fonction :

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.

Calculez directement la signature de la fonction et prenez les 4 premiers octets pour obtenirinterfaceId

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

Les tests peuvent être exécutés dans le débogueur :

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

Vous pouvez voir les résultats calculés etNorme ERC165La description dans le document est cohérente.

ERC721

Ensuite, examinons la définition de l’interface de la norme contractuelle 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); }

Si nous voulons déterminer si un contrat intelligent est un contrat ERC721, nous devons d’abord connaître le contrat ERC721.interfaceId, avant de pouvoir essayer d'utilisersupportsInterface(bytes4 interfaceId)Jugement de méthode. Dans le cours précédent, nous avons été familiarisés avec certains concepts et calculs de la norme ERC165.interfaceIdNous pouvons écrire directement le code pour calculer l'algorithme :

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

Le code utiliseEncode()La fonction effectue le calcul de la signature de fonction (keccak256Algorithme), pour le calcul dans l'exemple de code ci-dessus, spécifiezEncode()Les paramètres de sortie de la fonction sont"raw", la fonction renvoieJavaScriptLinguistiqueArrayBuffertaper.
Si vous en voulez deuxArrayBufferObjet^Opération (XOR), basée surArrayBufferCréation d'objetTypedArrayLa vue est ensuite itérée sur les données, en effectuant des opérations XOR sur chacune d'elles.

Exécuter dans le débogueur :

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

Vous pouvez voir les résultats calculés eteip-721Le même que celui décrit dans .

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

Avec l'ID d'interface ERC721, nous pouvons déterminer si un contrat est un contrat standard ERC721. Nous utilisonsBAYCPour réaliser le test, il s'agit d'un contrat conforme à la norme ERC721. Tout d'abord, nous devons enregistrer l'ABI. Comme nous n'appelons que les trois méthodes suivantes, nous ne pouvons enregistrer que ces trois méthodes :

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

Le code spécifique est le suivant :

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

Les tests peuvent être exécutés dans le débogueur :

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

Déterminer l'adresse0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13dLe contrat est conforme à la norme ERC721.

Dans ce cours, nous avons expliqué comment identifier les contrats ERC721. Pour les contrats ERC20 qui ne prennent pas en charge les normes ERC165, d'autres méthodes doivent être utilisées pour les identifier. Savez-vous comment vérifier si un contrat est à la norme ERC20 ?

Codage des données d'appel

Qu'est-ce quecalldata? Selon la compréhension de l'auteur, la description simple et populaire ici est :

« Calldata » est l'encodage d'un appel de fonction et de paramètres dans Ethereum. « Calldata » est encodé selon la spécification ABI (Application Binary Interface) du contrat.

Par exemple, nous pouvons utiliser le contrat ERC20 que nous avons appris dans le cours précédentbalanceOftransferL'appel de méthode, ainsi que les paramètres utilisés dans l'appel, sont codés sous forme decalldata. Dans certains scénarios d’application, par exemple :Interaction entre les contrats, qui sera utilisé dans ce scénariocalldata, bien sûr, il existe de nombreux autres scénarios d’application qui ne sont pas répertoriés ici un par un.

Comment coder un appel de fonction de contrat intelligent pour obtenircalldata

Vous pouvez l'utiliser sur la plateforme de trading quantitative Inventorexchange.IO("encode", ...)L'encodage des appels de fonctions de contrats intelligents est également très simple à utiliser.exchange.IO("encode", ...)Le premier paramètre de la fonction est une chaîne fixe"encode"; Le deuxième paramètre est l'adresse du contrat intelligent ; le troisième paramètre est le nom de la méthode du contrat intelligent à encoder ; les paramètres restants transmettent les valeurs de paramètres spécifiques de la méthode du contrat intelligent à encoder.

eth_sendRawTransaction

Lorsque nous codons un appel de méthode de contrat intelligent et générons le correspondantcalldataLors de la génération de données, si la méthode du contrat intelligent est une méthode d'écriture (c'est-à-dire une opération d'écriture), nous devons générercalldataLes données sont utilisées comme champ de données de la transaction, puis la méthode RPC d'Ethereum est utiliséeeth_sendRawTransactionEnvoyez une requête au réseau Ethereum contenant les données brutes de la transaction.

eth_sendRawTransactionLa méthode n'a qu'un seul paramètredata

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

cedataLe paramètre correspond aux données après le calcul de la signature d'une donnée de transaction. La structure des données de transaction d'Ethereum comporte principalement les champs suivants :

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

Comment signer une transaction Ethereum ?

Dans la plateforme de trading quantitative Inventor, nous utilisonsEncode()Fonction permettant d'effectuer un calcul de signature. Nous écrirons un exemple spécifique dans le cours suivant "Exécution de la méthode Write calldata".

Exécutez l'appel de la méthode Readdata

Pour la méthode ReadcalldataPour exécuter, nous utilisons la méthode RPC que nous avons apprise auparavant :eth_callPour exécuter, nous avons expliqué avanteth_callCette méthode Ethereum RPC ne fonctionne que sur des contrats intelligentsWriteDémonstration de la méthode, à l'aide de ce chapitrecalldataL'exemple suivant montre comment appeler la méthode Read du contrat intelligent. Utilisons le contrat WETHbalanceOfMéthode pour lire le solde du jeton WETH du portefeuille actuel.

Nous utilisons des outils de débogage pour tester sur le réseau principal 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个数为单位 }

Exécuter dans le débogueur :

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

Si la méthode du contrat intelligent a une valeur de retour, vous pouvez utiliserexchange.IO("decode", ...)Décodage de fonction. On peut voir qu'en passantcalldataLa méthode d'appel direct des contrats intelligentsbalanceOfLa méthode est la même et le solde WETH de mon portefeuille de test est de 0,015 WETH.

Exécutez l'appel de la méthode Writedata

Pour l'exécution des données d'appel de la méthode Write, vous devez utiliser la méthode RPC :eth_sendRawTransaction.

Nous utilisons des outils de débogage pour tester sur le réseau principal 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 }

Exécuter dans le débogueur :

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

mettre en œuvrevar ret = exchange.IO("api", "eth", "eth_sendRawTransaction", "0x" + signedTx)Fonction, le hachage de transaction renvoyé est :0x2ff585504b0fe59b0122f696e8808abfe2f3ce263448066533f3bb8a4f55e8e6. ceeth_sendRawTransactionLe calldata est appelé pour exécuter le contrat WETH.depositLa méthode échange les 0,005 ETH envoyés contre WETH.

Surveillance du pool de mémoire

Avant que la transaction de l'utilisateur sur Ethereum ne soit intégrée dans la blockchain Ethereum par les mineurs, toutes les transactions sont collectées dansMempoolDans le pool de mémoire de transaction, les « mineurs » recherchent également les transactions avec des frais élevés et les regroupent en premier pour maximiser les avantages miniers. Par conséquent, d’une manière générale, plus le prix du gaz d’une transaction est élevé, plus il est facile de la conditionner.

Certains scripts de transaction le feront égalementMempoolFureter dans l’espoir de trouver des affaires lucratives. Par exemple, si une transaction définit un glissement de change trop élevé, la transaction peut être soumise à une « attaque sandwich » par ces scripts de transaction. Alors, comment ces scripts surveillent-ilsMempoolDanspending(en attente, à emballer) Et l'affaire ?

Écouter en utilisant le protocole REST

En utilisant la méthode RPC que nous avons apprise précédemment :eth_getBlockByNumber, mais nous ne publierons pas les détails cette fois-ci.blockNumber, nous utilisons"pending"Étiquette.

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

Exécuter dans le débogueur :

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

Extraire une des données :

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

Écoute à l'aide du protocole WebSocket

Dans la plateforme de trading quantitative Inventor, nous utilisonsDialFonction pour créerWebSocketConnectez-vous pour voirFMZ APIDocumentationDialfonction.

Le code de test de ce chapitre s'exécute dans l'environnement du réseau principal Ethereum. Comme il utilise le protocole WebSocket pour la communication, il est plus pratique d'utiliser le test quantitatif en temps réel d'Inventor. Le message d'abonnement au protocole Websocket est :

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

En dehors denewPendingTransactions, vous pouvez également vous abonnernewHeadslogs

recevoirWebSocketSe connecter pour envoyer des données :

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

Ensuite selon :"result": "0x69c4251cecb814e17cfe7a5ee41742a616f9a4d1bbf245c49b186b1006fd14d3", demande de renseignements supplémentairestransaction. Pour un spécifiquetransactionNous utilisons la méthode Ethereum RPCeth_getTransactionByHashPour interroger.

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

Créez un vrai disque et exécutez le code ci-dessus. Vous pouvez recevoir les données poussées par la connexion WebSocket. Les données sont poussées en continu. Extrayons l'une d'entre elles.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" }

Extrait (partiellement omis) des données du journal :

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

Décrypter les détails de la transaction

Dans le dernier cours, nous avons écrit un programme de surveillance pour surveiller les transactions en attente sur Ethereum, obtenir le hachage de transaction poussé via le protocole WebSocket, puis interroger les détails de transaction spécifiques en fonction du hachage de transaction.

Ensuite, nous devonsinputLes données de terrain sont ensuite analysées.inputLes données du champ ressemblent à des données hexadécimales aléatoires, mais elles codent en réalité le contenu de la transaction : y compris la fonction appelée et les paramètres d'entrée, etc.

Après des tests répétés et approfondis, il a été constaté que la rapidité et la quantité de données transmises via la connexion WebSocket sont étroitement liées au nœud RPC actuellement utilisé. Lorsque deux services de nœud RPC différents (tels que infura et ALCHEMY) créent une connexion WebSocket au même nœud, En même temps, les données push reçues ne sont pas exactement les mêmes. Étant donné que le scénario actuel générera un grand nombre de requêtes, il est toujours nécessaire d'utiliser un service RPC plus stable et plus rapide. La connexion WebSocket poussera également de nombreux hachages de transaction qui sont en attente depuis longtemps.eth_getTransactionByHashLors de l'interrogation, vous obtenez souvent une valeur nulle (testé sur FMZ et node.js).

Nous avons utilisé ce tempsalchemyNœuds RPC :wss://eth-mainnet.g.alchemy.com/v2/oKmOQKbneVkxgHZfibs-iFhIlIAl6HDN. Ce nœud prend en charge à la fois le protocole WebSocket et le protocole REST.

Nous surveillons le contrat intelligent de routage de l'échange décentralisé Uniswapmulticall(uint256,bytes[])méthode, nous devons donc d'abord calculer le hachage de la signature de fonction de cette méthode.

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

Sur la base de l’exemple de la leçon précédente, nous avons apporté quelques modifications. Lors de la réception de messages envoyés via une connexion WebSocket, utilisezvar data = ws.read(-2)Recevez les dernières données.read()Définir le paramètre de fonction sur -2 signifie renvoyer immédiatement les dernières données. Nous nous soucions uniquement d'incluremulticallAppeléTransaction ,utiliserif (tx && tx.input.indexOf(sigHash) !== -1)Filtrage des jugements.

Besoin de concevoir 2 fonctions personnalisées :

  • calcAllFuncSigHash():Calculez le hachage de signature de toutes les méthodes basées sur l'ABI.
  • decodeCall():Fonction de décodage.

Ensuite, détectezmulticallLorsqu'elle est appelée, l'opération de décodage peut être lancée. Le premier décodagemulticallParamètres de la méthode :deadlineetdatadeadlineIl est plus facile de comprendre un horodatage.dataIl s’agit d’une autre donnée d’appel codée, nous devons donc continuer à l’utiliser.decodeCall()Décodage de fonction.

Exemple d'implémentation complète :

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

Créez un vrai disque pour exécuter le test :

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

capture d'écran:

img

Vous pouvez voir que le hachage de transaction est0x5288a7bd6e0f57162ca763df722de73793e542734d7d2b7af5755664e2e67910Pour cette transaction, les données d'entrée contiennent un appelmulticallAppel de méthode. Le sens de la transaction est : 0x851b594033d57c98af753bcb3a7d0237a615de32 -> 0x68b3465833fb72a70ecdf485e0e4c7bd8665fc45.0x68b3465833fb72a70ecdf485e0e4c7bd8665fc45C'est-à-dire l'adresse du contrat de routage d'Uniswap.

img

AnalysémulticallLe package appelle le contratexactInputSingleetunwrapWETH9méthodes et les paramètres spécifiques de ces méthodes.

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

Les étudiants intéressés peuvent modifier et développer cet exemple pour surveiller davantage de transactions et analyser ces opérations en chaîne.

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