Introdução fácil ao desenvolvimento web3 baseado no Ethereum com o FMZ

Autora:Sonhos pequenos, Criado: 2023-03-28 13:32:48, Atualizado: 2023-09-18 20:27:13

[TOC]

img

EtherEaseWithFMZ Tutorial

Introdução fácil ao desenvolvimento web3 baseado no Ethereum com o FMZ

O Ethereum é uma plataforma de smart contracts baseada na tecnologia blockchain, que oferece uma maneira descentralizada de escrever e implantar smart contracts. Os smart contracts são programas de computador especiais que podem ser executados automaticamente no blockchain e podem implementar uma variedade de lógica de negócios sem a necessidade de confiar em terceiros.

Inventor de plataforma de negociação quantitativaFMZ.COMA plataforma oferece uma API fácil de usar que permite que os desenvolvedores interajam mais facilmente com o blockchain Ethereum e seu ecossistema.

Exemplos de uso neste tutorialJavaScriptCriação de linguagens e uso de ambientes de testeA rede EthereumGoerli teste redeO documento API da plataforma FMZ também mostra as interfaces API usadas no tutorial, bem como descrições e exemplos de código.


Introdução ao FMZ

Antes de aprender a usar a plataforma de negociação quantitativa FMZ, precisamos familiarizar-nos com alguns conceitos básicos:

1 FMZ Quantificação de Plataforma de Negociação

O site oficial da plataforma de negociação de quantificação FMZhttps://www.fmz.comO site FMZ é o terminal de gerenciamento de todo o sistema, e os programas escritos pelo usuário são executados no host. O programa pode ser implantado em vários dispositivos, como servidores, computadores, etc. Quando o usuário escreve um bom programa no site FMZ para criar uma instância de execução, a plataforma FMZ comunica com o host e inicia uma instância de programa no host.

img

2o, administrador

Para executar um exemplo de programa, é necessário implantar um administrador, que também é muito simples de implantar, com tutoriais de implantação na plataforma. Também é possível implantar automaticamente o servidor de aluguel usando o "administrador de implantação de um botão" fornecido no FMZ.

  • Implementar administradores em dispositivos pessoais

    Os programas administradores podem ser implementados em dispositivos como servidores, computadores pessoais, etc. Os principais passos para a implementação são:

    1o, iniciar sessão ou abrir o dispositivo para a implementação do programa administrador, por exemploLogin para o servidorOuAbra o computador e entre no sistema operacionalNão, não é. 2, para baixar a versão correspondente do programa administrador (dependendo do sistema operacional do dispositivo), para baixar a página:https://www.fmz.com/m/add-node imgO download é um pacote de compressão que precisa ser descompressado. 4, para executar este administrador, o administrador é um programa chamadorobotO documento executável do FMZ. Configure o endereço de comunicação do administrador, que é único para cada conta FMZ, e, depois de entrar no FMZ, configure o endereço de comunicação do administrador.https://www.fmz.com/m/add-nodeA página pode ver o seu endereço (isto é,./robot -s node.fmz.com/xxxxxEste endereço, aqui.xxxxxO conteúdo da localização é diferente para cada conta da FMZ). Finalmente, é necessário inserir o código de acesso da conta da FMZ para configurar e executar o administrador.

  • Utilizando a função de "deployment host" do FMZ

    Adicionei uma página de administradores na plataforma FMZ, com o endereço:https://www.fmz.com/m/add-node

    img

3. Ferramentas de depuração

A plataforma de negociação quantitativa FMZ oferece uma ferramenta de depuração gratuita, com suporte a uma série de ferramentas de negociação quantitativa.JavaScriptTypeScriptA página é:https://www.fmz.com/m/debugA criação de instâncias é cobrada. Você pode testar e aprender com esta ferramenta durante o ensino fundamental. A ferramenta de depuração não é diferente da criação de instâncias, exceto por ter um tempo de execução limitado a 3 minutos.

UtilizaçãoTypeScriptQuando se trata de linguagem, é preciso escrever na primeira linha do código.// @ts-checkPara mudar paraTypeScriptO padrão, não mudar, é o padrão padrão.JavaScriptA língua.

4o, o mercado

No FMZ, "exchange" é um conceito genérico que, para o CEX, significa uma configuração de conta específica. Para o web3, a configuração é uma informação de configuração que contém o endereço do nó, a configuração de chave privada.

O Facebook também divulgou um vídeo no qual o usuário pode se conectar à plataforma FMZ.https://www.fmz.com/m/add-platformA página pode configurar as informações da bolsa, onde a bolsa é um conceito geral.

img

SeleçãoWeb3Para configurar o endereço do nó RPC, configure a chave privada e clique no canto inferior direito "Encriptação de informações sensíveis com chave privada independente" para ver o mecanismo de segurança.

Os nodes podem ser construídos por nós mesmos ou fornecidos por nossos servidores.InfuraDepois de se registrar, você pode ver o endereço do ponto de sua conta. A rede principal, a rede de teste também estão disponíveis, é mais conveniente configurar este endereço no gráfico acima.Rpc AddressNo controle.label, você pode dar seu próprio nome para distinguir os objetos de troca configurados.

img

Imagemhttps://mainnet.infura.io/v3/xxxxxxxxxxxxxO endereço do RPC da rede ETH da Infura é privado.


Interação com FMZ e Ethereum

在部署好托管者程序、配置好交易所对象的前提下,就可以使用FMZ.COM的「调试工具」进行测试了。调用以太坊RPC方法和以太坊交互,除了本章节列举介绍的几个RPC方法,其它RPC方法可以查询资料了解,例如https://www.quicknode.com/docs

Aqui estão alguns exemplos simples, para começarmos com o básico. Há várias maneiras de acessar o web3 para diferentes linguagens e ferramentas, como:

img

No FMZ, as chamadas de métodos RPC também são encapsuladas, e essas funções são encapsuladas na função API do FMZ.exchange.IOO modo de chamada é:exchange.IO("api", "eth", ...)O primeiro parâmetro é a entrada fixa."api"O segundo parâmetro é a entrada fixa."eth"Os outros parâmetros dependem do método de RPC usado.

A partir de agora, a nossa plataforma FMZ é a única que está disponível para exportar informações.LogA funçãoLogA função pode ser transmitida por vários parâmetros, que são exportados para a área de logs na página "Debugging Tools" ou "Real Disk" da plataforma FMZ, onde a página "Debugging Tools" será a principal ferramenta que vamos testar.

eth_getBalance

O Ethereumeth_getBalanceMétodo usado para consultar o saldo de ETH de um endereço no Ethereum, que requer o envio de dois parâmetros.

  • O que você precisa saber sobre o endereço?
  • A partir daí, o blogueiro começou a escrever sobre o tema.

Vamos consultar o fundador do Ethereum.V神O endereço do ETH Wallet, conhecido como:0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045

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

Já instalou um administrador (diagrama: linux/amd64...) e configurou objetos de troca (diagrama: Web3 test), testando o código em ferramentas de depuração:

img

Clique no botão "Executar" e execute este código, que mostra o resultado:

EthBalance: 0x117296558f185bbc4c6

LogA função é impressa.ethBalanceO valor da variável é:0x117296558f185bbc4c6, é o tipo de strings ─ simBalanço de ETH de 16 dígitosE o que é isso?weiA partir de agora,1e18 weiÉ igual a 1.ETHPor isso, é preciso converter para se tornar um saldo decimal legível de ETH.

O que é isso?ethBalanceConverte-se em dados legíveis:

function main() {
    let ethBalance = exchange.IO("api", "eth", "eth_getBalance", "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", "latest")
    Log("ethBalance:", ethBalance)
    
    // 将ethBalance转换为可读的数据
    let vitalikEthBalance = parseInt(ethBalance.substring(2), 16) / 1e18
    Log("vitalikEthBalance:", vitalikEthBalance)
}

img

Para cima.https://etherscan.io/Perguntas:

img

No entanto, a razão para isso é que o problema de precisão da linguagem em si pode ser desviado, então a plataforma FMZ tem duas funções embutidas para processar dados:

  • Big:Int converte uma string de 16 dígitos em um objeto BigInt.
  • BigDecimal: Converte objetos de tipo numérico em objetos BigDecimal que podem ser operados.

O código foi alterado novamente:

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

    // ETH的精度单位为1e18
    let ethDecimal = 18
    Log("vitalikEthBalance:", Number((BigDecimal(BigInt(ethBalance)) / BigDecimal(Math.pow(10, ethDecimal))).toString()))
}

VitalEthBalanço: 5149.6244846875215

Eth_chainId

eth_chainIdenet_versionAs funções são quase idênticas, por isso vamos testá-las juntas. Ambas as funções retornam o ID do blockchain para o qual o atual nó do RPC foi acessado, com a diferença de:net_versionO que é que isso quer dizer?eth_chainIdRetorna o Id de 16 dígitos.

Nome da rede correspondente ao 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

img

Utilize a rede de teste Ethereum configuradagoerliTestes em nós:

function main() {
    let netVersionId = exchange.IO("api", "eth", "net_version")
    let ethChainId = exchange.IO("api", "eth", "eth_chainId")

    Log("netVersionId:", netVersionId)
    Log("ethChainId:", ethChainId, " ,转换:", parseInt(ethChainId.substring(2), 16))
}

img

Eth_gasPrice

Chamadaeth_gasPriceMétodo para consultar a cadeia atualgas price

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

function main() {
    let gasPrice = exchange.IO("api", "eth", "eth_gasPrice")
    Log("gasPrice:", gasPrice, " ,转换:", toAmount(gasPrice, 0))
}

Aqui, nós transformamos uma string de 16 dígitos em uma operação que pode ser lida como uma função:toAmountTambém é importante notar que a unidade do preço do gás é:weiEntão, a forma da semente.decimalsO parâmetro de transmissão real correspondente pode ser 0.

eth_blockNumbe

eth_blockNumbePara consultar a altura do bloco.

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

A ferramenta de depuração é executada:

img

https://etherscan.io/A pergunta é:

img

eth_getBlockByNumber

O blogueiro também escreveu sobre o tema:

function main() {
    let blockNumber = exchange.IO("api", "eth", "eth_blockNumber")    
    Log(blockNumber)
    let blockMsg = exchange.IO("api", "eth", "eth_getBlockByNumber", blockNumber, true)
    Log(typeof(blockMsg), blockMsg)
    
    // 由于Log输出的内容过多,会自动截断,所以遍历返回的区块信息各个字段,逐个打印
    for (let key in blockMsg) {
        Log("key:", key, ", val:", blockMsg[key])
    }
}

A função de depuração pode ser executada através de ferramentas de depuração que permitem obter informações como:

img


Leia as informações do contrato

O Ethereum é uma plataforma de criptomoedas que oferece uma grande variedade de aplicações de contratos inteligentes.ENSO blogueiro também escreveu sobre o assunto:ENSO Ethereum Name Service é um serviço de análise de nomes de domínio descentralizado baseado no blockchain Ethereum. Lembre-se que no tutorial, nós consultamos o exemplo do saldo da carteira do Deus V, fundador do Ethereum.0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045Então, como é que sabemos o endereço?ENSOs contratos inteligentes, com um nome intuitivovitalik.ethO nome do deus V é vitalik, que é o nome do deus V, para fazer uma consulta.

O seguinte conteúdo deste capítulo é usado no ambiente da rede Ethereum, de acordo com oENSA documentação é conhecida por exigir que o nome de domínio do Ethereum seja consultadoHashing NamesUse o seguinte código:vitalik.ethO nome está sendo processado.

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

E aqui, no exemplo de código acima, nós vemos outra função estranha.EncodeEsta função é uma função API para a plataforma FMZ, que é especificamente usada para realizar operações de codificação na plataforma FMZ, que suporta vários métodos de codificação e suporta vários algoritmos de hash.

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

De acordo com a descrição na documentação ENS, usosha3.keccak256Algoritmos processam dados.

ChamadanameHashFunções, por exemplo:Log(nameHash("vitalik.eth"))O que você pode fazer:ee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835O prefixo "x" deve ser adicionado.0xee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835O contrato inteligente da ENSresolverParâmetros do método.

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

O endereço do contrato para a aplicação do contrato inteligente da ENS é:0x00000000000C2E074eC69A0dFb2997BA6C7d2e1eNão é a primeira vez que o mundo usa contratos inteligentes.resolverAntes de irmos, precisamos de preparar um contrato.ABI

Registro ABI

Aprender a trabalhar aqui faz com que se pergunte: o que é um contrato inteligente?ABIE então?

ABI,即应用程序二进制接口(Application Binary Interface),是智能合约与外部世界进行通信的接口标准。
智能合约的 ABI 定义了合约的函数接口、参数类型、返回值等信息,以及调用合约的方式和参数传递方式等规范。

智能合约的 ABI 通常以 JSON 格式存储,包含以下信息:

合约的函数接口:函数名、参数列表、返回值等信息。
函数参数类型:如 uint256、bool、string 等。
函数的输入参数和输出参数的编码方式:智能合约使用一种称为 Solidity ABI 的编码方式来编码函数的输入参数和输出参数,
以便与以太坊网络进行交互。
在以太坊网络中,使用智能合约的 ABI 来调用合约的函数。当需要调用合约函数时,需要提供函数名和函数参数,以及将函数参数按照 ABI 编码方式编码后的字节码。
以太坊节点会将这些信息打包成一笔交易,并将交易发送到以太坊网络中执行。

智能合约的 ABI 在 Solidity 语言中可以通过 interface 关键字来定义。以太坊开发工具如 Remix IDE、Truffle 等也提供了 ABI 编辑和生成工具,
使得开发者可以方便地创建和使用智能合约的 ABI。

Extrair o ABI do ENSresolverA parte do método, que também pode ser usada com o ABI completo, pode ser encontrada emhttps://etherscan.io/Para obter o ABI do contrato, ou para obter o ABI por outros meios (por exemplo: documentação do projeto).

img

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

Aqui vamos aprender uma nova forma de fazer chamadas na plataforma FMZ.exchange.IO("abi", address, abiContent)A partir daí, a empresa começou a trabalhar com a empresa.addressOs parâmetros são os endereços dos contratos inteligentes.abiContentO parâmetro é o contrato inteligente correspondente ABI (string).

let abiENS_resolver = `[{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"resolver","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"}]`
exchange.IO("abi", "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e", abiENS_resolver)  // 0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e 是在以太坊主网上部署的ENS智能合约的地址

Como invocar um contrato inteligente

A partir daí, você pode chamar o contrato inteligente ENS.resolverO método é, o método é de voltaENS: Public ResolverO endereço do contrato.

img

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

UtilizaçãoENS: Public ResolverContratoaddrComo obter o endereço da carteira do deus V?ENS: Public ResolverOs contratos ainda precisam ser registrados no ABI.https://etherscan.io/Acessado.

let abiENSPublicResolver = `[{"inputs":[{"internalType":"contract ENS","name":"_ens","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"contentType","type":"uint256"}],"name":"ABIChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"address","name":"a","type":"address"}],"name":"AddrChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"coinType","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"newAddress","type":"bytes"}],"name":"AddressChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"bool","name":"isAuthorised","type":"bool"}],"name":"AuthorisationChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"hash","type":"bytes"}],"name":"ContenthashChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"name","type":"bytes"},{"indexed":false,"internalType":"uint16","name":"resource","type":"uint16"},{"indexed":false,"internalType":"bytes","name":"record","type":"bytes"}],"name":"DNSRecordChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"name","type":"bytes"},{"indexed":false,"internalType":"uint16","name":"resource","type":"uint16"}],"name":"DNSRecordDeleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"DNSZoneCleared","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":true,"internalType":"bytes4","name":"interfaceID","type":"bytes4"},{"indexed":false,"internalType":"address","name":"implementer","type":"address"}],"name":"InterfaceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"string","name":"name","type":"string"}],"name":"NameChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"x","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"y","type":"bytes32"}],"name":"PubkeyChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":true,"internalType":"string","name":"indexedKey","type":"string"},{"indexed":false,"internalType":"string","name":"key","type":"string"}],"name":"TextChanged","type":"event"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"uint256","name":"contentTypes","type":"uint256"}],"name":"ABI","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"addr","outputs":[{"internalType":"address payable","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"uint256","name":"coinType","type":"uint256"}],"name":"addr","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"authorisations","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"clearDNSZone","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"contenthash","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes32","name":"name","type":"bytes32"},{"internalType":"uint16","name":"resource","type":"uint16"}],"name":"dnsRecord","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes32","name":"name","type":"bytes32"}],"name":"hasDNSRecords","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes4","name":"interfaceID","type":"bytes4"}],"name":"interfaceImplementer","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"pubkey","outputs":[{"internalType":"bytes32","name":"x","type":"bytes32"},{"internalType":"bytes32","name":"y","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"uint256","name":"contentType","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"setABI","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"uint256","name":"coinType","type":"uint256"},{"internalType":"bytes","name":"a","type":"bytes"}],"name":"setAddr","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"address","name":"a","type":"address"}],"name":"setAddr","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"address","name":"target","type":"address"},{"internalType":"bool","name":"isAuthorised","type":"bool"}],"name":"setAuthorisation","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes","name":"hash","type":"bytes"}],"name":"setContenthash","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"setDNSRecords","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes4","name":"interfaceID","type":"bytes4"},{"internalType":"address","name":"implementer","type":"address"}],"name":"setInterface","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"string","name":"name","type":"string"}],"name":"setName","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes32","name":"x","type":"bytes32"},{"internalType":"bytes32","name":"y","type":"bytes32"}],"name":"setPubkey","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"string","name":"key","type":"string"},{"internalType":"string","name":"value","type":"string"}],"name":"setText","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes4","name":"interfaceID","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"string","name":"key","type":"string"}],"name":"text","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"}]`
exchange.IO("abi", resolverAddress, abiENSPublicResolver)

img

Última chamadaENS: Public ResolverContratoaddrMétodo, os parâmetros continuam a serensNode

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

A função Log é:

img

vitalikAddress: 0xd8da6bf26964af9d7eed9e03e53415d37aa96045

Código completo para chamar a ENS

function nameHash(name) {
    if (name == "") {
        return "0000000000000000000000000000000000000000000000000000000000000000"
    } else {
        let arr = name.split(".")
        let label = arr[0]
        
        arr.shift()
        let remainder = arr.join(".")
        return Encode("sha3.keccak256", "hex", "hex", nameHash(remainder) + Encode("sha3.keccak256", "raw", "hex", label))
    }
}

function main() {
    // 计算名称
    let ensNode = "0x" + nameHash("vitalik.eth")

    // 注册ENS合约
    let abiENS_resolver = `[{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"resolver","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"}]`
    exchange.IO("abi", "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e", abiENS_resolver)
    let resolverAddress = exchange.IO("api", "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e", "resolver", ensNode)
    
    // 注册ENS Public Resolver合约
    let abiENSPublicResolver = `[{"inputs":[{"internalType":"contract ENS","name":"_ens","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"contentType","type":"uint256"}],"name":"ABIChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"address","name":"a","type":"address"}],"name":"AddrChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"coinType","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"newAddress","type":"bytes"}],"name":"AddressChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"bool","name":"isAuthorised","type":"bool"}],"name":"AuthorisationChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"hash","type":"bytes"}],"name":"ContenthashChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"name","type":"bytes"},{"indexed":false,"internalType":"uint16","name":"resource","type":"uint16"},{"indexed":false,"internalType":"bytes","name":"record","type":"bytes"}],"name":"DNSRecordChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"name","type":"bytes"},{"indexed":false,"internalType":"uint16","name":"resource","type":"uint16"}],"name":"DNSRecordDeleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"DNSZoneCleared","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":true,"internalType":"bytes4","name":"interfaceID","type":"bytes4"},{"indexed":false,"internalType":"address","name":"implementer","type":"address"}],"name":"InterfaceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"string","name":"name","type":"string"}],"name":"NameChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"x","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"y","type":"bytes32"}],"name":"PubkeyChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":true,"internalType":"string","name":"indexedKey","type":"string"},{"indexed":false,"internalType":"string","name":"key","type":"string"}],"name":"TextChanged","type":"event"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"uint256","name":"contentTypes","type":"uint256"}],"name":"ABI","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"addr","outputs":[{"internalType":"address payable","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"uint256","name":"coinType","type":"uint256"}],"name":"addr","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"authorisations","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"clearDNSZone","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"contenthash","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes32","name":"name","type":"bytes32"},{"internalType":"uint16","name":"resource","type":"uint16"}],"name":"dnsRecord","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes32","name":"name","type":"bytes32"}],"name":"hasDNSRecords","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes4","name":"interfaceID","type":"bytes4"}],"name":"interfaceImplementer","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"pubkey","outputs":[{"internalType":"bytes32","name":"x","type":"bytes32"},{"internalType":"bytes32","name":"y","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"uint256","name":"contentType","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"setABI","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"uint256","name":"coinType","type":"uint256"},{"internalType":"bytes","name":"a","type":"bytes"}],"name":"setAddr","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"address","name":"a","type":"address"}],"name":"setAddr","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"address","name":"target","type":"address"},{"internalType":"bool","name":"isAuthorised","type":"bool"}],"name":"setAuthorisation","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes","name":"hash","type":"bytes"}],"name":"setContenthash","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"setDNSRecords","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes4","name":"interfaceID","type":"bytes4"},{"internalType":"address","name":"implementer","type":"address"}],"name":"setInterface","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"string","name":"name","type":"string"}],"name":"setName","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes32","name":"x","type":"bytes32"},{"internalType":"bytes32","name":"y","type":"bytes32"}],"name":"setPubkey","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"string","name":"key","type":"string"},{"internalType":"string","name":"value","type":"string"}],"name":"setText","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes4","name":"interfaceID","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"string","name":"key","type":"string"}],"name":"text","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"}]`
    exchange.IO("abi", resolverAddress, abiENSPublicResolver)
    let vitalikAddress = exchange.IO("api", resolverAddress, "addr", ensNode)
    Log("vitalikAddress:", vitalikAddress)
}

Envio de ETH

Em capítulos anteriores do curso, aprendemos como configurar a chave privada, e como saber qual o endereço de carteira correspondente a essa chave privada para o objeto de câmbio que foi configurado?exchange.IO("address")A função obtém a chave privada configurada para o endereço da carteira correspondente.

O uso do seguinte conteúdo neste capítuloGoerliA partir de agora, o que eu estou fazendo é testar um ambiente de rede, então o ponto que eu estou usando é:https://goerli.infura.io/v3/*******A infura atribui um endereço diferente para cada usuário registrado, aqui:*******O conteúdo específico é escondido.

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

img

Depois de saber o seu endereço de carteira, você pode usar o método RPC do Ethereum.eth_getTransactionCountO conteúdo de transações para consultar o endereço da carteira. No Ethereum, esse conteúdo é muito usado, na verdade, é o que é necessário para passar as operações de transferência.nonceParâmetros, no Ethereum, o nonce é usado para garantir que cada transação seja um número único. É um número incremental que aumenta automaticamente a cada vez que uma nova transação é enviada. Portanto, quando você envia uma transação para um contrato inteligente, é necessário fornecer um nonce para garantir que a transação seja única e na ordem correta.

https://goethereumbook.org/en/

img

Aqui está o Ethereum do Go.PendingNonceAtA função é a que é chamada.eth_getTransactionCountMétodos. Em lições anteriores também aprendemos como chamar o método RPC, e vamos usá-lo novamente aqui.exchange.IO("api", "eth", ...)Função.

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

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

    /**
    * eth_getTransactionCount
    * @param address - string - The address from which the transaction count to be checked.
    * @param blockNumber - string - The block number as a string in hexadecimal format or tags.
    * @returns The integer of the number of transactions sent from an address encoded as hexadecimal.
    */
    let nonce = exchange.IO("api", "eth", "eth_getTransactionCount", walletAddress, "pending")
    Log("钱包地址:", walletAddress, "当前的 nonce:", nonce, ",转换为10进制:", toAmount(nonce, 0))
}

Antes de explicar o que é transferência, vamos simplesmente entender alguns conceitos que consomem um certo número de tokens de ETH (como um custo de gás) quando são transferidos no Ethereum.

  • GasPrice

    No entanto, o preço do gás na rede Ethereum sempre varia de acordo com a demanda do mercado e o que os usuários estão dispostos a pagar, por isso escrever um preço fixo de gás no código às vezes não é uma opção ideal.eth_gasPriceO preço médio do gás pode ser obtido através de um método chamado método.

  • GasLimit

    O limite de gás para uma transferência de Ethereum padrão é de 21000 unidades.

Entendido.noncegasPricegasLimitEstes conceitos podem ser testados em transferências. Uma função de transferência muito simples e fácil de usar em FMZ.

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

O Facebook também divulgou uma mensagem sobre o assunto.exchange.IOO terceiro parâmetro é escrito como "send".toAddressO parâmetro é o endereço do ETH recebido no momento da transferência.toAmountA quantidade de ETH transferida.

noncegasPricegasLimitEstes parâmetros podem ser obtidos automaticamente pelo sistema por defeito no FMZ.

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

Em seguida, transferimos um certo número de ETH para um endereço no goerli da web de teste:

function toInnerAmount(s, decimals) {
    return (BigDecimal(s)*BigDecimal(Math.pow(10, decimals))).toFixed(0)
}

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

    let ret = exchange.IO("api", "eth", "send", "0x4D75a08E870674E68cAE611f329A27f446A66813", toInnerAmount(0.01, 18))
    return ret    // 返回Transaction Hash : 0xa6f9f51b00d8ae850b0f204380b59da98f4bbce34b813577d3d948f61de4734e
}

A unidade de quantidade de transferências éweiÉ necessário usar uma função personalizada.toInnerAmountTratamento comoweiO valor da unidade.

Emhttps://etherscan.io/O Hash da transação:0xa6f9f51b00d8ae850b0f204380b59da98f4bbce34b813577d3d948f61de4734e

img

Também é possível escrever um hash de consulta de código.0xa6f9f51b00d8ae850b0f204380b59da98f4bbce34b813577d3d948f61de4734e, usoeth_getTransactionReceiptComo fazer uma consulta?

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

Resultados da pesquisa:

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

Cada campo tem uma descrição correspondente:

blockHash - 该交易所在区块的哈希值
blockNumber - 以十六进制编码的该交易所在区块的块号
contractAddress - 如果是合约创建,该合约的地址;否则为null
cumulativeGasUsed - 该交易在区块中执行时使用的总燃气量
effectiveGasPrice - 每单位燃气的总基础费用加小费
from - 发送者的地址
gasUsed - 该特定交易使用的燃气量
logs - 生成该交易的日志对象数组
  address - 生成该日志的地址
  topics - 0到4个32字节索引日志参数的数据数组。在Solidity中,第一个主题是事件签名的哈希值(例如Deposit(address,bytes32,uint256)),除非你使用匿名说明符声明该事件
  data - 日志的32字节非索引参数
  blockNumber - 该日志所在区块的块号
  transactionHash - 该日志创建时的交易哈希值。如果该日志处于待定状态,则为null
  transactionIndex - 该日志创建时的交易索引位置。如果该日志处于待定状态,则为null
  blockHash - 该日志所在区块的哈希值
  logIndex - 该日志在区块中的索引位置,以十六进制编码的整数。如果该日志处于待定状态,则为null
  removed - 如果该日志已被删除,则为true,由于链重组而被删除;如果是有效的日志,则为false
logsBloom - 用于检索相关日志的布隆过滤器
status - 以十六进制编码的值,它要么是1(成功),要么是0(失败)
to - 接收者的地址。如果是合约创建交易,则为null
transactionHash - 该交易的哈希值
transactionIndex - 以十六进制编码的该交易在区块中的索引位置
type - 值的类型

Chamados de contratos inteligentes Ethereum

Estamos emLeia as informações do contratoEste capítulo mostra um exemplo completo de como os métodos de chamada de contratos ENS implementados no Ethereum obtiveram o endereço da carteira de Deus V. Estes métodos são:ReadNão é preciso usar métodos.gasO que é o gás? Neste capítulo, vamos chamar alguns dos smart contracts do Ethereum.WriteMétodos e pagamentosgasEstas operações são validadas por cada um dos nós da rede e pelos mineiros e alteram o estado da cadeia de blocos.

ERC20

Para os contratos ERC20 ("contratos de tokens ERC20"), a plataforma FMZ classifica o contrato ERC20 como um ABI de uso comum, integrado diretamente no sistema, evitando o registro do ABI. Para o ABI, também aprendemos no tutorial anterior, que registramos o contrato do ABI do ENS antes de chamar o método do contrato ENS.

Para uma melhor compreensão do ABI, veja abaixo o ABI do contrato ERC20 antes de usar:

[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"guy","type":"address"},{"name":"wad","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"src","type":"address"},{"name":"dst","type":"address"},{"name":"wad","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"wad","type":"uint256"}],"name":"withdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"dst","type":"address"},{"name":"wad","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"deposit","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"src","type":"address"},{"indexed":true,"name":"guy","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"src","type":"address"},{"indexed":true,"name":"dst","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"dst","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"src","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Withdrawal","type":"event"}]

O seguinte conteúdo é utilizado neste capítulo:GoerliTestar um ambiente de rede.

Balanço

E então nós vamos voltar a praticar outra vez como chamar um contrato.ReadComo ler a informação do contrato e chamar o contrato ERC20balanceOfComo saber o saldo do token?balanceOfO método tem apenas um parâmetro, mas não é nomeado e pode ser visto como um endereço (ou seja, o endereço do token que está sendo consultado). Como os dados retornados não são unitários em um único token, também são necessários dados de precisão do token para ser calculado em troca, a precisão do token pode ser calculada em um contrato ERC20.decimalsMétodo de obtenção. Utilizamos a rede de teste EthereumgoerliA partir de agora, o sistema de negociação de tokens será executado em uma cadeia diferente, com o objetivo de testar se o endereço do contrato de tokens é diferente.

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

function main() {
    let walletAddress = exchange.IO("address")
    
    // goerli WETH address 
    let wethAddress = "0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6"
    // goerli LINK address 
    let linkAddress = "0x326C977E6efc84E512bB9C30f76E30c160eD06FB"

    // 由于是ERC20合约,FMZ已经内置ABI注册,所以这里不用注册ERC20 ABI
    let wethDecimals = exchange.IO("api", wethAddress, "decimals")
    let linkDecimals = exchange.IO("api", linkAddress, "decimals")

    let wethBalance = exchange.IO("api", wethAddress, "balanceOf", walletAddress)
    let linkBalance = exchange.IO("api", linkAddre

Mais.