0000000000164f2434262e1cc",
We can see that there are various events in the logs data, if we only care about ```Transfer``` events, we need to filter out the ```Transfer``` events in these data.
### Retrieving Logs
The Ethereum log is divided into two parts: 1. ```topics```; 2. ```data```.
- ```topics```
Taking the results of the code run for the ```eth_getLogs``` section test as an example, the data in the ```topics``` field is:
```desc
"topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x00000000000000000000000012b791bb27b3a4ee958b5a435fea7d49ec076e9c", "0x000000000000000000000000ef1c6e67703c7bd7107eed8303fbe6ec2554bf6b"],
मूल्यtopics
फ़ील्ड एक सरणी संरचना है जिसका उपयोग घटना का वर्णन करने के लिए किया जाता है। यह निर्दिष्ट किया गया है कि इसकी (सरणी) लंबाई 4 से अधिक नहीं हो सकती है और पहला तत्व घटना का हस्ताक्षर हैश है।
एफएमजेड क्वांट ट्रेडिंग प्लेटफॉर्म में, हम इस हस्ताक्षर हैश का उपयोग करके गणना कर सकते हैंEncode
निम्नलिखित कोड का प्रयोग करके कार्य करें:
function main() {
var eventFunction = "Transfer(address,address,uint256)"
var eventHash = Encode("keccak256", "string", "hex", eventFunction)
Log("eventHash:", "0x" + eventHash)
// eventHash: 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
}
की गणना करेंkeccak256
का हैश मान (हेक्स कोडिंग)Transfer(address,address,uint256)
है0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
.
मूल्यtopics
क्षेत्र क्रमशः दूसरे तत्व और तीसरे तत्व के साथ एक सरणी संरचना हैः
भेजने का पताfrom
प्राप्त करने का पताto
data
डेटा मेंdata
फ़ील्ड हैंः
"data": "0x0000000000000000000000000000000000000000000000000164f2434262e1cc",
कुछ पैरामीटर (स्मार्ट कॉन्ट्रैक्ट के सॉलिडिटी कोड में अनुक्रमित घोषणाओं के बिना पैरामीटर) को स्मार्ट कॉन्ट्रैक्ट में संग्रहीत किया जाता है।data
section.
डेटा को पार्स करें0x0000000000000000000000000000000000000000000000000164f2434262e1cc
function toAmount(s, decimals) {
return Number((BigDecimal(BigInt(s)) / BigDecimal(Math.pow(10, decimals))).toString())
}
function main() {
var value = "0x0000000000000000000000000000000000000000000000000164f2434262e1cc"
Log(toAmount(value, 0) / 1e18) // 0.10047146239950075
}
यह आंकड़ा 0.10047146239950075 के रूप में प्राप्त होता है औरdata
संबंधित हस्तांतरण राशि है।
उपरोक्त समझाया गया था, अभ्यास किया और जाने के लिए तैयार है. हम लॉग पुनर्प्राप्त करने के लिए शुरू कर सकते हैंः
function toAmount(s, decimals) {
return Number((BigDecimal(BigInt(s)) / BigDecimal(Math.pow(10, decimals))).toString())
}
function toInnerAmount(n, decimals) {
return (BigDecimal(n) * BigDecimal(Math.pow(10, decimals))).toFixed(0)
}
function main() {
// getBlockNumber
var blockNumber = exchange.IO("api", "eth", "eth_blockNumber")
Log("blockNumber:", blockNumber)
// get logs
var fromBlock = "0x" + (toAmount(blockNumber, 0) - 1).toString(16)
var toBlock = "0x" + toAmount(blockNumber, 0).toString(16)
var params = {
"fromBlock" : fromBlock,
"toBlock" : toBlock,
"address" : "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
}
var logs = exchange.IO("api", "eth", "eth_getLogs", params)
// Traverse logs
var eventFunction = "Transfer(address,address,uint256)"
var eventHash = "0x" + Encode("keccak256", "string", "hex", eventFunction)
Log("eventHash:", eventHash)
var counter = 0
for (var i = logs.length - 1; i >= 0 && counter < 10; i--) {
if (logs[i].topics[0] == eventHash) {
Log("Event Transfer, data:", toAmount(logs[i].data, 0) / 1e18, ", blockNumber:", toAmount(logs[i].blockNumber, 0), ", transactionHash:", logs[i].transactionHash,
", log:", logs[i])
counter++
}
}
}
जाँच करेंhttps://etherscan.io/
:
FMZ डिबगिंग टूल में चलाए गए परीक्षण कोड के परिणामः
डेटा मेंfrom
, to
फ़ील्ड को पुनः प्राप्ति के समय आवश्यकताओं के आधार पर भी पार्स किया जा सकता है, जैसेः
function main() {
var from = "0x00000000000000000000000012b791bb27b3a4ee958b5a435fea7d49ec076e9c"
var address = "0x" + exchange.IO("encodePacked", "address", from)
Log("address:", address)
}
परिचालन परिणाम:
पताः 0x12b791bb27b3a4ee958b5a435fea7d49ec076e9c
के बाद सेडिबगिंग उपकरणयह केवल कोड को थोड़े समय के लिए परीक्षण कर सकता है और कोड निष्पादन पूरा होने के बाद ही सामग्री को आउटपुट कर सकता है, यह वास्तविक समय में लॉग प्रदर्शित और आउटपुट नहीं कर सकता है। इस खंड में, हम परीक्षण के लिए लाइव ट्रेडिंग बनाने के लिए FMZ क्वांट ट्रेडिंग प्लेटफॉर्म का उपयोग करते हैं।
यहाँ हम एथेरियम मुख्यनेट का उपयोग करते हैं, और हम सुनते हैंTransfer(address,address,uint256)
घटना कीUSDT
क्रिप्टोक्यूरेंसी अनुबंध. हम पिछले पाठ में सीखा है के आधार पर, हम डिजाइन और एक निश्चित स्मार्ट अनुबंध की घटनाओं को लगातार सुनने का एक उदाहरण लिखा हैः
function toAmount(s, decimals) {
return Number((BigDecimal(BigInt(s)) / BigDecimal(Math.pow(10, decimals))).toString())
}
function toInnerAmount(n, decimals) {
return (BigDecimal(n) * BigDecimal(Math.pow(10, decimals))).toFixed(0)
}
function addEventListener(contractAddress, event, callBack) {
var self = {}
self.eventHash = "0x" + Encode("keccak256", "string", "hex", event)
self.contractAddress = contractAddress
self.latestBlockNumber = 0
self.fromBlockNumber = 0
self.firstBlockNumber = 0
/* TODO: test
self.isFirst = true
*/
self.getBlockNumber = function() {
var maxTry = 10
for (var i = 0; i < maxTry; i++) {
var ret = exchange.IO("api", "eth", "eth_blockNumber")
if (ret) {
return toAmount(ret, 0)
}
Sleep(5000)
}
throw "getBlockNumber failed"
}
self.run = function() {
var currBlockNumber = self.getBlockNumber()
var fromBlock = "0x" + self.fromBlockNumber.toString(16)
var toBlock = "0x" + currBlockNumber.toString(16)
var params = {
"fromBlock" : fromBlock,
"toBlock" : toBlock,
"address" : self.contractAddress,
"topics" : [self.eventHash]
}
// Log("fromBlockNumber:", self.fromBlockNumber, ", currBlockNumber:", currBlockNumber, "#FF0000")
var logs = exchange.IO("api", "eth", "eth_getLogs", params)
if (!logs) {
return
}
for (var i = 0; i < logs.length; i++) {
if (toAmount(logs[i].blockNumber, 0) > self.latestBlockNumber) {
/* TODO: test
if (self.isFirst) {
self.firstBlockNumber = toAmount(logs[i].blockNumber, 0)
Log("firstBlockNumber:", self.firstBlockNumber)
self.isFirst = false
}
*/
callBack(logs[i])
}
}
self.latestBlockNumber = currBlockNumber
self.fromBlockNumber = self.latestBlockNumber - 1
}
self.latestBlockNumber = self.getBlockNumber()
self.fromBlockNumber = self.latestBlockNumber - 1
return self
}
var listener = null
function main() {
var event = "Transfer(address,address,uint256)"
var contractAddress = "0xdac17f958d2ee523a2206206994597c13d831ec7"
var decimals = exchange.IO("api", contractAddress, "decimals")
Log(exchange.IO("api", contractAddress, "name"), " decimals:", decimals)
listener = addEventListener(contractAddress, event, function(log) {
var fromAddress = "0x" + exchange.IO("encodePacked", "address", log.topics[1])
var toAddress = "0x" + exchange.IO("encodePacked", "address", log.topics[2])
Log("Transfer:", fromAddress, "->", toAddress, ", value:", toAmount(log.data, decimals), ", blockNumber:", toAmount(log.blockNumber, 0))
/* TODO: test
arrLog.push(log)
*/
})
while (true) {
listener.run()
Sleep(5000)
}
}
/* TODO: test
var arrLog = []
function onexit() {
Log("End the run and verify the record")
var firstBlockNumber = listener.firstBlockNumber
var endBlockNumber = listener.latestBlockNumber
Log("getLogs, from:", firstBlockNumber, " -> to:", endBlockNumber)
var fromBlock = "0x" + (firstBlockNumber).toString(16)
var toBlock = "0x" + (endBlockNumber).toString(16)
var params = {
"fromBlock" : fromBlock,
"toBlock" : toBlock,
"topics" : ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],
"address" : "0xdac17f958d2ee523a2206206994597c13d831ec7"
}
var logs = exchange.IO("api", "eth", "eth_getLogs", params)
Log("arrLog:", arrLog.length)
Log("logs:", logs.length)
if (arrLog.length != logs.length) {
Log("Length varies!")
return
}
for (var i = 0; i < arrLog.length; i++) {
Log("Determine the blockNumber:", logs[i].blockNumber == arrLog[i].blockNumber, ", Determine from:", logs[i].topics[1] == arrLog[i].topics[1],
"Determine to:", logs[i].topics[2] == arrLog[i].topics[2])
}
}
*/
लाइव ट्रेडिंग पर चल रहा हैः
निष्पादन परिणामों के लिए कोड में एक सत्यापन अनुभाग (TODO: test) भी लिखा जाता है। एक साधारण सत्यापन के बाद यह देखा जा सकता है किTransfer
USDT अनुबंध की घटना की निरंतर निगरानी की जाती है और डेटा दर्ज किया जाता है और इन आंकड़ों और एक बार में प्राप्त घटना डेटा की तुलना करके यह देखा जा सकता है कि डेटा निम्न के अनुरूप हैः
पिछले पाठ के आधार परListening to contract events
, हम सुनने की प्रक्रिया के लिए फ़िल्टर जोड़कर विस्तार करते हैं और निर्दिष्ट पते से स्थानांतरण के लिए सुनते हैं। जब एक स्मार्ट अनुबंध एक लॉग बनाता है (यानी एक घटना जारी करता है), लॉग डेटाtopics
जानकारी के 4 टुकड़े तक शामिल है. तो हम एक फिल्टर नियम के साथ डिजाइन[[A1, A2, ...An], null, [C1], D]
उदाहरण के रूप में।
[A1, A2, ...An]
स्थिति पर डेटा से मेल खाता हैtopics[0]
.Null
स्थिति पर डेटा से मेल खाता हैtopics[1]
.[C1]
स्थिति पर डेटा से मेल खाता हैtopics[2]
.D
स्थिति पर डेटा से मेल खाता हैtopics[3]
.null
इसका मतलब है कि यह फ़िल्टर नहीं किया गया है, जैसेnull
से मेल खाती हैtopics[1]
और किसी भी मूल्य मेल खाती है।[C1]
से मेल खाती हैtopics[2]
याD
से मेल खाती हैtopics[3]
, और असंगत लॉग फ़िल्टर किए जाते हैं।[A1, A2, ...An]
से मेल खाती हैtopics[0]
, [A1, A2, ...An]
उनमें से किसी एक के साथ मेल खाता हैtopics[0]
, तो लॉग्स को फ़िल्टर नहीं किया जाएगा।एक्सचेंजों से यूएसडीटी हस्तांतरण सुनना
निगरानीUSDT
बिनेंस एक्सचेंज से और उस पर स्थानांतरित लेनदेनः
function toAmount(s, decimals) {
return Number((BigDecimal(BigInt(s)) / BigDecimal(Math.pow(10, decimals))).toString())
}
function toInnerAmount(n, decimals) {
return (BigDecimal(n) * BigDecimal(Math.pow(10, decimals))).toFixed(0)
}
function addEventListener(contractAddress, event, callBack) {
var self = {}
self.eventHash = "0x" + Encode("keccak256", "string", "hex", event)
self.contractAddress = contractAddress
self.latestBlockNumber = 0
self.fromBlockNumber = 0
self.firstBlockNumber = 0
self.filters = []
self.setFilter = function(filterCondition) {
if (filterCondition.length > 4) {
throw "filterCondition error"
}
self.filters.push(filterCondition)
Log("Set filter conditions:", filterCondition)
}
self.getTokenBalanceOfWallet = function(walletAddress, tokenAddress, tokenDecimals) {
var balance = exchange.IO("api", tokenAddress, "balanceOf", walletAddress)
if (balance) {
return toAmount(balance, tokenDecimals)
}
return null
}
self.getBlockNumber = function() {
var maxTry = 10
for (var i = 0; i < maxTry; i++) {
var ret = exchange.IO("api", "eth", "eth_blockNumber")
if (ret) {
return toAmount(ret, 0)
}
Sleep(5000)
}
throw "getBlockNumber failed"
}
self.run = function() {
var currBlockNumber = self.getBlockNumber()
var fromBlock = "0x" + self.fromBlockNumber.toString(16)
var toBlock = "0x" + currBlockNumber.toString(16)
var params = {
"fromBlock" : fromBlock,
"toBlock" : toBlock,
"address" : self.contractAddress,
"topics" : [self.eventHash]
}
var logs = exchange.IO("api", "eth", "eth_getLogs", params)
if (!logs) {
return
}
for (var i = 0; i < logs.length; i++) {
if (toAmount(logs[i].blockNumber, 0) > self.latestBlockNumber) {
// Check the filter condition, and execute the judgment if the filter condition is set
if (self.filters.length != 0) {
// Initial filter marker
var isFilter = true
// Traverse filter condition setting
for (var j = 0; j < self.filters.length; j++) {
// Take a filter setting, e.g: [[A1, A2, ...An], null, [C1], D]
var cond = self.filters[j]
// Traverse the filter setting
var final = true
for (var topicsIndex = 0; topicsIndex < cond.length; topicsIndex++) {
// Take one of the conditions in the filter setting, if it is the first condition: i.e. the data to be compared with topics[0]
var condValue = cond[topicsIndex]
// Data in the logs
if (topicsIndex > logs[i].topics.length - 1) {
continue
}
var topicsEleValue = logs[i].topics[topicsIndex]
// If it's a Transfer event, you need to handle the from and to
if (logs[i].topics[0] == "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef") {
if (topicsIndex == 1 || topicsIndex == 2) {
topicsEleValue = "0x" + exchange.IO("encodePacked", "address", topicsEleValue)
}
}
// If the condValue type is an array, it means that there are multiple comparison conditions in this position, and the multiple condition comparison is a logical or relationship
if (Array.isArray(condValue) && condValue.length > 1) {
// Determine condValue[0] == topicsEleValue || condValue[1] == topicsEleValue
final = final && condValue.some(element => element === topicsEleValue)
}else if (condValue === null) {
final = final && true
} else {
final = final && (condValue === topicsEleValue)
}
}
if (final) {
isFilter = false
}
}
if (isFilter) {
continue
}
}
callBack(logs[i])
}
}
self.latestBlockNumber = currBlockNumber
self.fromBlockNumber = self.latestBlockNumber - 1
}
self.latestBlockNumber = self.getBlockNumber()
self.fromBlockNumber = self.latestBlockNumber - 1
return self
}
var listener = null
function main() {
// Initial clean-up log
LogReset(1)
LogProfitReset()
var event = "Transfer(address,address,uint256)" // Listening to events
var contractAddress = "0xdac17f958d2ee523a2206206994597c13d831ec7" // USDT contract address
var decimals = exchange.IO("api", contractAddress, "decimals") // Get the precision information of USDT token
var accountBinanceAddress = "0x28C6c06298d514Db089934071355E5743bf21d60" // Binance hot wallet address
accountBinanceAddress = accountBinanceAddress.toLowerCase() // Addresses are handled in lowercase
Log(exchange.IO("api", contractAddress, "name"), " decimals:", decimals)
// Creating a listener object
listener = addEventListener(contractAddress, event, function(log) {
var fromAddress = "0x" + exchange.IO("encodePacked", "address", log.topics[1])
var toAddress = "0x" + exchange.IO("encodePacked", "address", log.topics[2])
if (fromAddress == accountBinanceAddress) {
Log("Binance transfer out - ", " Transfer:", fromAddress, "->", toAddress, ", value:", toAmount(log.data, decimals), ", blockNumber:", toAmount(log.blockNumber, 0), "#CD32CD")
} else if (toAddress == accountBinanceAddress) {
Log("Binance transfer in - ", " Transfer:", fromAddress, "->", toAddress, ", value:", toAmount(log.data, decimals), ", blockNumber:", toAmount(log.blockNumber, 0), "#FF0000")
}
})
// Set up event filtering
listener.setFilter([null, accountBinanceAddress, null]) // Binance -> USDT
listener.setFilter([null, null, accountBinanceAddress]) // USDT -> Binance
var preBalance = 0
while (true) {
listener.run()
var balance = listener.getTokenBalanceOfWallet(accountBinanceAddress, contractAddress, decimals)
if (balance) {
var direction = ""
if (preBalance != 0 && preBalance > balance) {
direction = " ↓ " + (preBalance - balance) + "#CD32CD"
} else if (preBalance != 0 && preBalance < balance) {
direction = " ↑ " + (balance - preBalance) + "#FF0000"
}
Log("Binance wallet address:", accountBinanceAddress, " balance:", balance, direction)
LogProfit(balance, "&") // Drawing only, no log printing
preBalance = balance
}
LogStatus(_D(), "Binance wallet address:", accountBinanceAddress, ", balance:", balance)
Sleep(5000 * 3)
}
}
उपरोक्त कोड लाइव ट्रेडिंग में चल रहा हैः
इस पाठ में, हम कैसे एक घटना फिल्टर डिजाइन करने के लिए पेश किया है. और इसका उपयोग करने के लिए सुनने के लिएUSDT
आप संशोधित कर सकते हैं और इस नमूना कार्यक्रम को विस्तार करने के लिए किसी भी घटना आप में रुचि रखते हैं सुनने के लिए, क्या नए लेनदेन देखने के लिएsmart money
किया है, क्या नए आइटमNFT
टाइकूनों ने दौड़ लगाई है, आदि।
एथेरियम से संबंधित कई गणनाओं के मान हैं जो अधिकतम सुरक्षित पूर्णांक से अधिक हैंJavaScript
इसलिए, FMZ क्वांट ट्रेडिंग प्लेटफ़ॉर्म पर कुछ तरीकों की आवश्यकता होती है जो बड़े मूल्यों को संभालने के लिए हैं, जिनका हमने पिछले पाठ्यक्रमों में विशेष रूप से उपयोग किया है और विस्तार से कवर नहीं किया है। यह खंड इस पहलू पर विस्तार से चर्चा करेगा।
अधिकतम सुरक्षित पूर्णांक मुद्रित करेंJavaScript
भाषाः
function main() {
Log("Number.MAX_SAFE_INTEGER:", Number.MAX_SAFE_INTEGER)
}
परिचालन परिणाम:
संख्या.MAX_SAFE_INTEGER: 9007199254740991
एथेरियम में परिभाषित सबसे छोटी इकाई है1wei
, और परिभाषा1Gwei
के बराबर है1000000000 wei
. 1Gwei
वास्तव में एथेरियम से संबंधित गणनाओं में बहुत बड़ी संख्या नहीं है, और कुछ डेटा इससे बहुत बड़ा है। तो इन डेटा के साथ बहुत बड़े मूल्यों आसानी से अधिक हो सकता हैNumber.MAX_SAFE_INTEGER: 9007199254740991
.
एफएमजेड क्वांट ट्रेडिंग प्लेटफॉर्म पर, हम प्लेटफार्मों का उपयोग करते हैंBigInt
इन बहुत बड़े पूर्णांक डेटा का प्रतिनिधित्व करने के लिए ऑब्जेक्ट का उपयोग करें।BigInt()
निर्माण करने के लिएBigInt
आप निर्माण कर सकते हैंBigInt
ऑब्जेक्ट्स को पैरामीटर के रूप में संख्यात्मक, हेक्साडेसिमल संख्यात्मक स्ट्रिंग का उपयोग करते हुए।toString()
विधिBigInt
ऑब्जेक्ट द्वारा एक स्ट्रिंग के रूप में प्रतिनिधित्व किए गए डेटा को आउटपुट करने के लिए।
परियोजनाओं का समर्थनBigInt
उद्देश्य हैंः
+
-
*
/
%
*
निम्नलिखित कोड उदाहरण देखें:
function main() {
// Decimal representation of 1Gwei
var oneGwei = 1000000000
// Decimal to hexadecimal conversion of 1Gwei
var oneGweiForHex = "0x" + oneGwei.toString(16)
Log("oneGwei : ", oneGwei)
Log("oneGweiForHex : ", oneGweiForHex)
// Constructing BigInt objects
Log("1Gwei / 1Gwei : ", (BigInt(oneGwei) / BigInt(oneGweiForHex)).toString(10))
Log("1Gwei * 1Gwei : ", (BigInt(oneGwei) * BigInt(oneGweiForHex)).toString(10))
Log("1Gwei - 1Gwei : ", (BigInt(oneGwei) - BigInt(oneGweiForHex)).toString(10))
Log("1Gwei + 1Gwei : ", (BigInt(oneGwei) + BigInt(oneGweiForHex)).toString(10))
Log("(1Gwei + 1) % 1Gwei : ", (BigInt(oneGwei + 1) % BigInt(oneGweiForHex)).toString(10))
Log("1Gwei ** 2 : ", (BigInt(oneGwei) ** BigInt(2)).toString(10))
Log("The square root of 100 : ", (BigInt(100) ** BigFloat(0.5)).toString(10))
Log("Number.MAX_SAFE_INTEGER : ", BigInt(Number.MAX_SAFE_INTEGER).toString(10))
Log("Number.MAX_SAFE_INTEGER * 2 : ", (BigInt(Number.MAX_SAFE_INTEGER) * BigInt("2")).toString(10))
}
डिबगिंग उपकरण परीक्षणः
2023-06-08 11:39:50 Info Number.MAX_SAFE_INTEGER * 2 : 18014398509481982
2023-06-08 11:39:50 Info Number.MAX_SAFE_INTEGER : 9007199254740991
2023-06-08 11:39:50 Info The square root of 100 : 10
2023-06-08 11:39:50 Info 1Gwei ** 2 : 1000000000000000000
2023-06-08 11:39:50 Info (1Gwei + 1) % 1Gwei : 1
2023-06-08 11:39:50 Info 1Gwei + 1Gwei : 2000000000
2023-06-08 11:39:50 Info 1Gwei - 1Gwei : 0
2023-06-08 11:39:50 Info 1Gwei * 1Gwei : 1000000000000000000
2023-06-08 11:39:50 Info 1Gwei / 1Gwei : 1
2023-06-08 11:39:50 Info oneGweiForHex : 0x3b9aca00
2023-06-08 11:39:50 Info oneGwei : 1000000000
..BigFloat
वस्तु का उपयोग समान रूप से किया जाता हैBigInt
वस्तु को बड़े मूल्यों के साथ फ्लोटिंग बिंदु संख्याओं का प्रतिनिधित्व करने के लिए, और यह जोड़, घटाव, गुणन और विभाजन का भी समर्थन करता है।
दBigFloat
वस्तु का समर्थन करता हैtoFixed()
method.
निम्नलिखित कोड उदाहरण देखें:
function main() {
var pi = 3.14
var oneGwei = "1000000000"
var oneGweiForHex = "0x3b9aca00"
Log("pi + oneGwei : ", (BigFloat(pi) + BigFloat(oneGwei)).toFixed(2))
Log("pi - oneGweiForHex : ", (BigFloat(pi) - BigFloat(oneGweiForHex)).toFixed(2))
Log("pi * 2.0 : ", (BigFloat(pi) * BigFloat(2.0)).toFixed(2))
Log("pi / 2.0 : ", (BigFloat(pi) / BigFloat(2.0)).toFixed(2))
}
डिबगिंग उपकरण परीक्षणः
2023-06-08 13:56:44 Info pi / 2.0 : 1.57
2023-06-08 13:56:44 Info pi * 2.0 : 6.28
2023-06-08 13:56:44 Info pi - oneGweiForHex : -999999996.86
2023-06-08 13:56:44 Info pi + oneGwei : 1000000003.14
..BigDecimal
ऑब्जेक्ट पूर्णांक मानों और फ्लोटिंग बिंदु मानों के साथ संगत है औरBigInt
वस्तु औरBigFloat
वस्तु, और यह भी जोड़, घटाव, गुणा और विभाजन का समर्थन करता है.
निम्नलिखित कोड उदाहरण देखें:
function main() {
var pi = 3.1415
var oneGwei = 1000000000
var oneGweiForHex = "0x3b9aca00"
Log("pi : ", BigDecimal(pi).toFixed(2))
Log("oneGwei : ", BigDecimal(oneGwei).toString())
Log("oneGweiForHex : ", BigDecimal(BigInt(oneGweiForHex)).toString())
Log("BigInt(oneGwei) : ", BigDecimal(BigInt(oneGwei)).toString())
Log("BigFloat(pi) : ", BigDecimal(BigFloat(pi)).toFixed(4))
Log("oneGwei + pi : ", (BigDecimal(oneGwei) + BigDecimal(pi)).toString())
Log("oneGwei - pi : ", (BigDecimal(oneGwei) - BigDecimal(pi)).toString())
Log("2.0 * pi : ", (BigDecimal(2.0) * BigDecimal(pi)).toString())
Log("pi / pi : ", (BigDecimal(pi) / BigDecimal(pi)).toString())
}
डिबगिंग टूल में चल रहा हैः
2023-06-08 14:52:53 Info pi / pi : 1
2023-06-08 14:52:53 Info 2.0 * pi : 6.283
2023-06-08 14:52:53 Info oneGwei - pi : 999999996.8585
2023-06-08 14:52:53 Info oneGwei + pi : 1000000003.1415
2023-06-08 14:52:53 Info BigFloat(pi) : 3.1415
2023-06-08 14:52:53 Info BigInt(oneGwei) : 1e+9
2023-06-08 14:52:53 Info oneGweiForHex : 1e+9
2023-06-08 14:52:53 Info oneGwei : 1e+9
2023-06-08 14:52:53 Info pi : 3.14
निम्नलिखित दो कार्य:toAmount()
, toInnerAmount()
हम कई बार पिछले पाठ्यक्रमों में इस्तेमाल किया है, इन दो कार्यों मुख्य रूप से डेटा परिशुद्धता रूपांतरण के लिए प्रयोग किया जाता है.
function toAmount(s, decimals) {
return Number((BigDecimal(BigInt(s)) / BigDecimal(Math.pow(10, decimals))).toString())
}
function toInnerAmount(n, decimals) {
return (BigDecimal(n) * BigDecimal(Math.pow(10, decimals))).toFixed(0)
}
..toAmount()
फ़ंक्शन एक चर को परिवर्तित करता है (कम करता है)s
परिशुद्धता पैरामीटर के अनुसारdecimals
वेब3 के व्यावहारिक विकास में, अक्सर कुछ चेन हेक्साडेसिमल डेटा से निपटना आवश्यक होता है।
हम अक्सर हमारे पिछले पाठ्यक्रमों में इसका सामना किया है, उदाहरण के लिए,data
क्षेत्र के आंकड़ेTransfer(address,address,uint256)
स्मार्ट कॉन्ट्रैक्ट की घटनाः
{
"data": "0x00000000000000000000000000000000000000000000000001c1a55000000000",
"topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x0000000000000000000000006b75d8af000000e20b7a7ddf000ba900b4009a80", "0x000000000000000000000000bcb095c1f9c3dc02e834976706c87dee5d0f1fb6"],
"transactionHash": "0x27f9bf5abe3148169b4b85a83e1de32bd50eb81ecc52e5af006157d93353e4c4",
"transactionIndex": "0x0",
"removed": false,
"address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
"blockHash": "0x847be24a7b159c292bda030a011dfec89487b70e71eed486969b032d6ef04bad",
"blockNumber": "0x109b1cc",
"logIndex": "0x0"
}
डाटा प्रोसेस करते समय"data": "0x00000000000000000000000000000000000000000000000001c1a55000000000"
, हम उपयोग करते हैंtoAmount()
इस प्रसंस्करण को डेटा क्षेत्र डेटा को पठनीय मानों में परिवर्तित करने का अच्छा काम करने के लिए डिज़ाइन किया गया है।
function toAmount(s, decimals) {
return Number((BigDecimal(BigInt(s)) / BigDecimal(Math.pow(10, decimals))).toString())
}
function main() {
var data = "0x00000000000000000000000000000000000000000000000001c1a55000000000"
Log(toAmount(data, 18)) // Print out 0.12656402755905127
}
1 ईटीएच टोकन, जैसा कि हम जानते हैं, है1e18 wei
, अगर हम एक डेटा प्राप्त126564027559051260
मेंwei
, इसे ईटीएच टोकन में कैसे परिवर्तित करें?
का उपयोग करनाtoAmount(, 18)
समारोह एक बहुत ही सरल रूपांतरण विधि है।toInnerAmount()
कार्य के उल्टे संचालन हैtoAmount()
कार्य (सटीकता के आधार पर, ज़ूम इन), और इन दो कार्यों का उपयोग करके डेटा को परिवर्तित करना आसान है।
जावास्क्रिप्ट भाषा में पूर्णांक मान सुरक्षा सीमा को ध्यान में रखना महत्वपूर्ण है,Number.MAX_SAFE_INTEGER
, और निम्नलिखित उदाहरण डेटा परिवर्तित करते समय एक छिपी हुई समस्या को दर्शाता हैः
function toAmount(s, decimals) {
return Number((BigDecimal(BigInt(s)) / BigDecimal(Math.pow(10, decimals))).toString())
}
function toInnerAmount(n, decimals) {
return (BigDecimal(n) * BigDecimal(Math.pow(10, decimals))).toFixed(0)
}
function main() {
var amount = 0.01
var innerAmount = Number(toInnerAmount(amount, 18))
Log("Number.MAX_SAFE_INTEGER:", Number.MAX_SAFE_INTEGER) // 9007199254740991
Log("innerAmount:", innerAmount) // 10000000000000000
Log("typeof(innerAmount):", typeof(innerAmount), ", innerAmount:", innerAmount)
// Decimal value 10000000000000000 -> Hexadecimal value 0x2386f26fc10000
Log("Convert", innerAmount, "to hexadecimal:", innerAmount.toString(16))
Log("Convert", BigInt(10000000000000000).toString(10), "to hexadecimal:", BigInt(10000000000000000).toString(16))
Log("0x" + BigInt(10000000000000000).toString(16), "Convert to decimal:", toAmount("0x" + BigInt(10000000000000000).toString(16), 0))
}
डिबगिंग टूल में चलाना संभव हैः
2023-06-15 16:21:40 Info Convert 0x2386f26fc10000 to decimal: 10000000000000000
2023-06-15 16:21:40 Info Convert 10000000000000000 to hexadecimal: 2386f26fc10000
2023-06-15 16:21:40 Info Convert 10000000000000000 to hexadecimal: 10000000000000000
2023-06-15 16:21:40 Info typeof(innerAmount): number , innerAmount: 10000000000000000
2023-06-15 16:21:40 Info innerAmount: 10000000000000000
2023-06-15 16:21:40 Info Number.MAX_SAFE_INTEGER: 9007199254740991
अवलोकन के माध्यम से हमने पाया कि:
Log("Convert", innerAmount, "to hexadecimal:", innerAmount.toString(16))
कोड की यह पंक्ति लॉग आउटपुट से मेल खाती हैःConverting 10000000000000000 to hex: 10000000000000000
, जो सही ढंग से परिवर्तित नहीं है। कारण स्वाभाविक रूप से है कि 10000000000000000 से परे हैNumber.MAX_SAFE_INTEGER
.
लेकिन जब दशमलव मूल्य सुरक्षित सीमा के भीतर है, यानी, से कमNumber.MAX_SAFE_INTEGER
,toString(16)
फ़ंक्शन इसे ठीक से फिर से परिवर्तित करता है, उदाहरण के लिएः
function main() {
var value = 1000
Log("Convert value to hexadecimal:", "0x" + value.toString(16)) // 0x3e8
Log("Convert 0x3e8 to decimal:", Number("0x3e8")) // 1000
}
ब्लॉकचेन में, यहां तक कि0.01
ईटीएच का मूल्य में रूपांतरण10000000000000000
मेंwei
से अधिक होगाNumber.MAX_SAFE_INTEGER``, so a safer conversion for such cases is:
BigInt ((10000000000000000).toString ((16) ``.
लेन-देन निष्पादित करना औरWrite
एथेरियम पर स्मार्ट कॉन्ट्रैक्ट्स की विधि की लागत एक निश्चित मात्रा में गैस है और कभी-कभी यह विफल हो जाती है। यह जानना महत्वपूर्ण है कि कौन से लेनदेन उन्हें भेजने और उन्हें कॉल करने से पहले विफल होने की संभावना है। परीक्षण के लिए एथेरियम पर अनुकरण कॉल हैं।
एथेरियम की आरपीसी विधिeth_call
: यह एक लेनदेन का अनुकरण कर सकता है और एक संभावित लेनदेन का परिणाम लौटा सकता है, लेकिन यह वास्तव में ब्लॉकचेन पर लेनदेन निष्पादित नहीं करता है।
..eth_call
विधि में 2 पैरामीटर हैं, पहला एक शब्दकोश संरचना है,transactionObject
:
// transactionObject
{
"from" : ..., // The address from which the transaction is sent
"to" : ..., // The address to which the transaction is addressed
"gas" : ..., // The integer of gas provided for the transaction execution
"gasPrice" : ..., // The integer of gasPrice used for each paid gas encoded as hexadecimal
"value" : ..., // The integer of value sent with this transaction encoded as hexadecimal
"data" : ..., // The hash of the method signature and encoded parameters. For more information, see the Contract ABI description in the Solidity documentation
}
दूसरा पैरामीटर हैblockNumber
: आप लेबल पास कर सकते हैंlatest/pending/earliest
, आदि:
/* blockNumber
The block number in hexadecimal format or the string latest, earliest, pending, safe or
finalized (safe and finalized tags are only supported on Ethereum, Gnosis, Arbitrum,
Arbitrum Nova and Avalanche C-chain), see the default block parameter description in
the official Ethereum documentation
*/
अगला, हम स्मार्ट अनुबंध विधि लेते हैंapprove
औरtransfer
टोकन की कॉलDAI
सिमुलेशन कॉल के लिए एक उदाहरण के रूप में, और निम्नलिखित परीक्षण वातावरण मुख्य एथेरियम नेटवर्क है।
हम सभी परिचित हैंapprove
ERC20 अनुबंधों के लिए विधि, और हमने इसे पिछले पाठ्यक्रमों में अभ्यास किया है। चूंकि ERC20 अनुबंध पहले से ही FMZ प्लेटफॉर्म ABI में निर्मित है, सिमुलेशन द्वारा बुलाए जाने के लिए स्मार्ट अनुबंध के ABI को पंजीकृत करने की आवश्यकता नहीं है।
function main() {
var contractAddressUniswapV3SwapRouterV2 = "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45"
var contractAddress_DAI = "0x6b175474e89094c44da98b954eedeac495271d0f"
var wallet = exchange.IO("address")
// encode approve
var data = exchange.IO("encode", contractAddress_DAI, "approve(address,uint256)",
contractAddressUniswapV3SwapRouterV2, "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
Log("ERC20 token DAI approve encode, data:", data)
var transactionObject = {
"from" : wallet,
"to" : contractAddress_DAI,
// "gasPrice" : "0x" + parseInt("21270894680").toString(16),
// "gas" : "0x" + parseInt("21000").toString(16),
"data" : "0x" + data,
}
var blockNumber = "latest"
var ret = exchange.IO("api", "eth", "eth_call", transactionObject, blockNumber)
Log("ret:", ret)
}
उदाहरण में कोड सबसे पहले कोड करता हैapprove(address,uint256)
विधि और मापदंड, और मापदंड मूल्य0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
केapprove
अधिकृतता स्मार्ट अनुबंध को पते पर दी जाती है0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45
यानी राउटर अनुबंध के लिएUniswap V3
अंत में एथेरियम आरपीसी विधिeth_call
सिमुलेशन के लिए कहा जाता है. आप देख सकते हैं किgasPrice
औरgas
खेतों मेंtransactionObject
मापदंडों को छोड़ दिया जा सकता है।
डिबगिंग टूल चलाया जाता है और सिमुलेशन सफलतापूर्वक अधिकृत करने के लिए अनुमोदित विधि को कॉल करता है (यह वास्तव में अधिकृत नहीं करता है):
2023-06-09 11:58:39 Info ret: 0x0000000000000000000000000000000000000000000000000000000000000001
2023-06-09 11:58:39 Info ERC20 token DAI approve encode, data: 095ea7b300000000000000000000000068b3465833fb72a70ecdf485e0e4c7bd8665fc45ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
कुछ विफलता परिदृश्यों का अनुकरण करना भी संभव है, जब हमgasPrice
औरgas
पैरामीटर, यदि वॉलेट में ईटीएच गैस शुल्क का भुगतान करने के लिए पर्याप्त नहीं है, तो एक त्रुटि की सूचना दी जाएगी::
अपर्याप्त धन
जब गैस की लागत बहुत कम सेट की जाती है, तो एक त्रुटि की सूचना दी जाएगीः
अंतर्निहित गैस बहुत कम हैः 21000 है, 21944 चाहिए (आपूर्ति गैस 21000)
हम ERC20s से परिचित हैंtransfer
विधि, जो आप एक निश्चित बटुआ पते के लिए ERC20 टोकन स्थानांतरित करने की अनुमति देता है, तो चलो Vitalik Buterin के लिए 1000 DAI के एक हस्तांतरण का अनुकरण करने की कोशिश करते हैं।
function toInnerAmount(n, decimals) {
return (BigDecimal(n) * BigDecimal(Math.pow(10, decimals))).toFixed(0)
}
function main() {
var walletVitalik = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
var contractAddress_DAI = "0x6b175474e89094c44da98b954eedeac495271d0f"
var wallet = exchange.IO("address")
// transfer to Vitalik Buterin
var decimals_DAI = exchange.IO("api", contractAddress_DAI, "decimals")
var transferAmount = toInnerAmount(1000, decimals_DAI)
Log("Transfer amount:", 1000, "DAI, use toInnerAmount convert to:", transferAmount)
// encode transfer
var data = exchange.IO("encode", contractAddress_DAI, "transfer(address,uint256)",
walletVitalik, transferAmount)
var transactionObject = {
"from" : wallet,
"to" : contractAddress_DAI,
"data" : "0x" + data,
}
var blockNumber = "latest"
var ret = exchange.IO("api", "eth", "eth_call", transactionObject, blockNumber)
return ret
}
चूंकि मेरे पास इस परीक्षण वॉलेट में डीएआई टोकन नहीं है, इसलिए इसे डिबग टूल में चलाकर अनपेक्षित रूप से निम्नलिखित त्रुटि की सूचना दी गई हैः
निष्पादन उलटा हुआः Dai/अपर्याप्त-वित्तपोषण
Vitalik Buterin के वॉलेट पते की जाँच करेंः0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045
, यह स्पष्ट है कि इस बटुए में डीएआई टोकन है. तो चलो अनुकरण कॉल के हस्तांतरण दिशा को समायोजित करें और वीटालिक बुटेरीन से हमारे लिए 1000 डीएआई के हस्तांतरण का अनुकरण करें.
कोड को संशोधित करें, जहां परिवर्तन मैंने टिप्पणी कीः
function toInnerAmount(n, decimals) {
return (BigDecimal(n) * BigDecimal(Math.pow(10, decimals))).toFixed(0)
}
function main() {
var walletVitalik = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
var contractAddress_DAI = "0x6b175474e89094c44da98b954eedeac495271d0f"
var wallet = exchange.IO("address")
var decimals_DAI = exchange.IO("api", contractAddress_DAI, "decimals")
var transferAmount = toInnerAmount(1000, decimals_DAI)
Log("Transfer amount:", 1000, "DAI, use toInnerAmount convert to:", transferAmount)
// encode transfer
var data = exchange.IO("encode", contractAddress_DAI, "transfer(address,uint256)",
wallet, transferAmount) // Use the wallet variable as a parameter and change the transfer recipient's address to my own
var transactionObject = {
"from" : walletVitalik, // Use the walletVitalik variable as the value of the from field to simulate that the call was made from the Vitalik Buterin's wallet address
"to" : contractAddress_DAI,
"data" : "0x" + data,
}
var blockNumber = "latest"
var ret = exchange.IO("api", "eth", "eth_call", transactionObject, blockNumber)
Log(ret)
}
डिबगिंग उपकरण परीक्षणः
2023-06-09 13:34:31 Info 0x0000000000000000000000000000000000000000000000000000000000000001
2023-06-09 13:34:31 Info Transfer amount: 1000 DAI, use toInnerAmount convert to: 1000000000000000000000
एफएमजेड क्वांट ट्रेडिंग प्लेटफॉर्म का उपयोग करके, लेनदेन के परिणामों का अनुकरण करना आसान है और संभावित रूप से विफल लेनदेन भेजने से गैस शुल्क के अनावश्यक नुकसान से बचें। हमने पाठ्यक्रम के इस अध्याय से उदाहरण कोड का उपयोग किया है ताकि वीटालिक बुटेरीन के बटुए में धन हस्तांतरित करने और वीटालिक बुटेरीन के बटुए में धन हस्तांतरित करने के लिए कॉल का अनुकरण किया जा सके। बेशक इसके लिए कई और उपयोग हैं।eth_call
अपनी कल्पना का उपयोग करें, आप क्या उपयोग करेंगेeth_call
विधि के लिए?
हम जानते हैं कि ईटीएच और बीटीसी जैसे टोकन समरूप टोकन हैं, और आपके बटुए में टोकन मेरे बटुए में टोकन से अलग नहीं है। लेकिन दुनिया में कई चीजें हैं जो समरूप नहीं हैं, जैसे कि अचल संपत्ति, प्राचीन वस्तुएं, आभासी कलाकृति, आदि। इन्हें सार में समरूप टोकन द्वारा दर्शाया नहीं जा सकता है। इसलिए, गैर-समरूप वस्तुओं को अमूर्त करने के लिए ईआरसी 721 मानक है, और एनएफटी और संबंधित अवधारणाएं हैं। तो Ethereum पर तैनात कई स्मार्ट कॉन्ट्रैक्ट्स में से, हम कैसे पहचानते हैं कि कौन से स्मार्ट कॉन्ट्रैक्ट ERC721 मानक स्मार्ट कॉन्ट्रैक्ट हैं?
ERC721 की पहचान करने के लिए सबसे पहले ERC165 मानक को जानना महत्वपूर्ण है।
ERC165 मानक के साथ एक स्मार्ट कॉन्ट्रैक्ट अन्य कॉन्ट्रैक्ट्स की जाँच के लिए अपने द्वारा समर्थित इंटरफेस की घोषणा कर सकता है। एक ERC165 इंटरफेस कॉन्ट्रैक्ट का केवल एक कार्य हैःsupportsInterface(bytes4 interfaceId)
, पैरामीटरinterfaceId
यदि कॉन्ट्रैक्ट इंटरफेसआईडी को लागू करता है तो यह एक बुलियन सही मान लौटाता है, अन्यथा यह एक गलत मान लौटाता है.
यहाँ हम इस बारे में बात करने के लिए जा रहे हैं कि कैसे यहinterfaceId
विशेष रूप से गणना और एन्कोड किया जाता है।
ERC165 मानकएक उदाहरण दिखाता हैः
pragma solidity ^0.4.20;
interface Solidity101 {
function hello() external pure;
function world(int) external pure;
}
contract Selector {
function calculateSelector() public pure returns (bytes4) {
Solidity101 i;
return i.hello.selector ^ i.world.selector;
}
}
अंतरफलक के फ़ंक्शन हस्ताक्षर के लिए (एक फ़ंक्शन नाम और पैरामीटर प्रकारों की सूची से मिलकर) एक असमानता ऑपरेशन करने के लिए, एक ERC165 इंटरफ़ेस अनुबंध के लिए जहां अनुबंध में केवल एक फ़ंक्शन हैः
pragma solidity ^0.4.20;
interface ERC165 {
/// @notice Query if a contract implements an interface
/// @param interfaceID The interface identifier, as specified in ERC-165
/// @dev Interface identification is specified in ERC-165. This function
/// uses less than 30,000 gas.
/// @return `true` if the contract implements `interfaceID` and
/// `interfaceID` is not 0xffffffff, `false` otherwise
function supportsInterface(bytes4 interfaceID) external view returns (bool);
}
इस इंटरफ़ेस के लिए इंटरफ़ेस पहचानकर्ता 0x01ffc9a7 है। आप इसे बाइट्स4 ((keccak256(
supportsInterface(बाइट्स4) ) चलाकर या ऊपर चयनकर्ता अनुबंध का उपयोग करके गणना कर सकते हैं।
फ़ंक्शन हस्ताक्षर की गणना सीधे करें और इसके पहले 4 बाइट्स लेंinterfaceId
.
function main() {
var ret = Encode("keccak256", "string", "hex", "supportsInterface(bytes4)")
Log("supportsInterface(bytes4) interfaceId:", "0x" + ret.slice(0, 8))
}
परीक्षणों को डिबग टूल में चलाया जा सकता हैः
2023-06-13 14:53:35 Info supportsInterface(bytes4) interfaceId: 0x01ffc9a7
यह देखा जा सकता है कि गणना किए गए परिणाम विवरण के अनुरूप हैंERC165 मानक document.
अब आइए ERC721 अनुबंध मानक की इंटरफ़ेस परिभाषा देखें:
interface ERC721 /* is ERC165 */ {
event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);
event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);
event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);
function balanceOf(address _owner) external view returns (uint256);
function ownerOf(uint256 _tokenId) external view returns (address);
function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external payable;
function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;
function transferFrom(address _from, address _to, uint256 _tokenId) external payable;
function approve(address _approved, uint256 _tokenId) external payable;
function setApprovalForAll(address _operator, bool _approved) external;
function getApproved(uint256 _tokenId) external view returns (address);
function isApprovedForAll(address _owner, address _operator) external view returns (bool);
}
यदि हम यह निर्धारित करना चाहते हैं कि क्या एक स्मार्ट कॉन्ट्रैक्ट एक ERC721 कॉन्ट्रैक्ट है, तो सबसे पहले हमेंinterfaceId
ERC721 अनुबंध से पहले हम उपयोग करने की कोशिश कर सकते हैंsupportsInterface(bytes4 interfaceId)
पिछले पाठ्यक्रमों में हमने ERC165 मानक की कुछ अवधारणाओं और गणना के लिए एल्गोरिथ्म से परिचित कराया हैinterfaceId
, और हम सीधे गणना करने के लिए कोड लिखते हैंः
function calcSelector(arrSelector) {
var ret = null
if (Array.isArray(arrSelector)) {
if (arrSelector.length == 1) {
ret = Encode("keccak256", "string", "hex", arrSelector[0])
} else if (arrSelector.length == 0) {
throw "Error: the number of elements in the array is 0"
} else {
var viewEncodeData = null
for (var i = 0; i < arrSelector.length; i++) {
if (i == 0) {
ret = new Uint8Array(Encode("keccak256", "string", "raw", arrSelector[i]))
} else {
viewData = new Uint8Array(Encode("keccak256", "string", "raw", arrSelector[i]))
if (viewData.length != ret.length) {
throw "Error: TypeArray view length is different"
}
for (var index = 0; index < ret.length; index++) {
ret[index] ^= viewData[index]
}
}
}
ret = Encode("raw", "raw", "hex", ret.buffer)
}
} else {
throw "Error: The parameter requires an array type."
}
return "0x" + ret.slice(0, 8)
}
function main() {
// supportsInterface(bytes4): 0x01ffc9a7
// var ret = calcSelector(["supportsInterface(bytes4)"])
// ERC721Metadata: 0x5b5e139f
/*
var arrSelector = [
"name()",
"symbol()",
"tokenURI(uint256)"
]
var ret = calcSelector(arrSelector)
*/
// ERC721: 0x80ac58cd
// /*
var arrSelector = [
"balanceOf(address)",
"ownerOf(uint256)",
"safeTransferFrom(address,address,uint256,bytes)",
"safeTransferFrom(address,address,uint256)",
"transferFrom(address,address,uint256)",
"approve(address,uint256)",
"setApprovalForAll(address,bool)",
"getApproved(uint256)",
"isApprovedForAll(address,address)",
]
var ret = calcSelector(arrSelector)
// */
Log(ret)
}
कोड में निम्नलिखित का प्रयोग किया गया हैEncode()
फलन हस्ताक्षर की गणना के लिए कार्यkeccak256
एल्गोरिथ्म), और उपरोक्त कोड उदाहरण में गणना के लिए, आउटपुट पैरामीटर निर्दिष्टEncode()
कार्य के रूप में"raw"
, फ़ंक्शन लौटाता हैArrayBuffer
प्रकारJavaScript
भाषा।
कार्य करने के लिए^
दो पर (आईसो-या) संचालनArrayBuffer
वस्तुओं, आप एक बनाने की जरूरत हैTypedArray
के आधार पर विचारArrayBuffer
ऑब्जेक्ट, फिर उस में डेटा के माध्यम से पुनरावृत्ति और एक-एक करके iso-or ऑपरेशन निष्पादित करें।
डिबगिंग टूल में चलाएँः
2023-06-13 15:04:09 Info 0x80ac58cd
यह देखा जा सकता है कि गणना किए गए परिणाम में वर्णित के अनुरूप हैंeip-721.
pragma solidity ^0.4.20;
/// @title ERC-721 Non-Fungible Token Standard/// @dev See https://eips.ethereum.org/EIPS/eip-721/// Note: the ERC-165 identifier for this interface is 0x80ac58cd.interface ERC721 /* is ERC165 */ {
/// @dev This emits when ownership of any NFT changes by any mechanism.
/// This event emits when NFTs are created (`from` == 0) and destroyed
/// (`to` == 0). Exception: during contract creation, any number of NFTs
/// may be created and assigned without emitting Transfer. At the time of
/// any transfer, the approved address for that NFT (if any) is reset to none.
event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);
...
ERC721 इंटरफ़ेस आईडी के साथ, हम निर्धारित कर सकते हैं कि एक अनुबंध एक ERC721 मानक अनुबंध है या नहीं। हम उपयोगBAYC
परीक्षण करने के लिए, जो एक अनुबंध है कि ERC721 का पालन करता है। सबसे पहले हम एबीआई रजिस्टर करने की जरूरत है, और हम केवल निम्नलिखित तीन तरीकों कॉल के बाद से हम इन तीन तरीकों रजिस्टर कर सकते हैंः
विशिष्ट कोड इस प्रकार हैं:
function main() {
// Contract address for ERC721, BAYC is used here
var testContractAddress = "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d"
var testABI = `[{
"inputs": [{
"internalType": "bytes4",
"name": "interfaceId",
"type": "bytes4"
}],
"name": "supportsInterface",
"outputs": [{
"internalType": "bool",
"name": "",
"type": "bool"
}],
"stateMutability": "view",
"type": "function"
}, {
"inputs": [],
"name": "symbol",
"outputs": [{
"internalType": "string",
"name": "",
"type": "string"
}],
"stateMutability": "view",
"type": "function"
}, {
"inputs": [],
"name": "name",
"outputs": [{
"internalType": "string",
"name": "",
"type": "string"
}],
"stateMutability": "view",
"type": "function"
}]`
// ERC721 Interface Id, calculated in the previous course
var interfaceId = "0x80ac58cd"
// Register ABI
exchange.IO("abi", testContractAddress, testABI)
// Call the supportsInterface method
var isErc721 = exchange.IO("api", testContractAddress, "supportsInterface", interfaceId)
// Output Information
Log("Contract address:", testContractAddress)
Log("Contract name:", exchange.IO("api", testContractAddress, "name"))
Log("Contract code:", exchange.IO("api", testContractAddress, "symbol"))
Log("Whether the contract is ERC721 standard:", isErc721)
}
परीक्षण डिबगिंग उपकरण में चलाया जा सकता हैः
2023-06-13 16:32:57 Info Whether the contract is ERC721 standard: true
2023-06-13 16:32:57 Info Contract code: BAYC
2023-06-13 16:32:57 Info