[TOC]

Используйте FMZ, чтобы легко начать разработку web3 на базе Ethereum
Ethereum — это платформа смарт-контрактов, основанная на технологии блокчейн, которая обеспечивает децентрализованный способ написания и развертывания смарт-контрактов. Смарт-контракт — это специальная компьютерная программа, которая может автоматически выполняться на блокчейне и реализовывать различную бизнес-логику без необходимости доверять третьей стороне.
Платформа количественной торговли Inventor (FMZ.COM) предоставляет простой в использовании API, который упрощает разработчикам взаимодействие с блокчейном Ethereum и его экосистемой. Реализовать такие функции, как доступ к децентрализованным биржам (DEX), получение данных в цепочке и отправка транзакций.
В примерах этого руководства используютсяJavaScriptНаписание языка, использование тестовой средыОсновная сеть Ethereum、Тестовая сеть Goerli. Вы также можете просмотреть интерфейсы API, используемые в руководстве, а также соответствующие описания и примеры кода в документации API платформы FMZ.
Прежде чем научиться использовать количественную торговую платформу FMZ, нам необходимо ознакомиться с несколькими основными концепциями:
После регистрации и входа на официальный сайт количественной торговой платформы FMZ (https://www.fmz.com) вы сможете воспользоваться различными функциями платформы. Веб-сайт FMZ является центром управления всей системой, а программы, написанные пользователями, фактически запускаются на хосте. Хост — это программное обеспечение, которое может быть развернуто на различных устройствах, таких как серверы, компьютеры и т. д. Когда пользователь пишет программу и создает работающий экземпляр на веб-сайте FMZ, платформа FMZ связывается с хостом и запускает экземпляр программы на хосте.

Если вы хотите запустить экземпляр программы, вы должны развернуть хост. Развертывание хоста также очень простое, и на платформе есть руководство по развертыванию. Вы также можете использовать «хост развертывания в один клик», предоставляемый FMZ, для автоматического развертывания с использованием сервера, арендованного FMZ.
Программа-хранитель может быть развернута и запущена на серверах, персональных компьютерах и других устройствах при условии нормального состояния сети (должна быть доступна соответствующая цель, например интерфейс обмена, адрес узла и т. д.). Основные этапы развертывания:

robotисполняемый файл. Настройте адрес связи с хранителем. Этот адрес связи уникален для каждой учетной записи FMZ. После входа в FMZ,https://www.fmz.com/m/add-nodeСтраница может просматривать свой собственный адрес (т.е../robot -s node.fmz.com/xxxxxВот эта цепочка адресов, здесьxxxxxСодержимое локации отображается по-разному для каждой учетной записи FMZ). Наконец, вам нужно ввести пароль учетной записи FMZ. После настройки запустите хост-программу.Добавить страницу кастодиана на платформе FMZ, адрес:https://www.fmz.com/m/add-node

Количественная торговая платформа FMZ предоставляет бесплатный инструмент отладки, который поддерживаетJavaScript,TypeScriptСтраница: https://www.fmz.com/m/debug, поскольку создание экземпляра и его запуск оплачиваются. Этот инструмент отладки можно использовать для тестирования и обучения на начальном этапе обучения. Инструмент отладки ничем не отличается от создания экземпляра, за исключением того, что время выполнения ограничено 3 минутами.
использоватьTypeScriptПри использовании языка его необходимо прописать в первой строке кода.// @ts-checkЧтобы переключиться наTypeScriptРежим, если не переключен, по умолчанию используетсяJavaScriptязык.
На FMZ «обмен» — это общее понятие. Для биржи CEX это относится к конкретной конфигурации биржевого счета. Для web3 этот обмен относится к информации о конфигурации, включая адрес узла и конфигурацию закрытого ключа.
При входе на платформу FMZ,https://www.fmz.com/m/add-platformНа странице можно настроить информацию об обмене, где обмен — это общее понятие.

выбиратьWeb3, настройте адрес узла RPC и закрытый ключ. Вы можете нажать «Конфиденциальная информация шифруется и сохраняется с использованием независимого закрытого ключа» в правом нижнем углу, чтобы просмотреть механизм безопасности.
Узлы могут быть созданы самостоятельно или предоставлены поставщиками услуг узлов. Существует множество поставщиков услуг узлов, таких как:Infura. После регистрации вы сможете просмотреть адрес узла вашей учетной записи. Есть и mainnet, и testnet, что удобнее. Настройте этот адрес узла на рисунке выше.Rpc Addressв элементах управления. Теги могут именоваться самостоятельно, чтобы различать настроенные объекты обмена.

На рисункеhttps://mainnet.infura.io/v3/xxxxxxxxxxxxxЭто адрес частного узла RPC основной сети Infura ETH.
После развертывания программы-хранителя и настройки объекта обмена вы можете использовать «инструмент отладки» FMZ.COM для тестирования. Вызовите методы RPC Ethereum для взаимодействия с Ethereum. В дополнение к нескольким методам RPC, перечисленным в этой главе, вы можете обратиться к документации по другим методам RPC, таким какhttps://www.quicknode.com/docs。
Давайте рассмотрим несколько простых примеров и начнем с основ. Существуют способы доступа к web3 для различных языков и инструментов, как показано на рисунке:

Вызовы методов RPC также инкапсулированы в FMZ. Эти функции инкапсулированы в функцию API FMZexchange.IOсередина. Метод вызова:exchange.IO("api", "eth", ...). Первый параметр фиксирован."api", второй параметр фиксирован"eth", остальные параметры зависят от конкретного вызываемого метода RPC.
Для вывода информации мы используем платформу FMZLogфункция,LogФункция может передавать несколько параметров, а затем выводить их в области журнала на странице «Debug Tool» или «Real Trading» платформы FMZ. Страница «Debug Tool» будет основным инструментом для нашего тестирования.
Эфириумeth_getBalanceМетод используется для запроса баланса ETH адреса на Ethereum. Этот метод требует передачи двух параметров.
Давайте проверим основателя EthereumV神Адрес кошелька ETH, известные адреса:0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045。
function main() {
let ethBalance = exchange.IO("api", "eth", "eth_getBalance", "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", "latest")
Log("ethBalance:", ethBalance)
}
Хранитель был развернут (на рисунке: linux/amd64 …) и объект обмена был настроен (на рисунке: Web3 test). Протестируйте код в отладочном инструменте:

Нажмите кнопку «Выполнить», чтобы запустить этот код и отобразить результаты:
ethBalance: 0x117296558f185bbc4c6
LogФункция печатаетethBalanceЗначения переменных:0x117296558f185bbc4c6, который является строковым типом. даБаланс ETH в шестнадцатеричном значении,кweiКак единое целое,1e18 weiэто 1ETH. Поэтому его необходимо преобразовать в читаемый десятичный баланс ETH.
ВоляethBalanceПреобразовать в читаемые данные:
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)
}

Наверхуhttps://etherscan.io/Запрос:

Однако эта обработка будет иметь отклонения из-за точности самого языка, поэтому платформа FMZ имеет две встроенные функции для обработки данных:
Снова отредактируйте код:
function main() {
let ethBalance = exchange.IO("api", "eth", "eth_getBalance", "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", "latest")
// ETH的精度单位为1e18
let ethDecimal = 18
Log("vitalikEthBalance:", Number((BigDecimal(BigInt(ethBalance)) / BigDecimal(Math.pow(10, ethDecimal))).toString()))
}
vitalikEthBalance: 5149.6244846875215
eth_chainIdиnet_versionИх применение схоже, поэтому мы протестировали их вместе. Обе функции возвращают идентификатор блокчейна, к которому подключен текущий узел RPC. Разница в том,net_versionВозвращает десятичный идентификатор.eth_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

Используйте настроенную тестовую сеть EthereumgoerliТест узла:
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))
}

Вызовeth_gasPriceМетод запроса текущей цепочкиgas 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))
}
Здесь мы пишем функцию для преобразования шестнадцатеричной строки в читаемое значение:toAmount. Еще одно замечание: единицей цены газа являетсяwei, поэтому параметрdecimalsСоответствующий фактический параметр может быть передан как 0.
eth_blockNumbeИспользуется для запроса высоты блока.
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))
}
Запустите в отладчике:

https://etherscan.io/По запросу:

Запросить информацию о блоке.
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])
}
}
Следующую информацию можно получить, выполнив команду в «Debug Tool»:

На Ethereum работает большое количество приложений смарт-контрактов.ENSодин из них.ENS, а именно Ethereum Name Service, представляет собой децентрализованную службу разрешения доменных имен, основанную на блокчейне Ethereum.
Помните пример из руководства, где мы запрашивали баланс кошелька основателя Ethereum Виталика Бутерина? Один из адресов кошелька Виталика:0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045. Так откуда же мы знаем этот адрес? На самом деле, черезENSСмарт-контракт с использованием интуитивно понятного имениvitalik.eth(vitalik - имя Виталика) для проведения запроса.
В следующем тексте этой главы используется основная сетевая среда Ethereum.ENSВ документе показано, что запрашиваемое доменное имя Ethereum должно бытьHashing Names, используйте следующий код дляvitalik.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))
}
}
В приведенном выше примере кода мы видим еще одну незнакомую функцию.EncodeЭта функция является функцией API платформы FMZ, которая специально используется для выполнения операций кодирования на платформе FMZ. Эта функция поддерживает несколько методов кодирования и несколько алгоритмов хэширования.
Encode(algo, inputFormat, outputFormat, data, keyFormat, key string)
Согласно документации ENS, используйтеsha3.keccak256Алгоритмы обрабатывают данные.
ВызовnameHashФункции, например:Log(nameHash("vitalik.eth")), мы можем получить:ee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835, вам необходимо добавить префикс «0x».0xee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835Как смарт-контракт ENSresolverПараметры метода.
let ensNode = "0x" + nameHash("vitalik.eth") // 准备好调用resolver方法的参数ensNode
Согласно документу ENS, адрес контракта приложения смарт-контракта ENS следующий:0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e. При вызове смарт-контрактаresolverПрежде чем продолжить, нам нужно подготовить контракт.ABI。
Узнав об этом, я не могу не спросить: что такое смарт-контракт?ABIШерстяная ткань?
ABI,即应用程序二进制接口(Application Binary Interface),是智能合约与外部世界进行通信的接口标准。
智能合约的 ABI 定义了合约的函数接口、参数类型、返回值等信息,以及调用合约的方式和参数传递方式等规范。
智能合约的 ABI 通常以 JSON 格式存储,包含以下信息:
合约的函数接口:函数名、参数列表、返回值等信息。
函数参数类型:如 uint256、bool、string 等。
函数的输入参数和输出参数的编码方式:智能合约使用一种称为 Solidity ABI 的编码方式来编码函数的输入参数和输出参数,
以便与以太坊网络进行交互。
在以太坊网络中,使用智能合约的 ABI 来调用合约的函数。当需要调用合约函数时,需要提供函数名和函数参数,以及将函数参数按照 ABI 编码方式编码后的字节码。
以太坊节点会将这些信息打包成一笔交易,并将交易发送到以太坊网络中执行。
智能合约的 ABI 在 Solidity 语言中可以通过 interface 关键字来定义。以太坊开发工具如 Remix IDE、Truffle 等也提供了 ABI 编辑和生成工具,
使得开发者可以方便地创建和使用智能合约的 ABI。
Извлеките следующее из ENS ABI:resolverПолный ABI также может быть использован вhttps://etherscan.io/Вы можете запросить ABI контракта на GitHub или получить ABI другими способами (например, из соответствующих проектных документов).

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"}]`
Здесь нам предстоит изучить новый метод вызова на платформе FMZ.exchange.IO("abi", address, abiContent), используйте этот метод для регистрации ABI,addressПараметр — адрес смарт-контракта.abiContentПараметр — это соответствующий ABI смарт-контракта (строка).
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智能合约的地址
Далее вы можете вызвать смарт-контракт ENSresolverметод, который возвращаетENS: Public ResolverАдрес контракта.

let resolverAddress = exchange.IO("api", "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e", "resolver", ensNode)
использоватьENS: Public ResolverДоговорнойaddrМетод получения адреса кошелька Виталика. ЗвонитьENS: Public ResolverДля начала контракт все равно необходимо зарегистрировать ABI. Информацию ABI этого смарт-контракта по-прежнему можно найти по адресуhttps://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)

Последний звонокENS: Public ResolverДоговорнойaddrМетод, параметры по-прежнемуensNode。
let vitalikAddress = exchange.IO("api", resolverAddress, "addr", ensNode)
Log("vitalikAddress:", vitalikAddress)
Выходные данные функции журнала:

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() {
// 计算名称
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)
}
В предыдущих главах курса мы узнали, как настраивать закрытые ключи. Для настроенного объекта обмена, как мы узнаем адрес кошелька, соответствующий этому закрытому ключу? Доступно на FMZexchange.IO("address")Функция получает адрес кошелька, соответствующий настроенному закрытому ключу.
Поскольку следующее содержание этой главы используетGoerliТестовая сетевая среда, поэтому я использую следующий узел:https://goerli.infura.io/v3/*******Infura назначает каждому зарегистрированному пользователю разные адреса узлов.*******Конкретное содержимое скрыто.
function main() {
let walletAddress = exchange.IO("address")
Log("测试网 goerli 钱包地址:", walletAddress)
}

Узнав адрес своего кошелька, вы сможете использовать метод RPC Ethereum.eth_getTransactionCountЗапросить количество транзакций по адресу кошелька. Этот счетчик очень часто используется в Ethereum. Фактически, это то, что нужно передавать при переводе денег.nonceПараметры. В Ethereum nonce — это число, используемое для обеспечения уникальности каждой транзакции. Это увеличивающееся число, которое автоматически увеличивается каждый раз при отправке новой транзакции. Поэтому при отправке транзакции в смарт-контракт вам необходимо предоставить одноразовый номер, чтобы гарантировать уникальность транзакции и ее правильность. В некоторых данных и документах мы можем найти:

Вот библиотека Ethereum на языке GoPendingNonceAtФункция на самом деле вызываетeth_getTransactionCountметод. В предыдущем курсе мы также узнали, как вызывать методы RPC. Мы снова это используем здесь.exchange.IO("api", "eth", ...)функция.
”`javascript function toAmount(s, decimals) { return Number((BigDecimal(BigInt(s)) / BigDecimal(Math.pow(10, decimals))).toString()) }
function main() { let walletAddress = exchange.IO(“address”) Log(“测试网 goerli 钱包地址:”, walletAddress)
/**
* eth_getTransactionCount
* @param address - string - The address from which the transaction count to be checked.
* @param bl