[TOC] Je vous en prie.
Le tutoriel EtherEaseWithFMZ
Commencez avec le développement web3 basé sur Ethereum en utilisant FMZ facilement
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.
Plateforme de négociation quantitative FMZ (FMZ.COMIl permet d'accéder aux échanges décentralisés (DEX), d'obtenir des données sur la chaîne, d'envoyer des transactions et d'autres fonctions.
Dans ce tutoriel, les exemples sont écrits enJavaScript
L'environnement de test utilise à la foisRéseau principal EthereumetRéseau de test de Goerli. Et vous pouvez également voir les interfaces API et les descriptions connexes, des exemples de code utilisés dans le tutoriel dans la documentation API de la plateforme FMZ
Avant d'apprendre à utiliser la plateforme de trading FMZ Quant, nous devons nous familiariser avec quelques concepts de base:
Après s'être inscrit et connecté sur le site officiel de la plateforme de négociation quantitative FMZ (https://www.fmz.comLe programme de logiciel de docker 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 de FMZ, la plate-forme FMZ communique avec le docker et démarre une instance de programme sur celui-ci.
Si vous souhaitez exécuter une instance de programme, vous devez déployer un docker. Le déploiement du docker est également très simple, et il existe des tutoriels de déploiement sur la plateforme. Vous pouvez également utiliser le
Vous pouvez déployer et exécuter le programme docker sur des serveurs, des ordinateurs personnels et d'autres appareils, tant que le réseau est normal (besoin d'avoir accès à la cible correspondante, telle qu'une certaine interface d'échange, une adresse de nœud, etc.).
robot
. Configurez l'adresse de communication docker, qui est unique pour chaque compte FMZ, après vous être connecté à FMZ, vous pouvez voir votre propre adresse àhttps://www.fmz.com/m/add-node
page (c'est-à-dire./robot -s node.fmz.com/xxxxx
cette chaîne d'adresses, où le contenu àxxxxx
La position est différente pour chaque compte FMZ). Enfin, vous devez entrer le mot de passe de votre compte FMZ. Après avoir configuré ces paramètres, exécutez le programme docker.Utilisez la fonction de déploiement en un clic de la plateforme FMZ
Ajoutez une page d'accueil sur la plateforme FMZ, adresse:https://www.fmz.com/m/add-node
FMZ Quant Trading Platform fournit un outil de débogage gratuit qui prend en chargeJavaScript
, TypeScript
, et la page est:https://www.fmz.com/m/debug. Parce que la création d'instances à exécuter est facturée. Pendant la période d'apprentissage initiale, vous pouvez utiliser cet outil de débogage pour les tests et l'apprentissage. À l'exception de la limite maximale de temps d'exécution de 3 minutes, il n'y a aucune différence entre l'utilisation de l'outil de débogage et la création d'une instance à exécuter.
Lorsque vous utilisezTypeScript
Le langage, vous devez écrire// @ts-check
sur la première ligne de code à passer àTypeScript
mode; s'il n'est pas commuté, le mode par défaut estJavaScript
language.
Sur FMZ,
Dans l'état de connexion de la plateforme FMZ, àhttps://www.fmz.com/m/add-platform
page, vous pouvez configurer des informations d'échange, où l'échange est un concept général.
SélectionnezWeb3
, configurer l'adresse du nœud RPC, configurer la clé privée, vous pouvez cliquer sur le coin inférieur droit
Les nœuds peuvent être des nœuds auto-construits ou des nœuds fournis par des fournisseurs de services de nœuds.Infure. Après l'enregistrement, vous pouvez voir l'adresse du nœud de votre propre compte. Le mainnet et le testnet sont tous deux disponibles, ce qui est très pratique.Rpc Address
L'étiquette peut être nommée par vous-même pour distinguer les objets d'échange configurés.
Dans la photo,https://mainnet.infura.io/v3/xxxxxxxxxxxxx
est l'adresse privée du nœud RPC du réseau principal Infura ETH.
Après avoir déployé le programme docker et configuré l'objet d'échange, vous pouvez utiliserFMZ.COM
Pour différents langages et outils, il existe des moyens d'accéder au web3, comme indiqué sur l'image:
Sur FMZ, les appels à la méthode RPC sont également encapsulés, et ces fonctions sont encapsulées dans la fonction FMZ APIexchange.IO
La méthode d'appel estexchange.IO("api", "eth", ...)
. Le premier paramètre est fixé à"api"
, le deuxième paramètre est fixé à"eth"
, et d'autres paramètres dépendent de la méthode RPC spécifique appelée.
Pour les informations de sortie, nous utiliserons leLog
La fonction de la plateforme FMZLog
fonction peut accepter plusieurs paramètres et ensuite les produire dans la zone de journal de la page
Leeth_getBalance
la méthode d'Ethereum est utilisée pour interroger le solde ETH d'une adresse sur Ethereum, et cette méthode nécessite deux paramètres.
Vitalik Buterin
l'adresse du portefeuille ETH, l'adresse connue est:0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045
.function main() {
let ethBalance = exchange.IO("api", "eth", "eth_getBalance", "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", "latest")
Log("ethBalance:", ethBalance)
}
Déjà déployé le docker (sur l'image: linux/amd64...) et configuré l'objet d'échange (sur l'image: test Web3), code de test dans le débogage outil:
Cliquez sur le bouton
Le bilan est le suivant: 0x117296558f185bbc4c6
Lelog
fonction imprime leethBalance
la valeur de la variable est:0x117296558f185bbc4c6
, qui est un type de chaîne.la valeur hexadécimale du solde ETHdanswei
unités, avec1e18 wei
étant égal à 1ETH
Par conséquent, il doit être converti pour devenir un solde décimal ETH lisible.
ConversionethBalance
dans des données lisibles:
function main() {
let ethBalance = exchange.IO("api", "eth", "eth_getBalance", "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", "latest")
Log("ethBalance:", ethBalance)
// Converting ethBalance into readable data
let vitalikEthBalance = parseInt(ethBalance.substring(2), 16) / 1e18
Log("vitalikEthBalance:", vitalikEthBalance)
}
Recherche en courshttps://etherscan.io/
:
Cependant, en raison du problème de précision du langage lui-même, il y aura des écarts dans cette façon de traitement.
Ajustez le code à nouveau:
function main() {
let ethBalance = exchange.IO("api", "eth", "eth_getBalance", "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", "latest")
// The precision unit of ETH is 1e18
let ethDecimal = 18
Log("vitalikEthBalance:", Number((BigDecimal(BigInt(ethBalance)) / BigDecimal(Math.pow(10, ethDecimal))).toString()))
}
Le bilan est de 5149,6244846875215.
eth_chainId
etnet_version
Ces deux fonctions renvoient l'id de la blockchain à laquelle le nœud RPC actuel est connecté, la différence étant quenet_version
renvoie un Id décimal eteth_chainId
renvoie un ID hexadécimal.
Nom du réseau correspondant à chaîneId
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
Testez avec le réseau de test Ethereum configurégoerli
nœud:
function main() {
let netVersionId = exchange.IO("api", "eth", "net_version")
let ethChainId = exchange.IO("api", "eth", "eth_chainId")
Log("netVersionId:", netVersionId)
Log("ethChainId:", ethChainId, " , conversion:", parseInt(ethChainId.substring(2), 16))
}
Appelez leeth_gasPrice
méthode pour interroger le courantgas price
sur la chaîne.
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, " , conversion:", toAmount(gasPrice, 0))
}
Ici, nous écrivons une fonction pour convertir la chaîne hexadécimale en une valeur numérique lisible:toAmount
En outre, il convient de noter que l'unité degasPrice
estwei
, donc passer la valeur 0 au paramètre réel correspondant au paramètre formeldecimals
.
"eth_blockNumber
est utilisé pour interroger la hauteur du bloc.
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écutez l' outil de débogage:
Recherche en courshttps://etherscan.io/
:
Informations sur le bloc de requête.
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)
// Due to the excessive content of Log output, it will be truncated automatically, so traverse each field of the returned block information and print them one by one
for (let key in blockMsg) {
Log("key:", key, ", val:", blockMsg[key])
}
}
L'exécution dans l'outil de débogage peut obtenir les informations suivantes:
Beaucoup d'applications de contrats intelligents fonctionnent sur Ethereum etENS
est l'un d'entre eux.ENS
, ou Ethereum Name Service, est un service décentralisé de résolution de noms de domaine basé sur la blockchain Ethereum.
Vous souvenez-vous de l'exemple du tutoriel où nous avons vérifié le solde du portefeuille du fondateur d'Ethereum Vitalik Buterin?0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045
- Alors comment savons-nous l'adresse?ENS
un contrat intelligent avec un nom intuitifvitalik.eth
.
Le contenu suivant dans ce chapitre utilise l'environnement Ethereum mainnet, selon leENS
la documentation,Hashing Names
sont nécessaires pour interroger les noms de domaine Ethereum. Utilisez le code suivant pour traitervitalik.eth
.
function nameHash(name) {
if (name == "") {
return "0000000000000000000000000000000000000000000000000000000000000000"
} else {
let arr = name.split(".")
let label = arr[0]
arr.shift()
let remainder = arr.join(".")
return Encode("sha3.keccak256", "hex", "hex", nameHash(remainder) + Encode("sha3.keccak256", "raw", "hex", label))
}
}
Dans l'exemple de code ci-dessus, nous avons vu une autre fonction inconnueEncode
Cette fonction est une fonction API de la plateforme FMZ et est spécifiquement utilisée pour encoder des opérations sur la plateforme FMZ.
Encode(algo, inputFormat, outputFormat, data, keyFormat, key string)
Conformément à la description contenue dans le document ENS, utilisezsha3.keccak256
algorithme pour traiter les données.
Appelez lenameHash
fonction, par exemple:Log(nameHash("vitalik.eth"))
, vous pouvez obtenir:ee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835
, et vous devez ajouter le préfixe 0xee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835
est utilisé comme paramètre duresolver
méthode dans le contrat intelligent ENS.
let ensNode = "0x" + nameHash("vitalik.eth") // Prepare the parameters ensNode for calling the resolver method
Selon la documentation ENS, l'adresse du contrat pour les applications de contrats intelligents ENS est la suivante:0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e
Avant d' appeler leresolver
La méthode de l'accord intelligent, nous devons également préparer laABI
du contrat.
En apprenant cela, vous vous demandez peutêtre:ABI
d'un contrat intelligent?
ABI, or Application Binary Interface, is the interface standard for smart contracts to communicate with the external world.
The ABI of a smart contract defines the contract's function interfaces, parameter types, return values, and other information, as well as specifications for calling the contract and passing parameters.
The ABI of a smart contract is usually stored in JSON format and contains the following information:
Contract function interfaces: function names, parameter lists, return values, etc.
Function parameter types: such as uint256, bool, string etc.
Encoding methods for input and output parameters of functions: Smart contracts use an encoding method called Solidity ABI to encode input and output parameters of functions so that they can interact with Ethereum network.
In Ethereum network ,the ABI of a smart contract is used to call its functions. When you need to call a contract function, you need to provide the name of the function, its parameters, and bytecode encoded according to ABI encoding method.
Ethereum nodes will package this information into transactions and send them out on Ethereum network for execution.
In Solidity language,the keyword 'interface' can be used define ABIs for smart contracts. Ethereum development tools like Remix IDE ,Truffle also provide editing & generation tools making it easier developers create & use ABIs.
Extraire leresolver
Vous pouvez consulter l'ABI du contrat surhttps://etherscan.io/
ou obtenir l'ABI par d'autres voies (par exemple, la documentation pertinente du projet).
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 allons apprendre une nouvelle méthode d'invocation sur la plateforme FMZ,exchange.IO("abi", address, abiContent)
, qui est utilisé pour enregistrer l'ABI.address
Paramètre est l'adresse du contrat intelligent et leabiContent
le paramètre est le contrat intelligent correspondant ABI (chaîne).
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 is the address of the ENS smart contract deployed on the Ethereum mainnet
Ensuite, vous pouvez appelerresolver
La méthode du contrat intelligent ENS, qui renvoie l'adresse duENS: Public Resolver
contract.
let resolverAddress = exchange.IO("api", "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e", "resolver", ensNode)
Utilisez leENS: Public Resolver
Les contratsaddr
Pour obtenir l'adresse du portefeuille de Vitalik Buterin.ENS: Public Resolver
Les informations ABI pour ce contrat intelligent peuvent toujours être obtenues à partir dehttps://etherscan.io/
.
let abiENSPublicResolver = `[{"inputs":[{"internalType":"contract ENS","name":"_ens","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"contentType","type":"uint256"}],"name":"ABIChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"address","name":"a","type":"address"}],"name":"AddrChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"coinType","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"newAddress","type":"bytes"}],"name":"AddressChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"bool","name":"isAuthorised","type":"bool"}],"name":"AuthorisationChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"hash","type":"bytes"}],"name":"ContenthashChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"name","type":"bytes"},{"indexed":false,"internalType":"uint16","name":"resource","type":"uint16"},{"indexed":false,"internalType":"bytes","name":"record","type":"bytes"}],"name":"DNSRecordChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"name","type":"bytes"},{"indexed":false,"internalType":"uint16","name":"resource","type":"uint16"}],"name":"DNSRecordDeleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"DNSZoneCleared","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":true,"internalType":"bytes4","name":"interfaceID","type":"bytes4"},{"indexed":false,"internalType":"address","name":"implementer","type":"address"}],"name":"InterfaceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"string","name":"name","type":"string"}],"name":"NameChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"x","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"y","type":"bytes32"}],"name":"PubkeyChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":true,"internalType":"string","name":"indexedKey","type":"string"},{"indexed":false,"internalType":"string","name":"key","type":"string"}],"name":"TextChanged","type":"event"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"uint256","name":"contentTypes","type":"uint256"}],"name":"ABI","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"addr","outputs":[{"internalType":"address payable","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"uint256","name":"coinType","type":"uint256"}],"name":"addr","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"authorisations","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"clearDNSZone","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"contenthash","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes32","name":"name","type":"bytes32"},{"internalType":"uint16","name":"resource","type":"uint16"}],"name":"dnsRecord","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes32","name":"name","type":"bytes32"}],"name":"hasDNSRecords","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes4","name":"interfaceID","type":"bytes4"}],"name":"interfaceImplementer","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"pubkey","outputs":[{"internalType":"bytes32","name":"x","type":"bytes32"},{"internalType":"bytes32","name":"y","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"uint256","name":"contentType","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"setABI","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"uint256","name":"coinType","type":"uint256"},{"internalType":"bytes","name":"a","type":"bytes"}],"name":"setAddr","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"address","name":"a","type":"address"}],"name":"setAddr","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"address","name":"target","type":"address"},{"internalType":"bool","name":"isAuthorised","type":"bool"}],"name":"setAuthorisation","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes","name":"hash","type":"bytes"}],"name":"setContenthash","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"setDNSRecords","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes4","name":"interfaceID","type":"bytes4"},{"internalType":"address","name":"implementer","type":"address"}],"name":"setInterface","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"string","name":"name","type":"string"}],"name":"setName","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes32","name":"x","type":"bytes32"},{"internalType":"bytes32","name":"y","type":"bytes32"}],"name":"setPubkey","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"string","name":"key","type":"string"},{"internalType":"string","name":"value","type":"string"}],"name":"setText","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes4","name":"interfaceID","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"string","name":"key","type":"string"}],"name":"text","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"}]`
exchange.IO("abi", resolverAddress, abiENSPublicResolver)
Enfin, appelez leENS: Public Resolver
Les contratsaddr
méthode, le paramètre étant toujoursensNode
.
let vitalikAddress = exchange.IO("api", resolverAddress, "addr", ensNode)
Log("vitalikAddress:", vitalikAddress)
Sortie de la fonction log:
vitalikAddress: 0xd8da6bf26964af9d7eed9e03e53415d37aa96045
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() {
// Calculate the name
let ensNode = "0x" + nameHash("vitalik.eth")
// Register ENS contract
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)
// Register ENS Public Resolver contract
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)
}
Dans les chapitres précédents du cours, nous avons appris comment configurer les clés privées. Comment connaissons-nous l'adresse de portefeuille correspondant à cette clé privée pour l'objet d'échange configuré?exchange.IO("address")
fonction pour obtenir l'adresse de portefeuille correspondant à la clé privée configurée.
Le contenu suivant dans ce chapitre utilise l'environnement Goerli testnet, donc le nœud que j'utilise est:https://goerli.infura.io/v3/*******
, et Infura attribue différentes adresses de nœuds pour chaque utilisateur enregistré.*******
cache un contenu spécifique.
function main() {
let walletAddress = exchange.IO("address")
Log("Testnet goerli wallet address:", walletAddress)
}
Après avoir connu votre adresse de portefeuille, vous pouvez utiliser la méthode RPC d'Ethereumeth_getTransactionCount
Dans Ethereum, ce nombre est très commun, et c'est en fait le nombre de transactions de l'adresse du portefeuille.nonce
Nonce est un nombre unique utilisé pour s'assurer que chaque transaction est unique. C'est un nombre croissant, et il augmentera automatiquement à 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 vous assurer que la transaction est unique et dans le bon ordre.
Voici lePendingNonceAt
fonction dans la bibliothèque Ethereum du langage Go appelle en fait leeth_getTransactionCount
Dans les cours précédents, nous avons également appris comment appeler les méthodes RPC.exchange.IO("api", "eth", ...)
fonctionne à nouveau.
function toAmount(s, decimals) {
return Number((BigDecimal(BigInt(s)) / BigDecimal(Math.pow(10, decimals))).toString())
}
function main() {
let walletAddress = exchange.IO("address")
Log("Testnet goerli wallet address:", 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: string = exchange.IO("api", "eth", "eth_getTransactionCount", walletAddress, "pending")
Log("wallet address:", walletAddress, "current nonce:", nonce, ", convert to decimal:", toAmount(nonce, 0))
}
Avant d'expliquer l'opération de transfert, comprenons brièvement certains concepts. Lors du transfert sur Ethereum, une certaine quantité de jetons ETH sera consommée (en tant que frais de gaz).
prix du gaz
Cependant, les frais de gaz sur le réseau Ethereum fluctuent toujours en fonction de la demande du marché et des frais que les utilisateurs sont prêts à payer, donc écrire un tarif fixe de gaz dans le code n'est parfois pas un choix idéal.eth_gasPrice
La méthode que nous avons apprise précédemment, qui peut obtenir le prix moyen de l'essence.
Limite de gaz
Un transfert standard d'éther a une limite de gaz de 21 000 unités.
Après avoir compris les concepts denonce
, gasPrice
, etgasLimit
, vous pouvez tester le transfert. FMZ fournit une fonction de transfert très simple et facile à utiliser.
exchange.IO("api", "eth", "send", toAddress, toAmount)
Lorsqu'il est utilisé pour les transferts, le troisième paramètre deexchange.IO
est fixé comme toAddress
le paramètre est l'adresse qui reçoit l'ETH pendant le transfert, ettoAmount
est le montant de l'ETH transféré.
Les paramètresnonce
, gasPrice
, etgasLimit
peuvent toutes utiliser les valeurs par défaut du système obtenues automatiquement sur FMZ.
exchange.IO("api", "eth", "send", toAddress, toAmount, {gasPrice: 5000000000, gasLimit: 21000, nonce: 100})
Ensuite, nous allons transférer une certaine quantité d'ETH à une adresse spécifique sur le réseau de test de Goerli:
function toInnerAmount(s, decimals) {
return (BigDecimal(s)*BigDecimal(Math.pow(10, decimals))).toFixed(0)
}
function main() {
let walletAddress = exchange.IO("address")
Log("Testnet goerli wallet address:", walletAddress)
let ret = exchange.IO("api", "eth", "send", "0x4D75a08E870674E68cAE611f329A27f446A66813", toInnerAmount(0.01, 18))
return ret // return Transaction Hash : 0xa6f9f51b00d8ae850b0f204380b59da98f4bbce34b813577d3d948f61de4734e
}
Parce que l'unité du montant du transfert Ethereum estwei
, une fonction personnaliséetoInnerAmount
doit être utilisé pour traiter la valeur danswei
units.
Hash de transaction de requête:0xa6f9f51b00d8ae850b0f204380b59da98f4bbce34b813577d3d948f61de4734e
surhttps://etherscan.io/
.
Vous pouvez également écrire du code pour demander le transfert de hachage0xa6f9f51b00d8ae850b0f204380b59da98f4bbce34b813577d3d948f61de4734e
, en utilisant leeth_getTransactionReceipt
méthode pour les requêtes.
function main() {
let transHash = "0xa6f9f51b00d8ae850b0f204380b59da98f4bbce34b813577d3d948f61de4734e"
let info = exchange.IO("api", "eth", "eth_getTransactionReceipt", transHash)
return info
}
Résultat de requête:
{
"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 correspondant à chaque champ:
blockHash - The hash value of the block where the transaction is located.
blockNumber - The block number of the block where the transaction is located, encoded in hexadecimal.
contractAddress - If it's a contract creation, the address of the contract; otherwise null.
cumulativeGasUsed - The total gas used when executing this transaction in the block.
effectiveGasPrice - Total base fee plus tip per unit of gas.
from - Sender's address.
gasUsed - Gas used by this specific transaction.
logs - Array of log objects generated by this transaction.
address - Address that generated this log.
topics - Data array with 0 to 4 indexed log parameters, each with 32 bytes. In Solidity, first topic is event signature hash (e.g., Deposit(address,bytes32,uint256)), unless you declare an event using anonymous specifier.
data - Non-indexed parameters for logs with length of 32 bytes.
blockNumber - The block number of the block where this log is located.
transactionHash - Transaction hash at time when log was created. Null if pending state.
transactionIndex - Index position during creation. Null if pending state.
blockHash - The hash value for containing block.
logIndex - Hexadecimal-encoded integer index position within containing block. Null if pending state.
removed - True if deleted due to chain reorganization; false for valid logs.
logsBloom - Bloom filter for retrieving related logs.
status - Hexadecimal-encoded value either being '1' (success) or '0' (failure).
to - Receiving party's address; null for contract creation transactions.
transactionHash - The hash value associated with given transaction.
transactionIndex - Hexadecimal-encoded index position within its respective containing-block.
type - Type value.
Dans le chapitre sur Read
méthodes, et appeler ces méthodes ne nécessite pasgas
Dans ce chapitre, nous allons appeler certainsWrite
méthodes de contrats intelligents sur Ethereum et de payer pourgas
Ces opérations seront vérifiées par chaque nœud et mineur de l'ensemble du réseau et changeront l'état de la blockchain.
Pour le contrat ERC20 (contrat ERC20 token), la plateforme FMZ répertorie l'ABI du contrat ERC20 ABI comme un ABI commun intégré directement dans le système, éliminant l'étape d'enregistrement de l'ABI.
Pour mieux comprendre ABI, vous pouvez le vérifier avant de l'utiliser.
[{"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":"tran