[TOC]
EtherEaseWithFMZ hướng dẫn
Bắt đầu với phát triển web3 dựa trên Ethereum sử dụng FMZ dễ dàng
Ethereum là một nền tảng hợp đồng thông minh dựa trên công nghệ blockchain, cung cấp một cách phi tập trung để viết và triển khai các hợp đồng thông minh.
FMZ Quant Trading Platform (FMZ.COM) cung cấp một 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ó. Nó đạt được quyền truy cập vào các sàn giao dịch phi tập trung (DEX), thu thập dữ liệu trên chuỗi, gửi giao dịch và các chức năng khác.
Trong hướng dẫn này, các ví dụ được viết bằngJavaScript
ngôn ngữ, môi trường thử nghiệm sử dụng cả haiMạng chính EthereumvàMạng thử GoerliVà bạn cũng có thể xem các giao diện API và mô tả liên quan, ví dụ mã được sử dụng trong hướng dẫn trong tài liệu API nền tảng FMZ.
Trước khi học cách sử dụng nền tảng giao dịch FMZ Quant, chúng ta cần làm quen với một vài khái niệm cơ bản:
Sau khi đăng ký và đăng nhập vào trang web chính thức của FMZ Quant Trading Platform (https://www.fmz.com), bạn có thể sử dụng các chức năng khác nhau của nền tảng. Trang web FMZ là cuối quản lý của toàn bộ hệ thống, và các chương trình được viết bởi người dùng thực sự chạy trên docker. Chương trình phần mềm docker có thể được triển khai trên các thiết bị khác nhau, chẳng hạn như máy chủ, máy tính, vv. Khi người dùng viết một chương trình và tạo một phiên bản chạy trên trang web FMZ, nền tảng FMZ sẽ liên lạc với docker và bắt đầu một phiên bản chương trình trên đó.
Nếu bạn muốn chạy một phiên bản chương trình, bạn phải triển khai một docker. Việc triển khai docker cũng rất đơn giản, và có các hướng dẫn triển khai trên nền tảng. Bạn cũng có thể sử dụng
Bạn có thể triển khai và chạy chương trình docker trên máy chủ, máy tính cá nhân và các thiết bị khác, miễn là mạng là bình thường (cần phải có thể truy cập vào mục tiêu tương ứng, chẳng hạn như một giao diện trao đổi nhất định, địa chỉ nút, v.v.).
robot
. Thiết lập địa chỉ liên lạc docker, mà là duy nhất cho mỗi tài khoản FMZ, sau khi đăng nhập vào FMZ, bạn có thể xem địa chỉ của riêng bạn tạihttps://www.fmz.com/m/add-node
trang (tức là,./robot -s node.fmz.com/xxxxx
chuỗi địa chỉ này, nơi nội dung tạixxxxx
vị trí là khác nhau cho mỗi tài khoản FMZ). Cuối cùng, bạn cần nhập mật khẩu của tài khoản FMZ của bạn. Sau khi cấu hình các thiết lập này, chạy chương trình docker.Sử dụng
Thêm một trang docker trên nền tảng FMZ, địa chỉ:https://www.fmz.com/m/add-node
FMZ Quant Trading Platform cung cấp một công cụ gỡ lỗi miễn phí hỗ trợJavaScript
, TypeScript
, và trang là:https://www.fmz.com/m/debug. Bởi vì tạo các instance để chạy được tính phí. Trong giai đoạn học tập ban đầu, bạn có thể sử dụng công cụ gỡ lỗi này để kiểm tra và học. Ngoại trừ giới hạn thời gian chạy tối đa là 3 phút, không có sự khác biệt giữa sử dụng công cụ gỡ lỗi và tạo một instance để chạy.
Khi sử dụngTypeScript
ngôn ngữ, bạn cần phải viết// @ts-check
trên dòng mã đầu tiên để chuyển sangTypeScript
chế độ; nếu không chuyển đổi, mặc định làJavaScript
language.
Trên FMZ,
Trong trạng thái đăng nhập của nền tảng FMZ, tạihttps://www.fmz.com/m/add-platform
trang, bạn có thể cấu hình thông tin trao đổi, nơi trao đổi là một khái niệm chung.
ChọnWeb3
, cấu hình địa chỉ nút RPC, cấu hình khóa riêng, bạn có thể nhấp vào góc dưới bên phải
Các nút có thể là các nút tự xây dựng hoặc các nút được cung cấp bởi các nhà cung cấp dịch vụ nút. Có nhiều nhà cung cấp dịch vụ nút, chẳng hạn như:Infura. Sau khi đăng ký, bạn có thể xem địa chỉ nút của tài khoản của riêng bạn. Cả mainnet và testnet đều có sẵn, điều này khá thuận tiện.Rpc Address
Các nhãn có thể được đặt tên bởi chính bạn để phân biệt giữa các đối tượng trao đổi được cấu hình.
Trong bức ảnh,https://mainnet.infura.io/v3/xxxxxxxxxxxxx
là địa chỉ nút RPC riêng của Infura ETH mainnet.
Sau khi triển khai chương trình docker và cấu hình đối tượng trao đổi, bạn có thể sử dụngFMZ.COM
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. Đối với các ngôn ngữ và công cụ khác nhau, có nhiều cách để truy cập web3, như được hiển thị trong hình:
Trên FMZ, các cuộc gọi phương thức RPC cũng được đóng gói và các hàm này được đóng gói trong hàm FMZ APIexchange.IO
Phương pháp gọi làexchange.IO("api", "eth", ...)
. Các tham số đầu tiên được cố định để"api"
, các tham số thứ hai được cố định để"eth"
, và các tham số khác phụ thuộc vào phương pháp RPC cụ thể được gọi.
Đối với thông tin đầu ra, chúng tôi sẽ sử dụng cácLog
Phương tiện truyền thông FMZLog
function có thể chấp nhận nhiều tham số và sau đó xuất ra chúng trong khu vực nhật ký của trang
Cáceth_getBalance
phương pháp của Ethereum được sử dụng để truy vấn số dư ETH của một địa chỉ trên Ethereum, và phương pháp này đòi hỏi hai tham số.
Vitalik Buterin
Địa chỉ ví của ETH, địa chỉ được biết là:0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045
.function main() {
let ethBalance = exchange.IO("api", "eth", "eth_getBalance", "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", "latest")
Log("ethBalance:", ethBalance)
}
Đã triển khai docker (trong hình: linux/amd64...) và cấu hình đối tượng trao đổi (trong hình: Web3 test), kiểm tra mã trong công cụ gỡ lỗi:
Nhấp vào nút
EthBalance: 0x117296558f185bbc4c6
Cáclog
chức năng in raethBalance
giá trị biến thể như:0x117296558f185bbc4c6
, đó là một kiểu chuỗi.giá trị mười sáu của số dư ETHtrongwei
đơn vị, với1e18 wei
bằng 1ETH
Do đó, nó cần phải được chuyển đổi để trở thành một số dư ETH thập phân có thể đọc được.
Chuyển đổiethBalance
thành dữ liệu có thể đọc được:
function main() {
let ethBalance = exchange.IO("api", "eth", "eth_getBalance", "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", "latest")
Log("ethBalance:", ethBalance)
// Converting ethBalance into readable data
let vitalikEthBalance = parseInt(ethBalance.substring(2), 16) / 1e18
Log("vitalikEthBalance:", vitalikEthBalance)
}
Tìm kiếmhttps://etherscan.io/
:
Tuy nhiên, do vấn đề độ chính xác của ngôn ngữ chính nó, sẽ có những sai lệch trong cách xử lý này. Do đó, nền tảng FMZ có hai chức năng tích hợp để xử lý dữ liệu:
Điều chỉnh lại mã:
function main() {
let ethBalance = exchange.IO("api", "eth", "eth_getBalance", "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", "latest")
// The precision unit of ETH is 1e18
let ethDecimal = 18
Log("vitalikEthBalance:", Number((BigDecimal(BigInt(ethBalance)) / BigDecimal(Math.pow(10, ethDecimal))).toString()))
}
Đơn vị: 5149.6244846875215
eth_chainId
vànet_version
Cả hai chức năng này trả về ID của blockchain mà nút RPC hiện tại được kết nối với, với sự khác biệt lànet_version
trả về một Id thập phân vàeth_chainId
trả về một ID hexadecimal.
Tên mạng tương ứng với 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
Kiểm tra với mạng thử nghiệm Ethereum được cấu hìnhgoerli
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, " , conversion:", parseInt(ethChainId.substring(2), 16))
}
Gọi choeth_gasPrice
phương pháp để truy vấn hiện tạigas price
trên chuỗi.
function toAmount(s, decimals) {
return Number((BigDecimal(BigInt(s)) / BigDecimal(Math.pow(10, decimals))).toString())
}
function main() {
let gasPrice = exchange.IO("api", "eth", "eth_gasPrice")
Log("gasPrice:", gasPrice, " , conversion:", toAmount(gasPrice, 0))
}
Ở đây chúng ta viết một hàm để chuyển đổi chuỗi hexadecimal thành một giá trị số có thể đọc được:toAmount
Ngoài ra, lưu ý rằng đơn vịgasPrice
làwei
, vì vậy chuyển giá trị 0 đến tham số thực tương ứng với tham số chính thứcdecimals
.
"eth_blockNumber
được sử dụng để truy vấn chiều cao 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))
}
Chạy trong công cụ gỡ lỗi:
Tìm kiếmhttps://etherscan.io/
:
Tìm kiếm thông tin 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)
// Due to the excessive content of Log output, it will be truncated automatically, so traverse each field of the returned block information and print them one by one
for (let key in blockMsg) {
Log("key:", key, ", val:", blockMsg[key])
}
}
Thực hiện trong
Nhiều ứng dụng hợp đồng thông minh chạy trên Ethereum, vàENS
là một trong số đó.ENS
, hoặc Dịch vụ Tên Ethereum, là một dịch vụ giải quyết tên miền phi tập trung dựa trên blockchain Ethereum.
Bạn có nhớ ví dụ trong hướng dẫn nơi chúng tôi kiểm tra số dư của ví của người sáng lập Ethereum Vitalik Buterin?0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045
Vậy làm thế nào chúng ta biết địa chỉ?ENS
hợp đồng thông minh sử dụng một tên trực quanvitalik.eth
.
Nội dung sau trong chương này sử dụng môi trường mạng chính Ethereum, theoENS
tài liệu,Hashing Names
được yêu cầu để truy vấn tên miền Ethereum. Sử dụng mã sau để xử lý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))
}
}
Trong ví dụ mã ở trên, chúng tôi đã thấy một chức năng không quen thuộc khácEncode
Chức năng này là một hàm API của nền tảng FMZ và được sử dụng đặc biệt để mã hóa các hoạt động trên nền tảng FMZ. Chức năng hỗ trợ nhiều phương pháp mã hóa và các thuật toán băm khác nhau.
Encode(algo, inputFormat, outputFormat, data, keyFormat, key string)
Theo mô tả trong tài liệu ENS, sử dụngsha3.keccak256
thuật toán để xử lý dữ liệu.
Gọi chonameHash
chức năng, ví dụ:Log(nameHash("vitalik.eth"))
, bạn có thể nhận được:ee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835
, và bạn cần thêm tiền tố 0xee6c4522aab0003e8d14cd40a6af439055fd2577951148c14b6cea9a53475835
được sử dụng như là tham số củaresolver
phương pháp trong ENS hợp đồng thông minh.
let ensNode = "0x" + nameHash("vitalik.eth") // Prepare the parameters ensNode for calling the resolver method
Theo tài liệu ENS, địa chỉ hợp đồng cho các ứng dụng hợp đồng thông minh ENS là:0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e
Trước khi gọi điện choresolver
phương pháp hợp đồng thông minh, chúng ta cũng cần chuẩn bịABI
của hợp đồng.
Khi biết điều này, bạn có thể hỏi:ABI
của một hợp đồng thông minh?
ABI, or Application Binary Interface, is the interface standard for smart contracts to communicate with the external world.
The ABI of a smart contract defines the contract's function interfaces, parameter types, return values, and other information, as well as specifications for calling the contract and passing parameters.
The ABI of a smart contract is usually stored in JSON format and contains the following information:
Contract function interfaces: function names, parameter lists, return values, etc.
Function parameter types: such as uint256, bool, string etc.
Encoding methods for input and output parameters of functions: Smart contracts use an encoding method called Solidity ABI to encode input and output parameters of functions so that they can interact with Ethereum network.
In Ethereum network ,the ABI of a smart contract is used to call its functions. When you need to call a contract function, you need to provide the name of the function, its parameters, and bytecode encoded according to ABI encoding method.
Ethereum nodes will package this information into transactions and send them out on Ethereum network for execution.
In Solidity language,the keyword 'interface' can be used define ABIs for smart contracts. Ethereum development tools like Remix IDE ,Truffle also provide editing & generation tools making it easier developers create & use ABIs.
Xóa raresolver
Bạn có thể truy vấn ABI của hợp đồng trênhttps://etherscan.io/
hoặc có được ABI thông qua các kênh khác (ví dụ: tài liệu dự án có liên quan).
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"}]`
Ở đây chúng ta sẽ học một phương pháp gọi mới trên nền tảng FMZ,exchange.IO("abi", address, abiContent)
, được sử dụng để đăng ký ABI.address
thông minh hợp đồng địa chỉ vàabiContent
tham số là hợp đồng thông minh tương ứng ABI (dòng chuỗi).
let abiENS_resolver = `[{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"resolver","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"}]`
exchange.IO("abi", "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e", abiENS_resolver) // 0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e is the address of the ENS smart contract deployed on the Ethereum mainnet
Tiếp theo, bạn có thể gọi choresolver
phương pháp của ENS hợp đồng thông minh, trả về địa chỉ củaENS: Public Resolver
contract.
let resolverAddress = exchange.IO("api", "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e", "resolver", ensNode)
Sử dụngENS: Public Resolver
hợp đồngaddr
để lấy địa chỉ ví của Vitalik Buterin.ENS: Public Resolver
Thông tin ABI cho hợp đồng thông minh này vẫn có thể được lấy từ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)
Cuối cùng, gọi choENS: Public Resolver
hợp đồngaddr
phương pháp, với các tham số vẫn làensNode
.
let vitalikAddress = exchange.IO("api", resolverAddress, "addr", ensNode)
Log("vitalikAddress:", vitalikAddress)
Lượng đầu ra của hàm log:
vitalikAddress: 0xd8da6bf26964af9d7eed9e03e53415d37aa96045
function nameHash(name) {
if (name == "") {
return "0000000000000000000000000000000000000000000000000000000000000000"
} else {
let arr = name.split(".")
let label = arr[0]
arr.shift()
let remainder = arr.join(".")
return Encode("sha3.keccak256", "hex", "hex", nameHash(remainder) + Encode("sha3.keccak256", "raw", "hex", label))
}
}
function main() {
// Calculate the name
let ensNode = "0x" + nameHash("vitalik.eth")
// Register ENS contract
let abiENS_resolver = `[{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"resolver","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"}]`
exchange.IO("abi", "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e", abiENS_resolver)
let resolverAddress = exchange.IO("api", "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e", "resolver", ensNode)
// Register ENS Public Resolver contract
let abiENSPublicResolver = `[{"inputs":[{"internalType":"contract ENS","name":"_ens","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"contentType","type":"uint256"}],"name":"ABIChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"address","name":"a","type":"address"}],"name":"AddrChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"coinType","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"newAddress","type":"bytes"}],"name":"AddressChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"bool","name":"isAuthorised","type":"bool"}],"name":"AuthorisationChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"hash","type":"bytes"}],"name":"ContenthashChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"name","type":"bytes"},{"indexed":false,"internalType":"uint16","name":"resource","type":"uint16"},{"indexed":false,"internalType":"bytes","name":"record","type":"bytes"}],"name":"DNSRecordChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"name","type":"bytes"},{"indexed":false,"internalType":"uint16","name":"resource","type":"uint16"}],"name":"DNSRecordDeleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"DNSZoneCleared","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":true,"internalType":"bytes4","name":"interfaceID","type":"bytes4"},{"indexed":false,"internalType":"address","name":"implementer","type":"address"}],"name":"InterfaceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"string","name":"name","type":"string"}],"name":"NameChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"x","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"y","type":"bytes32"}],"name":"PubkeyChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":true,"internalType":"string","name":"indexedKey","type":"string"},{"indexed":false,"internalType":"string","name":"key","type":"string"}],"name":"TextChanged","type":"event"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"uint256","name":"contentTypes","type":"uint256"}],"name":"ABI","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"addr","outputs":[{"internalType":"address payable","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"uint256","name":"coinType","type":"uint256"}],"name":"addr","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"authorisations","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"clearDNSZone","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"contenthash","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes32","name":"name","type":"bytes32"},{"internalType":"uint16","name":"resource","type":"uint16"}],"name":"dnsRecord","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes32","name":"name","type":"bytes32"}],"name":"hasDNSRecords","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes4","name":"interfaceID","type":"bytes4"}],"name":"interfaceImplementer","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"pubkey","outputs":[{"internalType":"bytes32","name":"x","type":"bytes32"},{"internalType":"bytes32","name":"y","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"uint256","name":"contentType","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"setABI","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"uint256","name":"coinType","type":"uint256"},{"internalType":"bytes","name":"a","type":"bytes"}],"name":"setAddr","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"address","name":"a","type":"address"}],"name":"setAddr","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"address","name":"target","type":"address"},{"internalType":"bool","name":"isAuthorised","type":"bool"}],"name":"setAuthorisation","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes","name":"hash","type":"bytes"}],"name":"setContenthash","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"setDNSRecords","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes4","name":"interfaceID","type":"bytes4"},{"internalType":"address","name":"implementer","type":"address"}],"name":"setInterface","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"string","name":"name","type":"string"}],"name":"setName","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes32","name":"x","type":"bytes32"},{"internalType":"bytes32","name":"y","type":"bytes32"}],"name":"setPubkey","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"string","name":"key","type":"string"},{"internalType":"string","name":"value","type":"string"}],"name":"setText","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes4","name":"interfaceID","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"string","name":"key","type":"string"}],"name":"text","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"}]`
exchange.IO("abi", resolverAddress, abiENSPublicResolver)
let vitalikAddress = exchange.IO("api", resolverAddress, "addr", ensNode)
Log("vitalikAddress:", vitalikAddress)
}
Trong các chương khóa học trước, chúng ta đã học cách cấu hình khóa riêng. Làm thế nào chúng ta biết địa chỉ ví tương ứng với khóa riêng này cho đối tượng trao đổi được cấu hình? Trên FMZ, bạn có thể sử dụngexchange.IO("address")
chức năng để lấy địa chỉ ví tương ứng với khóa riêng được cấu hình.
Nội dung sau trong chương này sử dụng môi trường testnet Goerli, vì vậy các nút tôi đang sử dụng là:https://goerli.infura.io/v3/*******
, và Infura gán địa chỉ nút khác nhau cho mỗi người dùng đã đăng ký.*******
ẩn nội dung cụ thể.
function main() {
let walletAddress = exchange.IO("address")
Log("Testnet goerli wallet address:", walletAddress)
}
Sau khi biết địa chỉ ví của bạn, bạn có thể sử dụng phương pháp RPC của Ethereumeth_getTransactionCount
Trong Ethereum, số lượng này rất phổ biến, và nó thực sự lànonce
trong Ethereum, nonce là một số duy nhất được sử dụng để đảm bảo rằng mỗi giao dịch là duy nhất. nó là một số ngày càng tăng, và nó sẽ tự động tăng mỗi khi một giao dịch mới được gửi. do đó, khi bạn gửi giao dịch đến một hợp đồng thông minh, bạn cần cung cấp một nonce để đảm bảo rằng giao dịch là duy nhất và theo thứ tự chính xác. chúng ta có thể tìm thấy thông tin này trong một số tài liệu và tài liệu:
Ở đây,PendingNonceAt
chức năng trong thư viện Ethereum của ngôn ngữ Go thực sự gọi cáceth_getTransactionCount
Trong các bài học trước, chúng ta cũng đã học cách gọi các phương thức RPC.exchange.IO("api", "eth", ...)
hoạt động trở lại.
function toAmount(s, decimals) {
return Number((BigDecimal(BigInt(s)) / BigDecimal(Math.pow(10, decimals))).toString())
}
function main() {
let walletAddress = exchange.IO("address")
Log("Testnet goerli wallet address:", walletAddress)
/**
* eth_getTransactionCount
* @param address - string - The address from which the transaction count to be checked.
* @param blockNumber - string - The block number as a string in hexadecimal format or tags.
* @returns The integer of the number of transactions sent from an address encoded as hexadecimal.
*/
let nonce: string = exchange.IO("api", "eth", "eth_getTransactionCount", walletAddress, "pending")
Log("wallet address:", walletAddress, "current nonce:", nonce, ", convert to decimal:", toAmount(nonce, 0))
}
Trước khi giải thích hoạt động chuyển tiền, chúng ta hãy hiểu một số khái niệm. Khi chuyển tiền trên Ethereum, một số lượng token ETH nhất định sẽ được tiêu thụ (như phí khí đốt). Phí khí đốt được xác định bởi hai thông số:
gas Giá
Tuy nhiên, phí khí trên mạng Ethereum luôn dao động theo nhu cầu thị trường và phí người dùng sẵn sàng trả, vì vậy viết phí khí cố định trong mã đôi khi không phải là một lựa chọn lý tưởng.eth_gasPrice
phương pháp chúng tôi đã học trước đây, mà có thể có được giá trung bình của khí đốt.
gasLimit
Một chuyển Ether tiêu chuẩn có giới hạn khí 21.000 đơn vị.
Sau khi hiểu các khái niệm củanonce
, gasPrice
, vàgasLimit
FMZ cung cấp một chức năng chuyển giao rất đơn giản và dễ sử dụng.
exchange.IO("api", "eth", "send", toAddress, toAmount)
Khi nó được sử dụng cho chuyển khoản, tham số thứ ba củaexchange.IO
được cố định là toAddress
tham số là địa chỉ nhận ETH trong quá trình chuyển tiền, vàtoAmount
là số tiền ETH được chuyển.
Các thông sốnonce
, gasPrice
, vàgasLimit
Tất cả có thể sử dụng các giá trị mặc định của hệ thống được lấy tự động trên FMZ. Chúng cũng có thể được chỉ định:
exchange.IO("api", "eth", "send", toAddress, toAmount, {gasPrice: 5000000000, gasLimit: 21000, nonce: 100})
Tiếp theo, chúng ta sẽ chuyển một số lượng nhất định của ETH đến một địa chỉ cụ thể trên mạng lưới thử nghiệm Goerli:
function toInnerAmount(s, decimals) {
return (BigDecimal(s)*BigDecimal(Math.pow(10, decimals))).toFixed(0)
}
function main() {
let walletAddress = exchange.IO("address")
Log("Testnet goerli wallet address:", walletAddress)
let ret = exchange.IO("api", "eth", "send", "0x4D75a08E870674E68cAE611f329A27f446A66813", toInnerAmount(0.01, 18))
return ret // return Transaction Hash : 0xa6f9f51b00d8ae850b0f204380b59da98f4bbce34b813577d3d948f61de4734e
}
Bởi vì đơn vị của số tiền chuyển giao Ethereum làwei
, một chức năng tùy chỉnhtoInnerAmount
cần được sử dụng để xử lý giá trị trongwei
units.
Query Transaction Hash:0xa6f9f51b00d8ae850b0f204380b59da98f4bbce34b813577d3d948f61de4734e
trênhttps://etherscan.io/
.
Bạn cũng có thể viết mã để truy vấn chuyển hash0xa6f9f51b00d8ae850b0f204380b59da98f4bbce34b813577d3d948f61de4734e
, sử dụngeth_getTransactionReceipt
phương pháp cho các truy vấn.
function main() {
let transHash = "0xa6f9f51b00d8ae850b0f204380b59da98f4bbce34b813577d3d948f61de4734e"
let info = exchange.IO("api", "eth", "eth_getTransactionReceipt", transHash)
return info
}
Kết quả truy vấn:
{
"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ô tả tương ứng với mỗi trường:
blockHash - The hash value of the block where the transaction is located.
blockNumber - The block number of the block where the transaction is located, encoded in hexadecimal.
contractAddress - If it's a contract creation, the address of the contract; otherwise null.
cumulativeGasUsed - The total gas used when executing this transaction in the block.
effectiveGasPrice - Total base fee plus tip per unit of gas.
from - Sender's address.
gasUsed - Gas used by this specific transaction.
logs - Array of log objects generated by this transaction.
address - Address that generated this log.
topics - Data array with 0 to 4 indexed log parameters, each with 32 bytes. In Solidity, first topic is event signature hash (e.g., Deposit(address,bytes32,uint256)), unless you declare an event using anonymous specifier.
data - Non-indexed parameters for logs with length of 32 bytes.
blockNumber - The block number of the block where this log is located.
transactionHash - Transaction hash at time when log was created. Null if pending state.
transactionIndex - Index position during creation. Null if pending state.
blockHash - The hash value for containing block.
logIndex - Hexadecimal-encoded integer index position within containing block. Null if pending state.
removed - True if deleted due to chain reorganization; false for valid logs.
logsBloom - Bloom filter for retrieving related logs.
status - Hexadecimal-encoded value either being '1' (success) or '0' (failure).
to - Receiving party's address; null for contract creation transactions.
transactionHash - The hash value associated with given transaction.
transactionIndex - Hexadecimal-encoded index position within its respective containing-block.
type - Type value.
Trong chương về Read
phương pháp, và gọi các phương pháp này không yêu cầugas
Trong chương này, chúng ta sẽ gọi một sốWrite
phương pháp hợp đồng thông minh trên Ethereum và trả tiền chogas
Những hoạt động này sẽ được xác minh bởi mỗi nút và thợ mỏ trong toàn bộ mạng và thay đổi trạng thái blockchain.
Đối với hợp đồng ERC20, nền tảng FMZ liệt kê ABI của hợp đồng ERC20 ABI như một ABI chung được tích hợp trực tiếp vào hệ thống, loại bỏ bước đăng ký ABI.
Để hiểu rõ hơn ABI, bạn có thể kiểm tra nó trước khi sử dụng nó.
[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"guy","type":"address"},{"name":"wad","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"src","type":"address"},{"name":"dst","type":"address"},{"name":"wad","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"wad","type":"uint256"}],"name":"withdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"dst","type":"address"},{"name":"wad","type":"uint256"}],"name":"tran