संसाधन लोड हो रहा है... लोड करना...

एफएमजेड का उपयोग करके एथेरियम पर आधारित वेब3 विकास के साथ आसानी से आरंभ करें

लेखक:FMZ~Lydia, बनाया गयाः 2023-06-25 09:17:53, अद्यतनः 2024-11-11 22:34:49

0000000000164f2434262e1cc", ट्रांजेक्शन हैश: 0x6aa8d80daf42f442591e7530e31323d05e1d6dd9f9f9b9c102e157d89810c048, पता : 0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2, blockHash: 0xcd3d567c9bd02a4549b1de0dc638ab5523e847c3c156b096424f56c633000fd9 }, { पता : 0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2, blockHash: 0xcd3d567c9bd02a4549b1de0dc638ab5523e847c3c156b096424f56c633000fd9, ब्लॉक संख्या: 0x109b1cd, logIndex: 0xde, हटाया: गलत, topics: [0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65, 0x00000000000000000000ef1c6e67703c7bd7107eed8303fbe6ec2554bf6b], डेटा: 0x0000000000000000000000000000000000000000000000000164f2434262e1cc, ट्रांजेक्शन हैश: 0x6aa8d80daf42f442591e7530e31323d05e1d6dd9f9f9b9c102e157d89810c048, ट्रांजेक्शनइंडेक्स: 0x91 }]


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/:

img

FMZ डिबगिंग टूल में चलाए गए परीक्षण कोड के परिणामः

img

डेटा में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])
    }
}
*/

लाइव ट्रेडिंग पर चल रहा हैः

img

निष्पादन परिणामों के लिए कोड में एक सत्यापन अनुभाग (TODO: test) भी लिखा जाता है। एक साधारण सत्यापन के बाद यह देखा जा सकता है किTransferUSDT अनुबंध की घटना की निरंतर निगरानी की जाती है और डेटा दर्ज किया जाता है और इन आंकड़ों और एक बार में प्राप्त घटना डेटा की तुलना करके यह देखा जा सकता है कि डेटा निम्न के अनुरूप हैः

img

घटना फ़िल्टरिंग

पिछले पाठ के आधार परListening to contract events, हम सुनने की प्रक्रिया के लिए फ़िल्टर जोड़कर विस्तार करते हैं और निर्दिष्ट पते से स्थानांतरण के लिए सुनते हैं। जब एक स्मार्ट अनुबंध एक लॉग बनाता है (यानी एक घटना जारी करता है), लॉग डेटाtopicsजानकारी के 4 टुकड़े तक शामिल है. तो हम एक फिल्टर नियम के साथ डिजाइन[[A1, A2, ...An], null, [C1], D]उदाहरण के रूप में।

  1. [A1, A2, ...An]स्थिति पर डेटा से मेल खाता हैtopics[0].
  2. Nullस्थिति पर डेटा से मेल खाता हैtopics[1].
  3. [C1]स्थिति पर डेटा से मेल खाता हैtopics[2].
  4. 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)
    }
}

उपरोक्त कोड लाइव ट्रेडिंग में चल रहा हैः

img

इस पाठ में, हम कैसे एक घटना फिल्टर डिजाइन करने के लिए पेश किया है. और इसका उपयोग करने के लिए सुनने के लिए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: यह एक लेनदेन का अनुकरण कर सकता है और एक संभावित लेनदेन का परिणाम लौटा सकता है, लेकिन यह वास्तव में ब्लॉकचेन पर लेनदेन निष्पादित नहीं करता है।

..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सिमुलेशन कॉल के लिए एक उदाहरण के रूप में, और निम्नलिखित परीक्षण वातावरण मुख्य एथेरियम नेटवर्क है।

सिमुलेशन कॉल को मंजूरी

हम सभी परिचित हैंapproveERC20 अनुबंधों के लिए विधि, और हमने इसे पिछले पाठ्यक्रमों में अभ्यास किया है। चूंकि 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विधि के लिए?

ERC721 अनुबंधों की पहचान करें

हम जानते हैं कि ईटीएच और बीटीसी जैसे टोकन समरूप टोकन हैं, और आपके बटुए में टोकन मेरे बटुए में टोकन से अलग नहीं है। लेकिन दुनिया में कई चीजें हैं जो समरूप नहीं हैं, जैसे कि अचल संपत्ति, प्राचीन वस्तुएं, आभासी कलाकृति, आदि। इन्हें सार में समरूप टोकन द्वारा दर्शाया नहीं जा सकता है। इसलिए, गैर-समरूप वस्तुओं को अमूर्त करने के लिए ईआरसी 721 मानक है, और एनएफटी और संबंधित अवधारणाएं हैं। तो Ethereum पर तैनात कई स्मार्ट कॉन्ट्रैक्ट्स में से, हम कैसे पहचानते हैं कि कौन से स्मार्ट कॉन्ट्रैक्ट ERC721 मानक स्मार्ट कॉन्ट्रैक्ट हैं?

ERC721 की पहचान करने के लिए सबसे पहले ERC165 मानक को जानना महत्वपूर्ण है।

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

अब आइए 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 कॉन्ट्रैक्ट है, तो सबसे पहले हमेंinterfaceIdERC721 अनुबंध से पहले हम उपयोग करने की कोशिश कर सकते हैं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

संबंधित

अधिक