[TOC] ¿Qué quieres decir?
Tutorial de EtherEaseWithFMZ
Comience con el desarrollo web3 basado en Ethereum usando FMZ fácilmente
Ethereum es una plataforma de contratos inteligentes basada en la tecnología blockchain, que proporciona una forma descentralizada de escribir e implementar contratos inteligentes.
Plataforma de negociación cuantitativa FMZ (FMZ.COMLa plataforma proporciona una API fácil de usar, que permite a los desarrolladores interactuar más fácilmente con la cadena de bloques Ethereum y su ecosistema.
En este tutorial, los ejemplos están escritos enJavaScript
En el contexto de la evaluación de la calidad de la información, el entorno de prueba utilizaLa red principal de EthereumyRed de prueba de Goerli. Y también puede ver las interfaces API y descripciones relacionadas, ejemplos de código utilizados en el tutorial en la documentación API de la plataforma FMZ
Antes de aprender a usar la plataforma de comercio de FMZ Quant, necesitamos familiarizarnos con algunos conceptos básicos:
Después de registrarse y iniciar sesión en el sitio web oficial de la Plataforma de Comercio Cuántico de FMZ (https://www.fmz.comEl sitio web de FMZ es el extremo de administración de todo el sistema, y los programas escritos por el usuario se ejecutan en el docker en realidad. El programa de software de docker se puede implementar en varios dispositivos, como servidores, computadoras, etc. Cuando un usuario escribe un programa y crea una instancia en ejecución en el sitio web de FMZ, la plataforma FMZ se comunicará con el docker y comenzará una instancia de programa en él.
Si desea ejecutar una instancia de programa, debe implementar un docker. La implementación del docker también es muy simple, y hay tutoriales de implementación en la plataforma. También puede usar el
Puede implementar y ejecutar el programa docker en servidores, computadoras personales y otros dispositivos, siempre que la red sea normal (necesita poder acceder al objetivo correspondiente, como una determinada interfaz de intercambio, dirección de nodo, etc.).
robot
. Configure la dirección de comunicación docker, que es única para cada cuenta FMZ, después de iniciar sesión en FMZ, puede ver su propia dirección enhttps://www.fmz.com/m/add-node
página (es decir,./robot -s node.fmz.com/xxxxx
esta cadena de direcciones, donde el contenido enxxxxx
la posición es diferente para cada cuenta FMZ). Finalmente, debe introducir la contraseña de su cuenta FMZ. Después de configurar estas configuraciones, ejecute el programa docker.Utilice la función
Añadir una página de docker en la plataforma FMZ, dirección:https://www.fmz.com/m/add-node
FMZ Quant Trading Platform proporciona una herramienta de depuración gratuita que admiteJavaScript
, TypeScript
, y la página es:https://www.fmz.com/m/debug. Porque la creación de instancias para ejecutar se factura. Durante el período de aprendizaje inicial, puede usar esta herramienta de depuración para probar y aprender. Excepto por el límite máximo de tiempo de ejecución de 3 minutos, no hay diferencia entre usar la herramienta de depuración y crear una instancia para ejecutar.
Cuando se utiliza elTypeScript
lenguaje, usted necesita escribir// @ts-check
en la primera línea de código para cambiar aTypeScript
modo; si no está activado, el valor predeterminado esJavaScript
language.
En FMZ,
En el estado de inicio de sesión de la plataforma FMZ,https://www.fmz.com/m/add-platform
página, se puede configurar información de intercambio, donde el intercambio es un concepto general.
SeleccionarWeb3
, configure la dirección del nodo RPC, configure la clave privada, puede hacer clic en la esquina inferior derecha
Los nodos pueden ser nodos autoconstruidos o nodos proporcionados por proveedores de servicios de nodos.Infura. Después de registrarse, puede ver la dirección de nodo de su propia cuenta. Tanto mainnet como testnet están disponibles, lo cual es bastante conveniente. Configure esta dirección de nodo en elRpc Address
La etiqueta puede ser nombrada por usted mismo para distinguir entre los objetos de intercambio configurados.
En la foto,https://mainnet.infura.io/v3/xxxxxxxxxxxxx
es la dirección privada del nodo RPC de la red principal de Infura ETH.
Después de desplegar el programa docker y configurar el objeto de intercambio, se puede utilizarFMZ.COM
Para varios lenguajes y herramientas, hay formas de acceder a web3, como se muestra en la imagen:
En FMZ, las llamadas al método RPC también están encapsuladas, y estas funciones están encapsuladas en la función FMZ APIexchange.IO
El método de llamada esexchange.IO("api", "eth", ...)
. El primer parámetro está fijado a"api"
, el segundo parámetro se fija en"eth"
, y otros parámetros dependen del método RPC específico que se esté llamando.
Para la información de salida, utilizaremos elLog
La función de la plataforma FMZ.Log
La función puede aceptar múltiples parámetros y luego emitirlos en el área de registro de la página
Eleth_getBalance
El método de Ethereum se utiliza para consultar el saldo de ETH de una dirección en Ethereum, y este método requiere dos parámetros.
Vitalik Buterin
la dirección de la billetera de ETH, la dirección conocida es:0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045
.function main() {
let ethBalance = exchange.IO("api", "eth", "eth_getBalance", "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", "latest")
Log("ethBalance:", ethBalance)
}
Ya desplegado el docker (en la imagen: linux/amd64...) y configurado el objeto de intercambio (en la imagen: prueba Web3), prueba de código en la herramienta de depuración:
Haga clic en el botón
EthBalance: 0x117296558f185bbc4c6
Ellog
La función imprime elethBalance
valor de la variable como0x117296558f185bbc4c6
, que es un tipo de cadena.el valor hexadecimal del saldo del ETHEn elwei
unidades, con1e18 wei
siendo igual a 1ETH
Por lo tanto, necesita ser convertido para convertirse en un saldo decimal de ETH legible.
ConversiónethBalance
en datos legibles:
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)
}
Busca enhttps://etherscan.io/
:
Sin embargo, debido al problema de precisión del lenguaje en sí, habrá desviaciones en esta forma de procesamiento.
Ajusta el código otra vez:
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()))
}
El saldo de la vida es de 5149,6244846875215.
eth_chainId
ynet_version
Ambas funciones devuelven la ID de la cadena de bloques a la que está conectado el nodo RPC actual, con la diferencia de quenet_version
devuelve un Id decimal yeth_chainId
Devuelve una ID hexadecimal.
Nombre de red correspondiente a chainId
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
Prueba con la red de pruebas de Ethereum configuradagoerli
Nodo:
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))
}
Llama aleth_gasPrice
método para consultar el corrientegas price
en la cadena.
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))
}
Aquí escribimos una función para convertir la cadena hexadecimal en un valor numérico legible:toAmount
Además, hay que tener en cuenta que la unidad degasPrice
eswei
, así pasar el valor 0 al parámetro real correspondiente al parámetro formaldecimals
.
"eth_blockNumber
se utiliza para consultar la altura del bloque.
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))
}
Ejecute la herramienta de depuración:
Busca enhttps://etherscan.io/
:
Información del bloque de búsqueda.
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])
}
}
La ejecución en la
Muchas aplicaciones de contratos inteligentes funcionan en Ethereum, yENS
es uno de ellos.ENS
, o Ethereum Name Service, es un servicio descentralizado de resolución de nombres de dominio basado en la cadena de bloques Ethereum.
¿Recuerdas el ejemplo en el tutorial donde verificamos el saldo de la billetera del fundador de Ethereum, Vitalik Buterin?0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045
De hecho, se puede consultar a través de laENS
contrato inteligente con un nombre intuitivovitalik.eth
.
El siguiente contenido de este capítulo utiliza el entorno de la red principal de Ethereum, de acuerdo con elENS
la documentación,Hashing Names
se requieren para consultar nombres de dominio de Ethereum. Utilice el siguiente código para procesarvitalik.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))
}
}
En el ejemplo de código anterior, vimos otra función desconocidaEncode
Esta función es una función API de la plataforma FMZ y se utiliza específicamente para codificar operaciones en la plataforma FMZ. La función admite múltiples métodos de codificación y varios algoritmos de hash.
Encode(algo, inputFormat, outputFormat, data, keyFormat, key string)
De acuerdo con la descripción del documento ENS, utilice elsha3.keccak256
algoritmo para procesar datos.
Llama alnameHash
función, por ejemplo:Log(nameHash("vitalik.eth"))
, puede obtener:ee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835
, y necesitas añadir el prefijo 0xee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835
se utiliza como parámetro delresolver
método en el contrato inteligente ENS.
let ensNode = "0x" + nameHash("vitalik.eth") // Prepare the parameters ensNode for calling the resolver method
Según la documentación ENS, la dirección del contrato para las aplicaciones de contratos inteligentes ENS es:0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e
Antes de llamar a laresolver
En la actualidad, la mayoría de los contratos inteligentes están en el mercado.ABI
del contrato.
Al saber esto, usted puede preguntar: ¿cuál es laABI
¿De un contrato inteligente?
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.
Extraer elresolver
En el caso de los contratos, el ABI de los contratos se puede consultar en el siguiente enlace:https://etherscan.io/
o obtener el ABI a través de otros canales (por ejemplo, documentación del proyecto pertinente).
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"}]`
Aquí vamos a aprender un nuevo método de invocación en la plataforma FMZ,exchange.IO("abi", address, abiContent)
, que se utiliza para registrar ABI.address
Parámetro es la dirección del contrato inteligente y elabiContent
el parámetro es el correspondiente contrato inteligente ABI (cuadrícula).
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
A continuación, puede llamar a laresolver
El método del contrato inteligente ENS, que devuelve la dirección de laENS: Public Resolver
contract.
let resolverAddress = exchange.IO("api", "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e", "resolver", ensNode)
Utilice elENS: Public Resolver
Los contratosaddr
Para obtener la dirección de la billetera de Vitalik Buterin.ENS: Public Resolver
La información de ABI para este contrato inteligente todavía se puede obtener 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)
Por último, llama alENS: Public Resolver
Los contratosaddr
método, siendo el parámetroensNode
.
let vitalikAddress = exchange.IO("api", resolverAddress, "addr", ensNode)
Log("vitalikAddress:", vitalikAddress)
Salida de la función de registro:
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)
}
En los capítulos anteriores del curso, hemos aprendido cómo configurar claves privadas. ¿Cómo sabemos la dirección de la billetera correspondiente a esta clave privada para el objeto de intercambio configurado?exchange.IO("address")
función para obtener la dirección de la billetera correspondiente a la clave privada configurada.
El siguiente contenido en este capítulo utiliza el entorno de Goerli testnet, por lo que el nodo que estoy utilizando es:https://goerli.infura.io/v3/*******
, y Infura asigna diferentes direcciones de nodos para cada usuario registrado.*******
Esconde contenido específico.
function main() {
let walletAddress = exchange.IO("address")
Log("Testnet goerli wallet address:", walletAddress)
}
Después de conocer la dirección de tu billetera, puedes usar el método RPC de Ethereumeth_getTransactionCount
En Ethereum, este recuento es muy común, y en realidad es el número de transacciones de la dirección de la billetera.nonce
En Ethereum, nonce es un número único utilizado para asegurar que cada transacción sea única. Es un número creciente, y aumentará automáticamente cada vez que se envíe una nueva transacción. Por lo tanto, cuando envías una transacción a un contrato inteligente, necesitas proporcionar un nonce para asegurar que la transacción sea única y en el orden correcto. Podemos encontrar esta información en algunos materiales y documentos:
Aquí, elPendingNonceAt
La función en la biblioteca de Ethereum del lenguaje Go es en realidad llamar a laeth_getTransactionCount
En los cursos anteriores, también hemos aprendido a llamar a los métodos RPC.exchange.IO("api", "eth", ...)
funcionan de nuevo.
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))
}
Antes de explicar la operación de transferencia, entendamos brevemente algunos conceptos. Al transferir en Ethereum, se consumirá una cierta cantidad de tokens ETH (como tarifas de gas).
Gas precio
Sin embargo, las tarifas de gas en la red Ethereum siempre fluctúan de acuerdo con la demanda del mercado y las tarifas que los usuarios están dispuestos a pagar, por lo que escribir una tarifa de gas fija en el código a veces no es una opción ideal.eth_gasPrice
método que aprendimos antes, que puede obtener el precio promedio de la gasolina.
GasLimit
Una transferencia estándar de Ether tiene un límite de gas de 21.000 unidades.
Después de comprender los conceptos denonce
, gasPrice
, ygasLimit
FMZ proporciona una función de transferencia muy simple y fácil de usar.
exchange.IO("api", "eth", "send", toAddress, toAmount)
Cuando se utiliza para transferencias, el tercer parámetro deexchange.IO
se fija como toAddress
el parámetro es la dirección que recibe ETH durante la transferencia, ytoAmount
es la cantidad de ETH transferida.
Los parámetrosnonce
, gasPrice
, ygasLimit
pueden utilizar todos los valores predeterminados del sistema obtenidos automáticamente en FMZ. También se pueden especificar:
exchange.IO("api", "eth", "send", toAddress, toAmount, {gasPrice: 5000000000, gasLimit: 21000, nonce: 100})
A continuación, transferiremos una cierta cantidad de ETH a una dirección específica en la red de prueba 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
}
Porque la unidad de la cantidad de transferencia de Ethereum eswei
, una función personalizadatoInnerAmount
Se necesita utilizar para procesar el valor enwei
units.
Hash de transacción de consulta:0xa6f9f51b00d8ae850b0f204380b59da98f4bbce34b813577d3d948f61de4734e
En elhttps://etherscan.io/
.
También se puede escribir código para la consulta transferencia hash0xa6f9f51b00d8ae850b0f204380b59da98f4bbce34b813577d3d948f61de4734e
, utilizando eleth_getTransactionReceipt
método para las consultas.
function main() {
let transHash = "0xa6f9f51b00d8ae850b0f204380b59da98f4bbce34b813577d3d948f61de4734e"
let info = exchange.IO("api", "eth", "eth_getTransactionReceipt", transHash)
return info
}
Resultado de la consulta:
{
"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": []
}
Descripción correspondiente a cada campo:
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.
En el capítulo sobre Read
métodos, y llamar a estos métodos no requieregas
(recuerdan lo que hablamos de gas antes?).Write
métodos de contratos inteligentes en Ethereum y pagar porgas
Estas operaciones serán verificadas por cada nodo y minero en toda la red y cambiar el estado de la cadena de bloques.
Para el contrato ERC20 (contrato de tokens ERC20), la plataforma FMZ enumera el ABI del contrato ERC20 ABI como un ABI común integrado directamente en el sistema, eliminando el paso de registrar el ABI.
Para comprender mejor ABI, puede comprobarlo antes de usarlo.
[{"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