Mở rộng web3 dựa trên Ethereum với FMZ

Tác giả:Giấc mơ nhỏ, Tạo: 2023-03-28 13:32:48, Cập nhật: 2023-09-18 20:27:13

[TOC]

img

EtherEaseWithFMZ

Mở rộng web3 dựa trên Ethereum với FMZ

Ethereum là một nền tảng hợp đồng thông minh dựa trên công nghệ blockchain, nó cung cấp một cách phân quyền để viết và triển khai hợp đồng thông minh. Hợp đồng thông minh là một chương trình máy tính đặc biệt có thể tự động thực hiện trên blockchain và thực hiện tất cả các logic kinh doanh mà không cần phải tin tưởng bên thứ ba.

Những người phát minh ra nền tảng giao dịch định lượngFMZ.COMCác API dễ sử dụng cho phép các nhà phát triển tương tác dễ dàng hơn với blockchain Ethereum và hệ sinh thái của nó. Khả năng truy cập sàn giao dịch tập trung (DEX), thu thập dữ liệu trên chuỗi, gửi giao dịch, v.v.

Sử dụng ví dụ trong bài họcJavaScriptViết ngôn ngữ, sử dụng môi trường thử nghiệmEthereumGoerli thử mạngBạn cũng có thể xem tài liệu API của nền tảng FMZ để xem các giao diện API được sử dụng trong hướng dẫn và các mô tả, ví dụ về mã liên quan.


FMZ sử dụng lối vào

Trước khi học cách sử dụng nền tảng giao dịch định lượng FMZ, chúng ta cần làm quen với một vài khái niệm cơ bản:

FMZ Quantified Trading Platform Architecture (FMZ là một nền tảng giao dịch định lượng)

Trong trang web chính thức của FMZhttps://www.fmz.comCác ứng dụng được viết bởi người dùng thực sự chạy trên máy chủ. Các ứng dụng này có thể được triển khai trên nhiều thiết bị khác nhau, chẳng hạn như máy chủ, máy tính, v.v. Khi người dùng viết một chương trình tốt trên trang web FMZ để tạo một trường hợp chạy, nền tảng FMZ sẽ liên lạc với người quản lý và khởi động một trường hợp chương trình trên người quản lý.

img

2. Người quản lý

Nếu bạn muốn thực hiện một ứng dụng, bạn phải triển khai một trình quản lý, và việc triển khai trình quản lý rất đơn giản, có hướng dẫn triển khai trên nền tảng. Bạn cũng có thể tự động triển khai một máy chủ thuê máy chủ bằng "một trình quản lý triển khai một nút" được cung cấp trên FMZ.

  • triển khai người quản lý trên thiết bị cá nhân

    Các chương trình quản trị có thể được triển khai trên các thiết bị như máy chủ, máy tính cá nhân, miễn là đảm bảo mạng hoạt động tốt, các bước chính của việc triển khai là:

    1, đăng nhập hoặc mở thiết bị để triển khai chương trình quản trị, ví dụ:Đăng nhập vào máy chủHoặcMở máy tính vào hệ điều hành❖ 2, tải xuống phiên bản ứng dụng quản trị tương ứng (tùy theo hệ điều hành thiết bị), tải xuống trang:https://www.fmz.com/m/add-node img3, tải xuống là một gói nén, cần giải nén. 4, để chạy chương trình quản trị viên này, một chương trình quản trị viên tên làrobotCác tài liệu thực thi của FMZ. Thiết lập địa chỉ giao tiếp của người quản lý, địa chỉ này là duy nhất cho mỗi tài khoản FMZ.https://www.fmz.com/m/add-nodeCác trang có thể xem địa chỉ của mình (tức là./robot -s node.fmz.com/xxxxxDòng địa chỉ này, ở đây.xxxxxNội dung của vị trí, mỗi tài khoản FMZ hiển thị khác nhau). Cuối cùng, bạn cũng cần nhập mật khẩu của tài khoản FMZ, cấu hình chúng và sau đó chạy chương trình quản trị viên.

  • Sử dụng các tính năng của nền tảng FMZ "Một nút triển khai quản trị viên"

    Một số người đã đăng ký đăng ký đăng ký trên trang web của FMZ.https://www.fmz.com/m/add-node

    img

3. Công cụ chỉnh sửa

FMZ Quantitative Trading Platform cung cấp một công cụ chỉnh sửa miễn phí, hỗ trợ các ứng dụng và dịch vụ khác nhau.JavaScriptTypeScriptTrang này là:https://www.fmz.com/m/debug, bởi vì việc tạo trường hợp chạy là tính phí. Bạn có thể sử dụng công cụ này để thử nghiệm, học tập trong thời gian học tiểu học. Ngoài việc giới hạn thời gian chạy tối đa 3 phút, các khía cạnh khác không khác gì với việc tạo trường hợp chạy.

Sử dụngTypeScriptTrong ngôn ngữ, bạn cần phải viết ở dòng đầu tiên của mã.// @ts-checkđể chuyển sangTypeScriptMô hình, không chuyển đổi mặc định làJavaScriptNgôn ngữ.

4, sàn giao dịch

Trong FMZ, "thị trường" là một khái niệm chung, với sàn giao dịch CEX chỉ là một cấu hình tài khoản giao dịch cụ thể. Đối với web3, sàn giao dịch này chỉ là một thông tin cấu hình, bao gồm địa chỉ nút, cấu hình khóa riêng.

Trong khi đó, một số người khác đã đăng ký đăng ký trên nền tảng FMZ.https://www.fmz.com/m/add-platformCác trang có thể cấu hình thông tin về sàn giao dịch, nơi sàn giao dịch là khái niệm chung.

img

Lựa chọnWeb3Bạn có thể cài đặt địa chỉ RPC, cài đặt khóa cá nhân, bạn có thể nhấp vào bên dưới bên phải "Làm mã hóa thông tin nhạy cảm bằng khóa riêng độc lập" để xem các cơ chế bảo mật.

Các nút có thể được xây dựng bằng các nút tự xây dựng hoặc các nút được cung cấp bởi các máy chủ nút. Có rất nhiều các máy chủ nút, ví dụ:Infura; Sau khi đăng ký, bạn có thể xem địa chỉ của tài khoản của mình.; HomeNet, TestNet cũng có, dễ dàng hơn, cấu hình địa chỉ này trong biểu đồ trên.Rpc AddressTrong điều khiển này, thẻ có thể đặt tên cho chính nó để phân biệt các đối tượng giao dịch được cấu hình.

img

Hình ảnhhttps://mainnet.infura.io/v3/xxxxxxxxxxxxxĐây là địa chỉ của các nút RPC trên mạng chủ sở hữu riêng của Infura.


Tương tác với FMZ và Ethereum

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

Chúng tôi liệt kê một vài ví dụ đơn giản, bắt đầu từ những điều cơ bản.

img

Trong FMZ, các cuộc gọi phương thức RPC cũng được gói gọn, những chức năng này được gói gọn trong các hàm API của FMZ.exchange.IOTrong đó.exchange.IO("api", "eth", ...)◎ Các tham số đầu tiên là truyền cố định"api"Các tham số thứ hai là truyền cố định."eth"Các tham số khác tùy thuộc vào phương pháp RPC được gọi cụ thể.

Chúng tôi sử dụng nền tảng FMZ để xuất thông tin.LogCác hàm,LogChức năng có thể nhập nhiều tham số và xuất ra khu vực nhật ký trong trang "Debug Tools" hoặc "RealDisk" của nền tảng FMZ, trang "Debug Tools" sẽ là công cụ chính của chúng tôi để thử nghiệm.

eth_getBalance

Ethereumeth_getBalancePhương pháp để truy vấn số dư ETH của một địa chỉ trên Ethereum, phương pháp này đòi hỏi phải truyền 2 tham số.

  • Địa chỉ cần truy vấn.
  • Những người dùng Facebook thường sử dụng "latest" (gần đây nhất).

Chúng ta hãy tìm hiểu về người sáng lập Ethereum.V神Địa chỉ của ví ETH được biết đến là:0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045

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

Đã triển khai trình quản lý (hình: linux/amd64...) và cấu hình các đối tượng sàn giao dịch (hình: Web3 test), kiểm tra mã trong công cụ gỡ lỗi:

img

Nhấp vào nút "Execute" và chạy đoạn mã này, kết quả sẽ xuất hiện:

EthBalance: 0x117296558f185bbc4c6

LogCác hàm được in raethBalanceGiá trị của biến là:0x117296558f185bbc4c6, là kiểu chuỗi.Số dư ETH với giá trị 16 chữ số,weiĐơn vị1e18 weilà 1ETHVì vậy, nó cũng cần phải được chuyển đổi để trở thành một số dư ETH thập phân có thể đọc được.

sẽethBalanceChuyển đổi thành dữ liệu có thể đọc:

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

Ở trênhttps://etherscan.io/Tìm kiếm:

img

Tuy nhiên, điều này được lý giải bởi vấn đề chính xác của ngôn ngữ sẽ có sự sai lệch, vì vậy nền tảng FMZ đã tích hợp hai chức năng để xử lý dữ liệu:

  • Big:Int chuyển đổi chuỗi 16 chữ số thành đối tượng BigInt.
  • BigDecimal: chuyển đổi các đối tượng kiểu số thành các đối tượng BigDecimal có thể vận hành.

Một số người khác đã bị ảnh hưởng.

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

Đơn vị: 5149.6244846875215

eth_chainId

eth_chainIdnet_versionCác hàm này đều trả về ID của blockchain mà các node RPC hiện tại đã truy cập, sự khác biệt là:net_versionTrả về ID số thập phân,eth_chainIdTrả về Id của hệ số 16.

Tên mạng tương ứng với chuỗi ID

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

Sử dụng mạng thử nghiệm Ethereum được cấu hình tốtgoerliKiểm tra nút:

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_gas Giá

Gọi điệneth_gasPricePhương pháp, truy vấn chuỗi hiện tạigas 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))
}

Ở đây chúng ta viết một hàm để chuyển đổi một chuỗi 16 chữ số thành một số lượng có thể đọc được:toAmountMột điều cần lưu ý là đơn vị của giá gas là:weiVì vậy, chúng ta có thể tạo ra các hình dángdecimalsGiá trị thông biến thực tương ứng là 0.

eth_blockNumbe

eth_blockNumbeĐể hỏi độ cao của khối.

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

Các công cụ này được sử dụng trong:

img

https://etherscan.io/Tìm kiếm:

img

eth_getBlockByNumber

Tìm kiếm thông tin về khối.

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

Các thông tin sau đây có thể được thực hiện trong công cụ gỡ lỗi:

img


Đọc thông tin hợp đồng

Có rất nhiều ứng dụng hợp đồng thông minh đang chạy trên Ethereum.ENSMột trong số đó là.ENSDịch vụ tên miền Ethereum (Ethereum Name Service) là một dịch vụ phân tích tên miền phi tập trung dựa trên blockchain Ethereum. Bạn có nhớ trong bài hướng dẫn, chúng tôi đã hỏi về ví dụ về số dư ví của người sáng lập Ethereum, V God?0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045│ Vậy làm sao chúng ta biết địa chỉ này?ENSHợp đồng thông minh, sử dụng một tên trực quanvitalik.eth(Vitalik là tên của vị thần V) để hỏi.

Các nội dung sau đây được sử dụng trong môi trường Ethereum theo quy định củaENSTài liệu được biết là cần thiết để truy vấn tên miền EthereumHashing NamesSử dụng mã sau đây.vitalik.ethTên đã được xử lý.

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

Trong ví dụ mã trên, chúng ta thấy một hàm khác lạ.Encode, là một hàm API của nền tảng FMZ, được sử dụng đặc biệt để mã hóa các hoạt động trên nền tảng FMZ, hỗ trợ nhiều cách mã hóa và hỗ trợ nhiều thuật toán hash.

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

Sử dụng theo mô tả trong tài liệu ENSsha3.keccak256Các thuật toán xử lý dữ liệu.

Gọi điệnnameHashCác hàm, ví dụ:Log(nameHash("vitalik.eth"))Bạn có thể:ee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835, cần thêm tiền tố "0x".0xee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835Một hợp đồng thông minh của ENSresolverCác tham số của phương pháp.

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

Tìm tài liệu của ENS để biết địa chỉ hợp đồng của ứng dụng hợp đồng thông minh ENS là:0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e❖ Những người đang gọi hợp đồng thông minhresolverTrước khi tiếp cận, chúng ta cần chuẩn bị hợp đồng.ABI

Đăng ký ABI

Học đến đây không thể không hỏi, hợp đồng thông minh là gì?ABICó gì không?

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

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

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

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

Và chúng ta có thể lấy nó ra khỏi ENS.resolverMột phần của phương pháp, cũng có thể sử dụng ABI đầy đủ, có thể được sử dụng trênhttps://etherscan.io/Bạn có thể truy cập vào ABI của hợp đồng, hoặc có được ABI bằng các cách khác (ví dụ: tài liệu dự án liên quan).

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

Một lần nữa, chúng ta sẽ học một cách gọi mới trên nền tảng FMZ.exchange.IO("abi", address, abiContent)Một số người đã sử dụng phương pháp này để đăng ký ABI.addressCác tham số là địa chỉ của hợp đồng thông minh.abiContentCác tham số là các hợp đồng thông minh tương ứng 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智能合约的地址

Cách gọi hợp đồng thông minh

Sau đó, bạn có thể gọi ENS Smart Contract.resolverPhương pháp này, phương pháp này quay lạiENS: Public ResolverĐịa chỉ của hợp đồng.

img

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

Sử dụngENS: Public ResolverThỏa thuậnaddrCách lấy địa chỉ ví của V.ENS: Public ResolverCác hợp đồng vẫn cần phải đăng ký ABI trước. Thông tin ABI của hợp đồng thông minh vẫn có thể được truy cập từ các trang web khác nhau.https://etherscan.io/Nhận được.

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

Gọi cuối cùngENS: Public ResolverThỏa thuậnaddrPhương pháp, các tham số vẫn làensNode

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

Lưu ý:

img

vitalikAddress: 0xd8da6bf26964af9d7eed9e03e53415d37aa96045

Mã đầy đủ để gọi 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)
}

Gửi ETH

Trong các bài học trước đây, chúng ta đã học cách cấu hình khóa riêng, và làm thế nào để chúng ta biết khóa riêng này tương ứng với địa chỉ ví đối với các đối tượng giao dịch đã được cấu hình?exchange.IO("address")Chức năng lấy khóa cá nhân được cấu hình cho địa chỉ ví tương ứng.

Do các nội dung sau đây được sử dụng trong chương này:GoerliTôi đã thử nghiệm môi trường web, vì vậy các nút mà tôi sử dụng là:https://goerli.infura.io/v3/*******Các địa chỉ của các nút được infura phân bổ cho mỗi người đăng ký khác nhau, ở đây*******Những người khác cũng có thể sử dụng các phương tiện này để thu thập thông tin.

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

img

Khi bạn biết địa chỉ ví của mình, bạn có thể sử dụng phương pháp RPC của Ethereum.eth_getTransactionCountSố lượng giao dịch truy vấn địa chỉ ví. Trong Ethereum, số lượng này rất phổ biến, thực sự là những gì cần được truyền khi chuyển tiền.nonceTrong Ethereum, nonce được sử dụng để đảm bảo rằng mỗi giao dịch là một số duy nhất. Nó là một số tăng dần và sẽ tự động tăng lên mỗi khi bạn gửi một giao dịch mới. Do đó, khi bạn gửi giao dịch đến hợp đồng thông minh, bạn cần phải cung cấp một nonce để đảm bảo giao dịch là duy nhất và thứ tự là đúng.

https://goethereumbook.org/en/

img

Đây là phần mềm Ethereum của ngôn ngữ GoPendingNonceAtCác hàm thực sự được gọi.eth_getTransactionCountCác phương pháp. Trong bài học trước, chúng ta đã học cách gọi phương pháp RPC, và chúng ta sẽ sử dụng nó một lần nữa.exchange.IO("api", "eth", ...)Chức năng.

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

Trước khi giải thích các hoạt động chuyển tiền, chúng ta chỉ cần hiểu một số khái niệm về việc chuyển tiền trên Ethereum sẽ tiêu thụ một số token ETH (như chi phí khí đốt). Chi phí khí đốt được xác định bởi hai tham số cụ thể:

  • gas Giá

    Tuy nhiên, chi phí nhiên liệu trên mạng Ethereum luôn thay đổi theo nhu cầu của thị trường và chi phí người dùng sẵn sàng trả, do đó, viết giá nhiên liệu cố định trong mã đôi khi không phải là lựa chọn lý tưởng.eth_gasPricePhương pháp này có thể thu được giá trung bình của khí đốt.

  • gasLimit

    Giới hạn khí đốt cho một giao dịch Ethereum tiêu chuẩn là 21000 đơn vị.

Được rồi.noncegasPricegasLimitCác khái niệm này có thể được thử nghiệm chuyển khoản.

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

Khi sử dụng như một khoản chuyển tiền,exchange.IOCác đối số thứ ba được viết là "send".toAddressCác tham số là địa chỉ nhận ETH khi chuyển tiền.toAmountSố lượng ETH được chuyển.

noncegasPricegasLimitCác tham số này có thể được sử dụng trên FMZ với các giá trị mà hệ thống mặc định tự động lấy. Bạn cũng có thể chỉ định:

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

Tiếp theo, chúng tôi chuyển một số ETH vào một địa chỉ trên goerli trên mạng thử nghiệm:

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
}

Vì đơn vị của số lượng chuyển tiền Ethereum làweiBạn cần phải sử dụng một chức năng tùy chỉnh.toInnerAmountxử lý nhưweiSố lượng của đơn vị.

Tronghttps://etherscan.io/Tìm kiếm Transaction Hash:0xa6f9f51b00d8ae850b0f204380b59da98f4bbce34b813577d3d948f61de4734e

img

Bạn cũng có thể viết mã truy vấn chuyển đổi hash0xa6f9f51b00d8ae850b0f204380b59da98f4bbce34b813577d3d948f61de4734eSử dụngeth_getTransactionReceiptCách tìm kiếm.

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

Kết quả tìm kiếm:

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

Mỗi trường có mô tả tương ứng:

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

Gọi hợp đồng thông minh Ethereum

Chúng ta đang ởĐọc thông tin hợp đồngTrong chương này, qua một ví dụ hoàn chỉnh, các phương pháp gọi các hợp đồng ENS được triển khai trên Ethereum đã lấy địa chỉ ví của V. Những phương pháp này thuộcReadCác phương pháp này không cần thiết.gasTrong chương này, chúng ta sẽ gọi một số hợp đồng thông minh trên Ethereum là các hợp đồng thông minh.WritePhương pháp và thanh toángasCác hoạt động này sẽ được xác minh bởi mỗi nút trên toàn mạng và các thợ mỏ và thay đổi trạng thái của blockchain.

ERC20

Đối với các hợp đồng ERC20 (các hợp đồng token ERC20), nền tảng FMZ liệt kê ABI của hợp đồng ERC20 là ABI thông thường được tích hợp trực tiếp trong hệ thống, bỏ qua bước đăng ký ABI này. Đối với ABI, chúng tôi cũng đã tìm hiểu trong bài học trước đây, chúng tôi đã đăng ký ABI của hợp đồng ENS trước khi gọi phương pháp hợp đồng ENS.

Để hiểu rõ hơn về ABI, trước khi sử dụng, hãy xem ABI của hợp đồng ERC20 dưới đây:

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

Sử dụng nội dung sau đây:GoerliCác nhà nghiên cứu cho biết:

Số dư

Sau đó, chúng ta tập lại cách gọi hợp đồng.ReadCách đọc thông tin hợp đồng, gọi hợp đồng ERC20balanceOfCách tìm kiếm số dư tokenbalanceOfPhương pháp chỉ có một tham số, nhưng không được đặt tên, được nhìn thấy bằng kiểu là một địa chỉ (tức là địa chỉ của mã thông báo được truy vấn). Vì dữ liệu được trả về không được tính bằng một mã thông báo, nên cũng cần dữ liệu chính xác của mã thông báo để tính toán, độ chính xác của mã thông báo có thể được tính bằng hợp đồng ERC20.decimalsPhương pháp lấy. Chúng tôi sử dụng mạng thử nghiệm Ethereum.goerliĐể kiểm tra, hãy lưu ý rằng địa chỉ hợp đồng mã thông báo trên các chuỗi khác nhau cũng có thể khác nhau.

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

Thêm nữa