Легкое введение в разработку web3 на базе Ethereum с FMZ

Автор:Маленькие мечты, Создано: 2023-03-28 13:32:48, Обновлено: 2023-09-18 20:27:13

[TOC]

img

Урок EtherEaseWithFMZ

Легкое введение в разработку web3 на базе Ethereum с FMZ

Ethereum - это платформа умных контрактов, основанная на технологии блокчейн, которая предоставляет децентрализованный способ написания и развертывания умных контрактов; умные контракты - это специальные компьютерные программы, которые могут автоматически выполняться на блокчейне и реализовывать различные бизнес-логики без необходимости доверять третьим лицам.

Изобретатели количественной платформы для торговлиFMZ.COMЭто позволяет разработчикам более легко взаимодействовать с блокчейном Ethereum и его экосистемой. Это позволяет получить доступ к централизованной бирже (DEX), получить данные о цепочке, отправить транзакции и т. д.

Использование примеров в этом урокеJavaScriptНаписание языков, использование тестовых средЭфириумГёрли тестирует сетьВ API-документации FMZ-платформы также можно посмотреть API-интерфейсы, используемые в учебниках, а также их описания и примеры кода.


FMZ использует вход

Перед тем, как научиться использовать квантовую торговую платформу FMZ, нам необходимо ознакомиться с несколькими основными концепциями:

1 FMZ - архитектура квантовой платформы

На официальном сайте FMZhttps://www.fmz.comПосле регистрации, после входа в систему, можно использовать различные функции платформы. FMZ является администратором всей системы, и программы, написанные пользователем, фактически работают на хостере. Хостера могут быть развернуты на различных устройствах, таких как серверы, компьютеры и т. д. Когда пользователь создает рабочий экземпляр на сайте FMZ, платформа FMZ общается с хостером и запускает экземпляр программы на хостере.

img

2. Хранители

Если вы хотите запустить экземпляр программы, вам нужно будет развернуть хостера, развертывание хостера также очень простое, есть инструкции по развертыванию на платформе.

  • Развернуть хост на персональных устройствах

    Программа может быть развернута на серверах, персональных компьютерах и других устройствах, при условии, что сеть функционирует. Основные шаги в развертывании:

    1. Зарегистрироваться или открыть устройство, на котором вы хотите развернуть программу администратора, например:Вход на серверИлиОткрыть компьютер и войти в операционную системуЯ не знаю. 2, загрузить соответствующую версию хостпрограммы (в зависимости от операционной системы устройства), загрузить страницу:https://www.fmz.com/m/add-node img3, загружается пакет сжатия, который требует разжатия. 4, чтобы запустить этот хост, хост - это программа под названиемrobotИспользуемый файл. Конфигурируйте адрес обмена сообщениями администратора, который является уникальным для каждой учетной записи FMZ, после входа в FMZhttps://www.fmz.com/m/add-nodeНа странице можно посмотреть свой адрес (т.е../robot -s node.fmz.com/xxxxxЭто адресная строка, здесь.xxxxxСодержимое местоположения, показываемое каждой учетной записью FMZ, отличается). Наконец, необходимо ввести пароль учетной записи FMZ, который необходимо настроить, после чего можно запустить администраторную программу.

  • Использование FMZ-платформы с функцией "Одна кнопка развертывания хостера"

    Добавить страницу хозяина на платформе FMZ, адрес:https://www.fmz.com/m/add-node

    img

3. Инструменты для декомпиляции

FMZ Quantitative Trading Platform предоставляет бесплатный инструмент для декомпенсации, поддерживающий:JavaScriptTypeScriptНа странице написано:https://www.fmz.com/m/debug, поскольку создание экземпляров платного действия. В начальном классе можно использовать этот инструмент для тестирования, обучения. Кроме ограничения времени выполнения на 3 минуты, другие аспекты не отличаются от создания экземпляров.

ИспользованиеTypeScriptВ языке, который требует написания в первой строке кода// @ts-checkДля переключения наTypeScriptПо умолчанию, не переключаетсяJavaScriptЯзык.

4., биржа

В FMZ "биржа" является общей концепцией, которая для биржи CEX означает конкретную конфигурацию учетной записи биржи. Для web3 эта биржа означает конфигурационную информацию, содержащую адрес узла, конфигурацию частного ключа.

На сайте FMZ можно посмотреть видео, сделанное в режиме онлайн.https://www.fmz.com/m/add-platformНа странице, на которой можно настроить информацию об биржах, где биржа является общей концепцией.

img

ВыборWeb3Для того, чтобы установить адрес RPC-нота или установить частный ключ, нажмите в нижнем правом углу "Сохранение конфиденциальной информации с использованием независимого частного ключа" для просмотра механизма безопасности.

Нод может быть создан самостоятельно или предоставлен сервером. Нод-серверов много, например:ИнфураПосле регистрации можно посмотреть адрес своего аккаунта. Главная сеть, тестовая сеть доступны, более удобно, чтобы настроить этот адрес в графике выше.Rpc AddressВ контроле.tag можно дать себе название, чтобы отличить объекты биржи, на которых они настраиваются.

img

На рисункеhttps://mainnet.infura.io/v3/xxxxxxxxxxxxxЭто адрес RPC-нота частной сети ETH Infura.


Взаимодействие с FMZ и Ethereum

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

Мы перечислим несколько простых примеров, чтобы начать с основ.

img

В FMZ также были завернуты вызовы методов RPC, которые были завернуты в функции API FMZ.exchange.IOВ среднем.exchange.IO("api", "eth", ...)Первый параметр - фиксированный поток."api"Второй параметр - фиксированный поток."eth"Другие параметры определяются в зависимости от конкретного метода RPC.

Мы использовали платформу FMZ для вывода информации.LogФункцияLogФункция может вводить несколько параметров, а затем выводить их в регионе журналов на странице FMZ "Дебютные инструменты" или "Физический диск", где страница "Дебютные инструменты" будет основным инструментом для нашего тестирования.

eth_getBalance

Эфириумeth_getBalanceМетод, используемый для запроса баланса ETH на адрес на Ethereum, требует передачи 2 параметров.

  • Например, в 2010 году в Нью-Йорке вспыхнул пожар.
  • Например, в некоторых странах, в частности, в Китае, в Китае, в Китае, в Китае, в Китае, в Китае, в Китае, в Китае, в Китае, в Китае, в Китае, в Китае, в Китае, в Китае, в Китае, в Китае, в Китае, в Китае, в Китае, в Китае, в Китае, в Китае, в Китае, в Китае, в Китае, в Китае, в Китае, в Китае, в Китае.

Давайте спросим у основателя Ethereum.V神На данный момент существует только один ETH-кошелек.0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045

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

Уже развернуты хостеры (изображение: linux/amd64...) и настроены объекты биржи (изображение: Web3 test), в дебаторе тестируется код:

img

Нажмите кнопку "Выполнить", чтобы запустить этот код, и вы увидите результат:

EthБалканс: 0x117296558f185bbc4c6

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

img

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

img

Однако это объясняется тем, что в вопросах точности языка могут быть отклонения, поэтому платформа FMZ встроена в две функции для обработки данных:

  • Big:Int преобразует шестнадцатизначную строку в объект BigInt.
  • BigDecimal: преобразует объекты с числовым типом в обрабатываемые объекты BigDecimal.

Новый код:

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

ВиталикЭтБалкан: 5149.6244846875215

eth_chainId

eth_chainIdиnet_versionПрименение почти одинаковое, поэтому проверим вместе. Обе функции возвращают ID блокчейна, к которому в данный момент присоединился узел RPC, разница в том, чтоnet_versionИ мы возвращаем ID десятичного порядка.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

img

Использование хорошо настроенной тестовой сети 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))
}

img

eth_gasPrice

Звонок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Соответствующее значение реального параметра передачи может быть равно нулю.

eth_blockNumbe

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

Дебютные инструменты:

img

https://etherscan.io/Запрос:

img

eth_getBlockByNumber

Например, вы можете получить информацию о блоке.

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

В инструменте "Дебют" вы можете получить следующую информацию:

img


Читать информацию о контракте

На эфире работает множество приложений для умных контрактов.ENSОн был одним из них.ENSEthereum Name Service - это децентрализованная служба анализа доменных имен, основанная на блокчейне Ethereum. Помните, что в нашем уроке мы спрашивали примеры с балансом кошелька основателя Ethereum, Бога V?0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045Но как мы узнаем этот адрес?ENSУмные контракты, использующие интуитивно понятные названияvitalik.ethНапример, в одном из интервью, который я читал в своем блоге, я написал, что я хочу узнать больше о жизни человека.

В этой главе мы рассмотрим следующее:ENSДокументы, которые требуются для запроса доменного имени EthereumHashing 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)

Использование в соответствии с описанием в документации ENSsha3.keccak256Алгоритмы обрабатывают данные.

ЗвонокnameHashФункции, например:Log(nameHash("vitalik.eth"))В этом случае:ee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835, необходимо добавить префикс "0x".0xee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835В качестве интеллектуального контракта ENSresolverПараметры метода.

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

В документе ENS указано, что адрес контракта на приложение ENS Smart Contract:0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e‒ В связи с этим, я не могу сказать, что я не знаю, что делать.resolverМы должны подготовить контракт, прежде чем приступить к работе.ABI

Регистрация ABI

Именно поэтому мы пришли сюда, чтобы узнать, что такое умные контракты.ABIЧто это?

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

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

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

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

Вытащить ABI из ENSresolverЧасть методов, также можно использовать с полным ABI, можно использовать вhttps://etherscan.io/Вы можете запросить ABI по контракту или получить ABI другими способами (например, документация по проекту).

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

В этой статье мы узнаем о новом способе вызова на платформе 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智能合约的地址

Как вызвать умные контракты

В следующий раз мы сможем настроить систему, которая будет называться ENS Smart Contract.resolverСделано. Сделано.ENS: Public ResolverАдрес контракта.

img

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

ИспользованиеENS: Public ResolverКонтрактaddrСпособы получения адреса кошелька бога V.ENS: Public ResolverКонтракт по-прежнему требует регистрации 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)

img

Последний звонокENS: Public ResolverКонтрактaddrМетод, параметры остаютсяensNode

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

Вывод функции Log:

img

vitalikAddress: 0xd8da6bf26964af9d7eed9e03e53415d37aa96045

Полный код вызова 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)
}

Отправка ETH

В предыдущих главах мы уже говорили о том, как настроить частный ключ, и как мы узнаем, что этот частный ключ соответствует адресу кошелька для конфигурированного объекта биржи?exchange.IO("address")Функция получает конфигурированный частный ключ, соответствующий адресу кошелька.

В связи с использованиемGoerliЯ использую следующие узлы для тестирования веб-среды:https://goerli.infura.io/v3/*******Инфура распределяет различные адреса узлов для каждого зарегистрированного пользователя.*******В частности, в Twitter появилась статья, в которой говорится, что в ней скрыто определенное содержание.

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

img

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

https://goethereumbook.org/en/

img

Здесь вы можете увидеть, что происходит в репозитории Ethereum на языке GoPendingNonceAtФункция, на самом деле, называетсяeth_getTransactionCountМетод. В предыдущих уроках мы также изучали, как использовать метод RPC, и мы используем его снова.exchange.IO("api", "eth", ...)Функция.

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

Перед тем, как рассказать о том, как происходит транзакция, мы просто познакомимся с некоторыми понятиями, которые потребляют определенные токены ETH при транзакции на Ethereum (как расходы на газ).

  • Газовый

    Тем не менее, стоимость газа в сети Ethereum всегда колеблется в зависимости от потребностей рынка и того, что пользователи готовы заплатить, поэтому фиксированная стоимость газа, записанная в коде, иногда не является идеальным вариантом.eth_gasPriceВ этом случае, если вы хотите получить среднюю цену на газ, используйте один из следующих методов:

  • Газовой лимит

    Газовый лимит на стандартную транзакцию эфиримов составляет 21000 единиц.

Понимаю.noncegasPricegasLimitЭти концепции можно протестировать. В FMZ упакованы очень простые и удобные функции перевода.

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

Поскольку они используются в качестве перевода денег, они могут быть использованы в качестве платежных средств.exchange.IOТретий параметр фиксируется как "send".toAddressПараметры - это адрес, на котором получается ETH при переводе.toAmountКоличество ETH для перевода.

noncegasPricegasLimitЭти параметры могут быть использованы в FMZ с помощью системного автоматического получения по умолчанию.

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

Далее мы переводим определенную сумму ETH в адрес на тестовом сайте goerli:

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
}

Потому что единицей количества транзакций в Эфириуме являетсяweiДля этого нужно использовать специальную функцию.toInnerAmountОбработкаweiЧисло в единице.

Вhttps://etherscan.io/Например:0xa6f9f51b00d8ae850b0f204380b59da98f4bbce34b813577d3d948f61de4734e

img

Вы также можете написать код для запроса, передачи хештегов.0xa6f9f51b00d8ae850b0f204380b59da98f4bbce34b813577d3d948f61de4734eИспользованиеeth_getTransactionReceiptКак сделать запрос?

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

Результаты поиска:

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

Описание каждого поля:

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 - 值的类型

Смарт-контракты на Ethereum

Мы находимсяЧитать информацию о контрактеВ этой главе приведен полный пример того, как методы вызова ENS-контрактов, развернутых на Эфириуме, получают адрес кошелька Бога V. Эти методы относятся кReadВ этом случае вы не должны использовать эти методы.gasВ этой главе мы будем называть некоторые из этих умных контрактов на Эфириуме.WriteСпособы и оплатаgasЭти операции будут проверены каждым нотом по всей сети, а также майнером, и изменят состояние блокчейна.

ERC20

Для ERC20 контрактов (ERC20 token contracts) платформа FMZ включает ABI ERC20 контрактов как обычный ABI прямо в систему, без регистрации ABI.

Для более полного понимания ABI, перед тем как использовать его, вы можете посмотреть следующий ABI для ERC20 контракта:

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

Использование:GoerliПроверка сетевой среды.

баланс

И затем мы повторяем еще раз, как вызвать контракт.ReadМетод чтения контрактной информации и вызова контракта ERC20balanceOfКак узнать баланс токенов?balanceOfМетод имеет только один параметр, но не имеет названия, который можно увидеть по типу как адрес (т. е. адрес запрошенного токона). Так как возвращенные данные не являются единицами в виде токенов, для их расчета также требуются данные о точности токенов, то точность токенов может быть определена по контракту ERC20.decimalsМетод получения. Мы используем тестовую сеть EthereumgoerliПроведите тестирование и обратите внимание, что в разных цепочках могут быть разные адреса контрактов на токены.

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

Больше