রিসোর্স লোড হচ্ছে... লোডিং...

এফএমজেড ব্যবহার করে ইথেরিয়ামের উপর ভিত্তি করে সহজেই ওয়েব 3 ডেভেলপমেন্ট দিয়ে শুরু করুন

লেখক:এফএমজেড-লিডিয়া, তৈরিঃ 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], ডাটা: 0x0000000000000000000000000000000000000000000000000000000164f2434262e1cc, লেনদেন হ্যাশ : 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"],  

এর মূল্যtopicsfield একটি অ্যারে কাঠামো যা ইভেন্টটি বর্ণনা করতে ব্যবহৃত হয়। এটি নির্দিষ্ট করা হয়েছে যে এর (অ্যারে) দৈর্ঘ্য 4 এর বেশি হতে পারে না এবং প্রথম উপাদানটি ইভেন্টের স্বাক্ষর হ্যাশ। FMZ কোয়ান্ট ট্রেডিং প্ল্যাটফর্মে, আমরা এই স্বাক্ষর হ্যাশ গণনা করতে পারি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

এফএমজেড ডিবাগিং টুল-এ চালিত পরীক্ষার কোডের ফলাফলঃ

img

তথ্যfrom, toক্ষেত্রগুলি পুনরুদ্ধারের সময় প্রয়োজনীয়তার উপর নির্ভর করে বিশ্লেষণ করা যেতে পারে, উদাহরণস্বরূপঃ

function main() {
    var from = "0x00000000000000000000000012b791bb27b3a4ee958b5a435fea7d49ec076e9c"
    var address = "0x" + exchange.IO("encodePacked", "address", from)
    Log("address:", address)
}

চলমান ফলাফল:

ঠিকানাঃ 0x12b791bb27b3a4ee958b5a435fea7d49ec076e9c

চুক্তির ঘটনা শুনুন

যেহেতুডিবাগিং টুলএই বিভাগে, আমরা এফএমজেড কোয়ান্ট ট্রেডিং প্ল্যাটফর্ম ব্যবহার করি লাইভ ট্রেডিং তৈরি করতে পরীক্ষা করার জন্য।

এখানে আমরা ইথেরিয়াম মেইননেট ব্যবহার করি, এবং আমরা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: পরীক্ষা) কোড লিখিত হয়। একটি সহজ বৈধতা পরে এটি দেখা যায় যেTransferইউএসডিটি কন্ট্রাক্টের ইভেন্টটি ক্রমাগত পর্যবেক্ষণ করা হয় এবং ডেটা রেকর্ড করা হয় এবং এই ডেটা এবং একযোগে প্রাপ্ত ইভেন্ট ডেটাগুলির মধ্যে তুলনা করে দেখা যায় যে ডেটাগুলি নিম্নলিখিতগুলির সাথে সামঞ্জস্যপূর্ণঃ

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ওয়েব৩ এর ব্যবহারিক উন্নয়নে, প্রায়ই কিছু চেইনড হেক্সাডেসিমাল ডেটা নিয়ে কাজ করা প্রয়োজন। আমাদের পূর্ববর্তী কোর্সে আমরা প্রায়ই এর মুখোমুখি হয়েছি, উদাহরণস্বরূপ,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 ETH টোকেন, যেমনটা আমরা জানি,1e18 wei, যদি আমরা একটি তথ্য পেতে126564027559051260মধ্যেwei, কিভাবে এটি ETH টোকেনে রূপান্তর করা যায়? ব্যবহার করে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, যা সঠিকভাবে রূপান্তরিত হয় না। কারণ স্বাভাবিকভাবেই যে 100000000000000000000 অতিক্রম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.01ETH এর মান রূপান্তরিত10000000000000000মধ্যেweiঅতিক্রম করবেNumber.MAX_SAFE_INTEGER``, so a safer conversion for such cases is:বিগ ইন্ট (১০০০০০০০০০০০০০০) স্ট্রিং (১৬) ``

সিমুলেশন কল

লেনদেন সম্পাদন এবংWriteইথেরিয়ামের স্মার্ট কন্ট্রাক্টের পদ্ধতিতে নির্দিষ্ট পরিমাণে গ্যাস খরচ হয় এবং কখনও কখনও এটি ব্যর্থ হয়। এটি পাঠানোর আগে এবং তাদের কল করার আগে কোন লেনদেন ব্যর্থ হওয়ার সম্ভাবনা রয়েছে তা জানা গুরুত্বপূর্ণ। পরীক্ষার জন্য ইথেরিয়ামে সিমুলেটেড কল রয়েছে।

eth_call

ইথেরিয়ামের আরপিসি পদ্ধতিeth_call: এটি একটি লেনদেন সিমুলেট করতে পারে এবং একটি সম্ভাব্য লেনদেনের ফলাফল ফেরত দিতে পারে, কিন্তু এটি আসলে ব্লকচেইনে লেনদেন চালায় না।

দ্যeth_callপদ্ধতিতে দুটি পরামিতি রয়েছে, প্রথমটি একটি অভিধান গঠন,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প্যারামিটার, যদি ওয়ালেটে ETH গ্যাস ফি পরিশোধের জন্য যথেষ্ট না হয়, একটি ত্রুটি রিপোর্ট করা হবে::

পর্যাপ্ত তহবিল নেই

যখন গ্যাসের খরচ খুব কম সেট করা হয়, তখন একটি ত্রুটি রিপোর্ট করা হবেঃ

অভ্যন্তরীণ গ্যাস খুব কমঃ 21000 আছে, 21944 চান (সরবরাহ গ্যাস 21000)

সিমুলেশন কল ট্রান্সফার

আমরা ERC20 এর সাথে পরিচিতtransferপদ্ধতি, যা আপনাকে ERC20 টোকেন একটি নির্দিষ্ট মানিব্যাগ ঠিকানায় স্থানান্তর করতে দেয়, তাই আসুন 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 টোকেন নেই, তাই এটি ডিবাগ টুলের মধ্যে চালানো অপ্রত্যাশিতভাবে নিম্নলিখিত ত্রুটি রিপোর্ট করেছেঃ

বাস্তবায়ন বিপরীতঃ Dai/insufficient-balance

ভিটালিক বুটারিনের মানিব্যাগের ঠিকানা দেখুন:0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045, এটা স্পষ্ট যে এই মানিব্যাগ DAI টোকেন আছে. তাই আসুন অনুকরণ কল স্থানান্তর দিক সামঞ্জস্য এবং 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")

    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 স্ট্যান্ডার্ড রয়েছে এবং এনএফটি এবং সম্পর্কিত ধারণাগুলি রয়েছে। সুতরাং ইথেরিয়ামে প্রয়োগ করা অনেক স্মার্ট কন্ট্রাক্টের মধ্যে, আমরা কীভাবে সনাক্ত করব কোন স্মার্ট কন্ট্রাক্টগুলি ERC721 স্ট্যান্ডার্ড স্মার্ট কন্ট্রাক্ট?

ERC721 সনাক্ত করতে, প্রথমে ERC165 স্ট্যান্ডার্ড জানা গুরুত্বপূর্ণ।

ERC165

ERC165 স্ট্যান্ডার্ডের সাহায্যে একটি স্মার্ট কন্ট্রাক্ট অন্য কন্ট্রাক্টগুলির জন্য এটি সমর্থন করে এমন ইন্টারফেসগুলিকে ঘোষণা করতে পারে। একটি ERC165 ইন্টারফেস কন্ট্রাক্টের কেবলমাত্র একটি ফাংশন রয়েছেঃsupportsInterface(bytes4 interfaceId)প্যারামিটারinterfaceIdis the interface Id to be queried. যদি চুক্তিটি 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 ((bytes4) ) চালিয়ে গণনা করতে পারেন); অথবা উপরে নির্বাচক চুক্তি ব্যবহার করে।

সরাসরি ফাংশন স্বাক্ষর গণনা করুন এবং তার প্রথম 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অবজেক্ট, তারপর এটির মধ্যে থাকা তথ্যের মাধ্যমে পুনরাবৃত্তি করুন এবং একের পর এক আইসো-অথবা অপারেশনটি সম্পাদন করুন।

ডিবাগিং টুল চালানঃ

2023-06-13 15:04:09		Info	0x80ac58cd

এটি দেখা যায় যে গণনা করা ফলাফলগুলিইআইপি-৭২১.

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 স্ট্যান্ডার্ড চুক্তি কিনা। আমরা ব্যবহার করিBAYCERC721 অনুসরণ করে একটি চুক্তি যা পরীক্ষা করতে, প্রথম আমরা ABI নিবন্ধন করতে হবে, এবং যেহেতু আমরা শুধুমাত্র নিম্নলিখিত তিনটি পদ্ধতি কল, আমরা এই তিনটি পদ্ধতি নিবন্ধন করতে পারেনঃ

  • সমর্থন ইন্টারফেস ((ইন্টারফেস আইডি)
  • প্রতীক ((()
  • নাম ((()

নির্দিষ্ট কোডগুলি নিম্নরূপঃ

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

সম্পর্কিত

আরো