Les ressources ont été chargées... Je charge...

Introduction facile au développement web3 basé sur Ethereum avec FMZ

Auteur:L'inventeur de la quantification - un petit rêve, Créé: 2023-03-28 13:32:48, Mis à jour: 2024-11-11 22:28:24

nom: token,type:address],name:approveZeroThenMax,outputs:[],stateMutability:payable,type:bytefunction,{inputs:[],stateMutability:payable,type:function,{inputs:[internalType:payable,type:function,inputs:[internalType:address,name:token,type:address],name:approveZeroThenMaxMinusOne,outputs:[],stateMutability:payable,type:bytefunction,{inputs:[],stateMutability:[],[stateMutability:payable,type:type:type,type:type,type,type Var abiPool = [inputs:[],stateMutability:nonpayable,type:constructor},{anonymous:true,internalType:int24,inputs:[indexed:true,internalType:address,name:owner,type:address},{indexed:true,internalType:int24,stateMutability:nonpayable,type:int24},{anonymous:true,addalType:int24,name:addaddaddaddaddUpperType:address,name:owner:type:type:add,type:addadd,type:add,type:add,type:add,type:,

Le contrat V3FactoryAdresse = 0x1F98431c8aD98523631AE4a59f267346ea31F984 le contrat V3SwapRouterV2Address = 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45

fonction toAmount ((s, décimales) { Retourner le nombre (s) (s) (s) (s) (s) (s) (s) (s) Je ne sais pas.

fonction àInnerAmount ((n, décimales) { retour (BigDecimal(n) * BigDecimal(Math.pow(10, décimales))).à Fixé(0) Je ne sais pas.

fonction main (() { // ABI pour enregistrer le contrat d'usine Uniswapexchange.IO("Abi", contratV3FactoryAdresse, abiFactory) Il s'agit d'un projet qui a été réalisé par l'entreprise.

// 注册Uniswap路由合约的ABI
exchange.IO("abi", contractV3SwapRouterV2Address, abiRoute)

// 获取交易对的池地址
var tokenIn = {name : "1INCH", address: "0x111111111117dC0aa78b770fA6A738034120C302", decimals: exchange.IO("api", "0x111111111117dC0aa78b770fA6A738034120C302", "decimals")}
var tokenOut = {name : "WETH", address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", decimals: exchange.IO("api", "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "decimals")}
var poolAddress = exchange.IO("api", contractV3FactoryAddress, "getPool", tokenIn.address, tokenOut.address, 10000)

// 注册池合约ABI
exchange.IO("abi", poolAddress, abiPool)

var slot0 = exchange.IO("api", poolAddress, "slot0")
Log("slot0:", slot0)

}


获取到兑换池的价格信息,打印出代码中```slot0```变量:

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

Les principaux données sur les prix sont enregistrées sursqrtPriceX96Les champs, qui doivent être calculés en fonction des données de précision des jetons de la palette de change, ainsi que le prix actuel du pool de change, sont calculés en fonction de la valeur de la palette de change.UniswapDans la description de la documentation, nous avons mis en œuvre une fonction pour calculer:

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

On peut utiliser cette fonction pour calculer la combinaison de jetons comme1INCH/WETHLe prix actuel de la billetterie est de 10000 paires de billets.

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

Imprimer une variablepriceAffichage:price: 0.000203Il y a une différence entre le 1 INCH et le 0.000203 WETH.

Uniswap V3 est une bibliothèque de transactions

Les inventeurs d'une plateforme de trading quantitatif ont dévoilé un paquet completUniswapLes modèlesLes fonctionnalités de conversion, d'obtention de prix, de demande de solde de portefeuille, etc., ont été mises en œuvre, sans avoir à réécrire le code en fonction du contenu de l'exposé ci-dessus, vous pouvez lire ce modèle pour apprendre plus en profondeur le code source et développer des applications Web3. Il y a beaucoup de détails de conception à apprendre dans cette bibliothèque de modèles:

  • Obtenir automatiquement des informations sur les jetons Si vous utilisez un exemple de modèle, vous pouvez utiliser un exemple de modèle.AutoFetchTokensSi le paramètre est "true", le programme de modèle accède automatiquement.https://tokens.coingecko.com/uniswap/all.jsonLes liens, l'obtention et le traitement automatique de toutes les informations sur les jetons. Cela permet d'éviter d'ajouter manuellement un jeton dans le code de la stratégie.addToken(name, address)Je ne peux pas vous dire ce que je fais.

         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
                      }
                  }
              })
          }  
    
  • Adaptez les adresses de contrats selon les paramètres de la chaîne Le modèle est configuréChainTypeParamètres permettant de changer plusieurs chaînes:

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

    Le code de sélection:

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

    Les méthodes RPC pour appeler Ethereumeth_chainIdEnquête en courschainIdJe ne sais pas.chainIdIl y a aussi des sites Web qui sont utilisés pour créer des liens vers des sites Web.UniswapIl y a une série d'adresses de contrats.USDTLes contrats peuvent avoir des adresses différentes sur différentes chaînes.

    Le code de sélection:

          // 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")
          }
    
  • Utiliser la bibliothèque de classes de transactions Uniswap V3

    Dans ce modèle$.testUniswap()La fonction est une fonction qui teste les fonctions de modèle et dont le code donne des exemples d'appels pour utiliser le modèle:

    $.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 politique fait référence à la bibliothèque de classes de transactions Uniswap V3 (" Comment faire référence à la bibliothèque de classes de modèles peut être consulté dans la documentation de la plate-forme FMZ "), une fonction peut être appelée dans cette bibliothèque de classes de modèles.

    Créer un groupe appeléexUne variable appelée "Uniswap V3 Transaction Library" est un modèle d'interface enveloppée.$.NewUniswapV3()Créer un objet pour attribuer une valeur àex

    let ex = $.NewUniswapV3()
    

    UtilisationexFonction membre de l'objetaddToken()Il a ajouté des informations sur les jetons.

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

    Si vous voulez obtenir et imprimer le prix d'un pool de change pour une paire de transactions, vous pouvez utiliserexFonction membre de l'objetgetPrice()Il y a aussi une autre version de ce mot:

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

    Si vous voulez effectuer des opérations de conversion, vous pouvez utiliserexFonction membre de l'objetswapToken()Pour effectuer la conversion:

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

Les réclamations

Dans ce chapitre, nous apprendrons à lire les événements publiés par les contrats intelligents à l'aide de la plate-forme de négociation quantitative des inventeurs, les événements publiés par les contrats intelligents étant stockés dans les journaux de la machine virtuelle Ethereum.

Le code de l'application

Les événements de demande de déblocage de contrats intelligents nécessitent l'utilisation de la méthode RPC d'Ethereumeth_getLogsPour obtenir des données de journaux sur la chaîne, nous avons expliqué dans un cours précédent comment appeler les nœuds RPC d'Ethereum. Par exemple, nous obtenonsWETHL'événement contracté peut être codé en utilisant FMZ.Outils de débogageTest, l'objet d'échange configuré RPC nœud est le nœud de l'Ethereum, qui est appeléeth_getLogsNous avons donné trois paramètres à la méthode.fromBlocktoBlockaddressNous utilisons les paramètres fromBlock et toBlock pour limiter les requêtes à l'intérieur d'un bloc:

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   
}

Pour accéder aux données des logs, nous avons omis une partie de ce contenu en raison de la grande quantité de données:

[{
	"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 que les données de logs contiennent toutes sortes d'événements, si nous ne nous intéressons qu'àTransferLes événements ont besoin de ces données.TransferL'incident a été filtré.

Rechercher les journaux

Les journaux Ethereum sont divisés en deux parties:topics; 2, donnéesdata

  • Le sujettopicsPoureth_getLogsLes résultats de l'exécution du code des tests de chapitre sont des exemples.topicsLes données des champs sont:

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

    Celle-ci esttopicsLa valeur du champ (theme) est une structure arithmétique utilisée pour décrire un événement. Il est spécifié que sa longueur ne peut pas dépasser 4. Le premier élément est la valeur de hash de signature de l'événement. Nous utilisons une plateforme de trading quantifié par les inventeurs.EncodeLa fonction peut calculer cette valeur de hachage de signature en utilisant le code suivant:

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

    CalculerTransfer(address,address,uint256)Je ne sais paskeccak256La valeur de hachage (code hex) est0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef

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

    • Envoyer une adressefrom
    • Adresse de réceptionto
  • Les donnéesdata

    dataLes données des champs sont:

    "data": "0x0000000000000000000000000000000000000000000000000164f2434262e1cc",
    

    Certains paramètres de l'événement (paramètres dans le code Solidity du contrat intelligent qui ne sont pas indexés) sont stockés dansdataIl y a aussi une section consacrée à l'éducation.

    Pour analyser ces données0x0000000000000000000000000000000000000000000000000164f2434262e1cc

    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
    }
    

    Il y a aussi une autre version de la même histoire, qui a été publiée par le site officiel de l'organisation.dataLes données correspondent au montant des transferts.


Après avoir pratiqué ce qui précède, nous sommes prêts. Nous pouvons commencer à chercher les journaux:

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

Danshttps://etherscan.io/Les requêtes:

img

Résultats des tests de code dans l'outil de débogage FMZ:

img

Il est également possible d'analyser les requêtes en fonction des besoins.fromtoLes données des champs, par exemple:

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

Les résultats:

Adresse: 0x12b791bb27b3a4ee958b5a435fea7d49ec076e9c

Les accords de surveillance

En raisonOutils de débogageLe code ne peut être testé que pendant une courte période, et le contenu n'est publié qu'après l'exécution du code, et ne peut pas être affiché en temps réel.

Ici, nous utilisons le réseau Ethereum pour écouter.USDTCe contrat de monnaieTransfer(address,address,uint256)L'événement, basé sur ce que nous avons appris en classe précédente, nous avons conçu un exemple d'une écoute continue d'un événement de contrat intelligent:

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 = {

Plus de