وسائل لوڈ ہو رہے ہیں... لوڈنگ...

ایف ایم زیڈ کا استعمال کرتے ہوئے ایتھرون پر مبنی ویب 3 کی ترقی میں آسان تعارف

مصنف:ایجاد کاروں کی مقدار - خواب, تخلیق: 2023-03-28 13:32:48, تازہ کاری: 2024-11-11 22:28:24

بلاک سے: سےبلاک، toBlock: toBlock، ایڈریس : خود معاہدہ topics : [self.eventHash] } // لاگ ((بلاک نمبر:، خود.بلاک نمبر، ، currبلاک نمبر:، currبلاک نمبر، #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 = صفر فنکشن main() { var واقعہ = ٹرانسفر ((ایڈریس،ایڈریس،وینٹ256) var معاہدہایڈریس = 0xdac17f958d2ee523a2206206994597c13d831ec7 var اعشاریہ =exchange.IO("اے پی آئی، معاہدہ، ایڈریس، اعشاریہ) نوشتہ جاتexchange.IO("api", contractAddress, name), " اعشاریہ:", اعشاریہ)

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: ٹیسٹ var arrLog = [] function onexit ((() { لاگ (بلاگ ختم، تصدیق ریکارڈ) 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("长度不等!")
    return 
}

for (var i = 0; i < arrLog.length; i++) {
    Log("判断blockNumber:", logs[i].blockNumber == arrLog[i].blockNumber, ",判断from:", logs[i].topics[1] == arrLog[i].topics[1], 
        "判断to:", logs[i].topics[2] == arrLog[i].topics[2])
}

} */


实盘运行:

![img](/upload/asset/16ffd65adc050d33056d.png)

对于执行结果,代码中也编写了验证部分(TODO: test)。经过简单验证可以看到持续监控USDT合约的```Transfer```事件并且记录数据,用这个数据和一次性获取的事件数据对比可以观察出数据一致:

![img](/upload/asset/16e07390a11a606276b1.png)

### 事件过滤

在上一节课程「监听合约事件」的基础上,我们拓展一下,在监听的过程中增加过滤器,监听指定地址的转入转出。当智能合约创建日志时(即释放事件),日志数据中```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转账**

监控从币安交易所转出、转入币安交易所```USDT```的交易:

```javascript
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("设置过滤条件:", 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) {
                // 检查过滤条件,设置了过滤条件则执行判断
                if (self.filters.length != 0) {
                    // 初始过滤标记
                    var isFilter = true 
                    // 遍历过滤条件设置
                    for (var j = 0; j < self.filters.length; j++) {
                        // 取一个过滤设置,例如:[[A1, A2, ...An], null, [C1], D]
                        var cond = self.filters[j]

                        // 遍历这个过滤设置
                        var final = true
                        for (var topicsIndex = 0; topicsIndex < cond.length; topicsIndex++) {
                            // 拿到这个过滤设置中的某一个条件,如果是第一个条件:即要和topics[0]对比的数据
                            var condValue = cond[topicsIndex]

                            // 日志中的数据
                            if (topicsIndex > logs[i].topics.length - 1) {
                                continue 
                            }
                            var topicsEleValue = logs[i].topics[topicsIndex]
                            // 如果是Transfer事件,需要处理from和to
                            if (logs[i].topics[0] == "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef") {
                                if (topicsIndex == 1 || topicsIndex == 2) {
                                    topicsEleValue = "0x" + exchange.IO("encodePacked", "address", topicsEleValue)
                                }
                            }

                            // 如果condValue类型是数组,表示该位置的对比条件有多个,多个条件对比是逻辑或关系
                            if (Array.isArray(condValue) && condValue.length > 1) {
                                // 判断 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() {
    // 初始清理日志
    LogReset(1)
    LogProfitReset()

    var event = "Transfer(address,address,uint256)"                          // 监听事件
    var contractAddress = "0xdac17f958d2ee523a2206206994597c13d831ec7"       // USDT合约地址
    var decimals = exchange.IO("api", contractAddress, "decimals")           // 获取USDT token的精度信息
    var accountBinanceAddress = "0x28C6c06298d514Db089934071355E5743bf21d60" // Binance 热钱包地址
    accountBinanceAddress = accountBinanceAddress.toLowerCase()              // 地址处理为小写
    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])
        if (fromAddress == accountBinanceAddress) {
            Log("币安转出 - ", " Transfer:", fromAddress, "->", toAddress, ", value:", toAmount(log.data, decimals), ", blockNumber:", toAmount(log.blockNumber, 0), "#CD32CD")
        } else if (toAddress == accountBinanceAddress) {
            Log("转入币安 - ", " Transfer:", fromAddress, "->", toAddress, ", value:", toAmount(log.data, decimals), ", blockNumber:", toAmount(log.blockNumber, 0), "#FF0000")
        }        
    })

    // 设置事件过滤
    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("币安钱包地址:", accountBinanceAddress, " 余额:", balance, direction)
            LogProfit(balance, "&")   // 只画图,不打印日志
            preBalance = balance
        }
        LogStatus(_D(), "币安钱包地址:", accountBinanceAddress, ", 余额:", balance)
        Sleep(5000 * 3)
    }
}

مندرجہ بالا کوڈ اصلی ڈسک پر چلتا ہے:

img

img

اس سیکشن میں ہم نے واقعہ فلٹر کو ڈیزائن کرنے کا طریقہ بتایا ہے۔ اور اس کے ساتھ ہی بئنآن ایکسچینج ہاٹ والیٹس سے متعلق نگرانی کی۔USDTآپ اس مثال کے پروگرام کو تبدیل یا بڑھا سکتے ہیں تاکہ آپ کسی بھی واقعہ کو سننے کے لۓ جو آپ کو دلچسپی رکھتے ہیں، دیکھیں.smart moneyکیا آپ کو معلوم ہے کہ آپ کے ملک میں کیا ہو رہا ہے؟NFTڈیم نے کون سے نئے منصوبے شروع کیے ہیں؟

یونٹ تبادلہ

ایتھرین سے متعلق بہت سے حساب کتاب میں، اعداد و شمار سے زیادہ ہیںJavaScriptزبان کے زیادہ سے زیادہ محفوظ عددی اعداد۔ اس لیے موجد کے مقداری تجارتی پلیٹ فارم پر بڑے عددی اقدار کو سنبھالنے کے لیے کچھ طریقوں کی ضرورت ہوتی ہے، جو کہ ہم نے پچھلے کورسز میں بھی استعمال کیے ہیں اور جن کا تفصیل سے ذکر نہیں کیا گیا ہے۔ اس باب میں اس کے بارے میں تفصیل سے بات کی جائے گی۔

پرنٹنگJavaScriptزبان میں مقرر کردہ زیادہ سے زیادہ محفوظ انٹیجر:

function main() {
    Log("Number.MAX_SAFE_INTEGER:", Number.MAX_SAFE_INTEGER)
}

اس کا نتیجہ:

نمبر.MAX_SAFE_INTEGER: 9007199254740991

بگ انٹ

ایتھرین میں سب سے چھوٹی یونٹ کی وضاحت کی گئی ہے1wei، تعریف1Gweiکے برابر ہے1000000000 wei1Gweiایتھرین کے حساب کتاب میں یہ واقعی ایک بڑی تعداد نہیں ہے ، کچھ اعداد و شمار اس سے کہیں زیادہ بڑے ہیں۔Number.MAX_SAFE_INTEGER: 9007199254740991

اور ہم نے اس کے بارے میں بہت کچھ سیکھا ہے۔BigIntاشیاء کو ان عظیم اعداد و شمار کے اعداد و شمار کی نمائندگی کرنے کے لئے استعمال کیا جاتا ہے؛ تعمیراتی افعالBigInt()تعمیر کرنے کے لئےBigIntاعتراضات۔ عددی، سولہ عددی عددی سٹرنگ کو بطور پیرامیٹر تعمیر کیا جاسکتا ہے۔BigIntاشیاء کا استعمال کریں۔BigIntاشیاءtoString()ایک طریقہ جس میں اعداد و شمار کو ایک تار کی شکل میں ظاہر کیا جاتا ہے.

BigIntاشیاء کی حمایت کی آپریشن:

  • گرافکس کا حساب:+
  • کم کرنے کا طریقہ:-
  • ضرب کا عمل:*
  • اس کے علاوہ:/
  • ماڈل کی تلاش:%
  • آپ نے کیا سوچا؟**

مندرجہ ذیل کوڈ مثالیں ملاحظہ کریں:

function main() {
    // 1Gwei的十进制表示
    var oneGwei = 1000000000

    // 1Gwei的十进制转换为十六进制表示
    var oneGweiForHex = "0x" + oneGwei.toString(16)

    Log("oneGwei : ", oneGwei)
    Log("oneGweiForHex : ", oneGweiForHex)

    // 构造BigInt对象
    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("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		信息	Number.MAX_SAFE_INTEGER * 2 : 18014398509481982
2023-06-08 11:39:50		信息	Number.MAX_SAFE_INTEGER : 9007199254740991
2023-06-08 11:39:50		信息	100 的平方根 : 10
2023-06-08 11:39:50		信息	1Gwei ** 2 : 1000000000000000000
2023-06-08 11:39:50		信息	(1Gwei + 1) % 1Gwei : 1
2023-06-08 11:39:50		信息	1Gwei + 1Gwei : 2000000000
2023-06-08 11:39:50		信息	1Gwei - 1Gwei : 0
2023-06-08 11:39:50		信息	1Gwei * 1Gwei : 1000000000000000000
2023-06-08 11:39:50		信息	1Gwei / 1Gwei : 1
2023-06-08 11:39:50		信息	oneGweiForHex : 0x3b9aca00
2023-06-08 11:39:50		信息	oneGwei : 1000000000

بگ فلوٹ

BigFloatاشیاء اورBigIntآبجیکٹ کا استعمال اسی طرح ہوتا ہے ، جو بڑی عددی تعداد کو ظاہر کرنے کے لئے استعمال ہوتا ہے ، اور ضرب کے آپریشن کو بھی سپورٹ کرتا ہے۔BigFloatاشیاء کی حمایتtoFixed()طریقہ کار۔

مندرجہ ذیل کوڈ مثالیں ملاحظہ کریں:

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		信息	pi / 2.0 : 1.57
2023-06-08 13:56:44		信息	pi * 2.0 : 6.28
2023-06-08 13:56:44		信息	pi - oneGweiForHex : -999999996.86
2023-06-08 13:56:44		信息	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		信息	pi / pi : 1
2023-06-08 14:52:53		信息	2.0 * pi : 6.283
2023-06-08 14:52:53		信息	oneGwei - pi : 999999996.8585
2023-06-08 14:52:53		信息	oneGwei + pi : 1000000003.1415
2023-06-08 14:52:53		信息	BigFloat(pi) : 3.1415
2023-06-08 14:52:53		信息	BigInt(oneGwei) : 1e+9
2023-06-08 14:52:53		信息	oneGweiForHex : 1e+9
2023-06-08 14:52:53		信息	oneGwei : 1e+9
2023-06-08 14:52:53		信息	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




















































































ہم نے پہلے کورسز میں دیکھا ہے کہ اسمارٹ کنٹریکٹ کے بارے میںTransfer(address,address,uint256)واقعات میںdataفیلڈ ڈیٹا:

{
	"data": "0x00000000000000000000000000000000000000000000000001c1a55000000000",
	"topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x0000000000000000000000006b75d8af000000e20b7a7ddf000ba900b4009a80", "0x000000000000000000000000bcb095c1f9c3dc02e834976706c87dee5d0f1fb6"],
	"transactionHash": "0x27f9bf5abe3148169b4b85a83e1de32bd50eb81ecc52e5af006157d93353e4c4",
	"transactionIndex": "0x0",
	"removed": false,
	"address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
	"blockHash": "0x847be24a7b159c292bda030a011dfec89487b70e71eed486969b032d6ef04bad",
	"blockNumber": "0x109b1cc",
	"logIndex": "0x0"
}

ڈیٹا پروسیسنگ"data": "0x00000000000000000000000000000000000000000000000001c1a55000000000"اس وقت استعمال کریںtoAmount()فنکشن۔ اس طرح کے پروسیسنگ ڈیزائن کو اچھی طرح سے استعمال کیا جا سکتا ہےdataفیلڈ ڈیٹا کو پڑھنے کے قابل اقدار میں تبدیل کریں۔

function toAmount(s, decimals) {
    return Number((BigDecimal(BigInt(s)) / BigDecimal(Math.pow(10, decimals))).toString())
}

function main() {
    var data = "0x00000000000000000000000000000000000000000000000001c1a55000000000"
    Log(toAmount(data, 18))  // 打印出 0.12656402755905127
}

ایک ETH ٹوکن ہم جانتے ہیں کہ1e18 weiاور اگر ہم نے ایکweiیونٹ کے اعداد و شمار126564027559051260ای ٹی ایچ ٹوکن کی تعداد میں کیسے تبدیل کیا جائے؟ استعمال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)
    
    // 十进制数值 10000000000000000 -> 十六进制数值 0x2386f26fc10000
    Log("转换", innerAmount, "为十六进制:", innerAmount.toString(16))
    Log("转换", BigInt(10000000000000000).toString(10), "为十六进制:", BigInt(10000000000000000).toString(16))
    
    Log("0x" + BigInt(10000000000000000).toString(16), "转换为10进制:", toAmount("0x" + BigInt(10000000000000000).toString(16), 0))
}

یہ ڈیبگنگ ٹولز میں چل سکتا ہے:

2023-06-15 16:21:40		信息	0x2386f26fc10000 转换为10进制: 10000000000000000
2023-06-15 16:21:40		信息	转换 10000000000000000 为十六进制: 2386f26fc10000
2023-06-15 16:21:40		信息	转换 10000000000000000 为十六进制: 10000000000000000
2023-06-15 16:21:40		信息	typeof(innerAmount): number , innerAmount: 10000000000000000
2023-06-15 16:21:40		信息	innerAmount: 10000000000000000
2023-06-15 16:21:40		信息	Number.MAX_SAFE_INTEGER: 9007199254740991

ہم نے دیکھا کہ:

Log("转换", innerAmount, "为十六进制:", innerAmount.toString(16))

اس کوڈ لائن کے مطابق لاگ آؤٹ پٹ:转换 10000000000000000 为十六进制: 10000000000000000اور اس کی وجہ یہ ہے کہ 10000000000000000 سے زیادہ ہے.Number.MAX_SAFE_INTEGER

لیکن جب اعشاریہ کی تعداد محفوظ حد میں ہے، یعنی اس سے کم ہےNumber.MAX_SAFE_INTEGERاس کے بعد،toString(16)فنکشن کی تبدیلی عام ہے، مثال کے طور پر:

function main() {
    var value = 1000
    Log("把value转换为十六进制:", "0x" + value.toString(16))   // 0x3e8
    Log("把0x3e8转换为十进制:", Number("0x3e8"))               // 1000
}

بلاکچین کے میدان میں، یہاں تک کہ0.01ایک ETH کے بدلے میںweiیونٹ کی تعداد10000000000000000اور اس سے آگے بھی جائیں گےNumber.MAX_SAFE_INTEGERاس طرح کے حالات کے لئے محفوظ ترین تبادلوں میں سے ایک ہے:BigInt(10000000000000000).toString(16)

الیکٹو کال

ایتھرین پر ٹرانزیکشنز انجام دینے، اسمارٹ کنٹریکٹس کو کال کرنے کے لئے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
*/

اگلا، ہم ٹوکن استعمال کرتے ہیں.DAIاسمارٹ کنٹریکٹ کا طریقہapprovetransferمثال کے طور پر ، ایتھروجن نیٹ ورک کے لئے مندرجہ ذیل ٹیسٹ ماحول میں ایک ایل ای ڈی کال ہے۔

اینالاگ کال approve

ERC20 معاہدے کے لئےapproveیہ طریقہ ہم سب سے واقف ہیں اور ہم نے پچھلے کورسز میں بھی اس پر عمل کیا ہے۔ چونکہ 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)اس کے علاوہ، آپ کو اس بات کا یقین کرنے کی ضرورت ہے کہ آپ کو اس کے بارے میں کیا سوچنا ہے.approveطریقہ کار کے پیرامیٹرز کی قدر0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffزیادہ سے زیادہ اختیارات کی تعداد کا اشارہ کرتا ہے۔ اسمارٹ معاہدوں کو اختیارات، ایڈریس0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45یعنیUniswap V3روٹنگ کا معاہدہ۔ آخری بار ایتھرینیم آر پی سی کے طریقہ کار کو کال کریںeth_callہم آپ کو دکھاتے ہیں کہ ہم کیا کر رہے ہیں.transactionObjectپیرامیٹرز میںgasPricegasآپ کو اس کے بارے میں مزید جاننے کی ضرورت ہے۔

ڈیبگنگ کا آلہ چل رہا ہے ، اس طرح کی کال کرنے کے لئے منظور کرنے کا طریقہ کار کو اجازت دینے میں کامیابی (اور اصل میں اجازت نہیں دی گئی):

2023-06-09 11:58:39		信息	ret: 0x0000000000000000000000000000000000000000000000000000000000000001
2023-06-09 11:58:39		信息	ERC20 token DAI approve encode, data: 095ea7b300000000000000000000000068b3465833fb72a70ecdf485e0e4c7bd8665fc45ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff

اور یہ بھی ممکن ہے کہ ہم کچھ ناکام منظرناموں کی نقل کر سکیں، اور جب ہم ان کو ایڈجسٹ کرتے ہیں،gasPriceاورgasاگر آپ کے پاس پیٹرول کی قیمت ادا کرنے کے لئے کافی ETH نہیں ہے تو ، آپ کی پیمائش میں غلطی ہوگی:

ناکافی فنڈز

جب گیس کی قیمت بہت کم ہے تو غلطی ہوتی ہے:

اندرونی گیس بہت کم: 21000 ہے، 21944 چاہتے ہیں (گیس 21000 فراہم کی)

نقل و حمل کو کال کرنے کا نمونہ

ERC20 کے لئےtransferہم نے اس طریقہ کار سے واقف نہیں ہیں، جس میں ERC20 ٹوکن کو کسی پرس کے ایڈریس میں منتقل کیا جاسکتا ہے، اور ہم نے 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")

    // 转账给V神
    var decimals_DAI = exchange.IO("api", contractAddress_DAI, "decimals")
    var transferAmount = toInnerAmount(1000, decimals_DAI)
    Log("转账金额:", 1000, "DAI, 使用 toInnerAmount 转换为:", 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 
}

میرے ٹیسٹ والیٹ میں ڈی اے آئی ٹوکن نہ ہونے کی وجہ سے ، ڈیبگنگ ٹول میں چلنے والے نتائج میں سے ایک میں توقع کی گئی غلطی کی اطلاع دی گئی:

عملدرآمد کی واپسی: ڈائی/ناقص توازن

وی دیوتا کے اس بٹوے کا پتہ دیکھیں:0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045یہ پتہ چلتا ہے کہ یہ بٹوے ڈی اے آئی ٹوکن کے ساتھ ہے۔ تو آئیے ہم متوازی کالوں کے لئے منتقلی کی سمت کو ہم آہنگ کرتے ہیں ، اور V خدا نے ہمیں 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("转账金额:", 1000, "DAI, 使用 toInnerAmount 转换为:", transferAmount)

    // encode transfer
    var data = exchange.IO("encode", contractAddress_DAI, "transfer(address,uint256)",
        wallet, transferAmount)     // 使用wallet变量作为参数,转账接收方地址改为我自己

    var transactionObject = {
        "from" : walletVitalik,     // 使用walletVitalik变量作为from字段的值,模拟这个调用是由V神钱包地址发出
        "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		信息	0x0000000000000000000000000000000000000000000000000000000000000001
2023-06-09 13:34:31		信息	转账金额: 1000 DAI, 使用 toInnerAmount 转换为: 1000000000000000000000

ایجاد کنندہ کے ذریعہ مقداری تجارتی پلیٹ فارم کا استعمال کرتے ہوئے ، ٹرانزیکشن کے نتائج کو آسانی سے نمایاں کیا جاسکتا ہے اور ممکنہ طور پر ناکام ہونے والی ٹرانزیکشن بھیجنے سے گیس کی لاگت میں غیر ضروری نقصان سے بچنا ہے۔ ہم نے اس باب کے کورس میں مثال کے کوڈ کا استعمال کرتے ہوئے وی وی والیٹ کو منتقلی کا نمونہ بنایا ، جس میں وی وی والیٹ نے ہمیں منتقلی کا مطالبہ کیا تھا۔eth_callآپ کے خیال کو استعمال کرنے سے ، آپ کو اپنے آپ کو اور اپنے دوستوں کو بھی بچانے میں مدد ملے گی۔eth_callیہ طریقہ کار کہاں استعمال ہوتا ہے؟

ERC721 معاہدے کی شناخت

ہم جانتے ہیں کہ ای ٹی ایچ ، بی ٹی سی جیسے ٹوکن ایک ہم آہنگ ٹوکن ہیں ، آپ کے ہاتھ میں موجود ٹوکن اور میرے ہاتھ میں موجود ٹوکن میں کوئی فرق نہیں ہے۔ لیکن دنیا میں بہت سی چیزیں مختلف ہیں ، جیسے: جائیداد ، نوادرات ، مجازی آرٹ وغیرہ ، جن کی نمائندگی ہم آہنگ ٹوکن کے ذریعہ نہیں کی جاسکتی ہے۔ لہذا ، ERC721 معیار کے ساتھ غیر ہم آہنگ اشیاء کو خلاصہ کرنے کے لئے ، NFT اور اس سے متعلقہ تصورات موجود ہیں۔ تو ایتھروئن پر تعینات بہت سے سمارٹ معاہدوں میں سے ہم کس طرح پہچان سکتے ہیں کہ کون سے معاہدے 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 ((bytes4) )) چلانے سے حساب لگاسکتے ہیں) ؛ یا اوپر سلیکٹر معاہدہ کا استعمال کرتے ہوئے۔

اگر آپ براہ راست فنکشن کے دستخط کا حساب لگائیں اور اس کے پہلے چار بائٹس کو نکالیں تو آپ کو ملے گا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		信息	supportsInterface(bytes4) interfaceId: 0x01ffc9a7

اور آپ کو معلوم ہے کہ آپ کے نتائج کیا ہیں اورERC165 معیاراس کے علاوہ، اس کے بارے میں مزید معلومات کے لئے یہاں کلک کریں۔

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 معاہدہ ہے یا نہیں تو ، ہمیں پہلے یہ جاننے کی ضرورت ہے کہ ERC721 معاہدہ کیا ہے اور اس کا کیا مطلب ہےinterfaceIdاس کے بعد آپ اسے استعمال کرنے کی کوشش کر سکتے ہیں۔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 "错误:数组中元素个数为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 "错误:TypeArray view长度不同"
                    }

                    for (var index = 0; index < ret.length; index++) {
                        ret[index] ^= viewData[index]
                    }
                }
            }
            ret = Encode("raw", "raw", "hex", ret.buffer)
        }
    } else {
        throw "错误:参数需要数组类型。"
    }

    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"اور اس کے بعد، اس فنکشن کو واپس آتا ہےJavaScriptزبانArrayBufferقسمیں۔ اگر آپ دو کے برابر ہیںArrayBufferاعتراض^(غیر یا) آپریشن، کی بنیاد پر کیا جانا چاہئےArrayBufferاشیاء کی تخلیقTypedArrayاس کے بعد ، آپ کو ایک نظر ڈالنا چاہئے ، اور پھر اس میں موجود ڈیٹا کو گھومنا چاہئے ، انفرادی طور پر مختلف یا حساب کتاب کرنا ہوگا۔

ڈیبگنگ ٹولز میں چلتا ہے:

2023-06-13 15:04:09		信息	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 کے انٹرفیس ID کے ساتھ ہم یہ فیصلہ کر سکتے ہیں کہ کوئی معاہدہ ERC721 معیار کا معاہدہ ہے یا نہیں۔ ہم اس کا استعمال کرتے ہیں۔BAYCٹیسٹ کرنے کے لئے، یہ ایک معاہدہ ہے جو ERC721 پر عمل کرتا ہے، سب سے پہلے ہمیں ABI رجسٹر کرنے کی ضرورت ہے، اور چونکہ ہم صرف تین طریقوں کو کال کرتے ہیں، ہم صرف تین طریقوں کو رجسٹر کرسکتے ہیں:

  • سپورٹسانٹرفیس ((انٹرفیس آئی ڈی)
  • علامت ((()
  • نام

اس کا کوڈ مندرجہ ذیل ہے:

function main() {
    // ERC721的合约地址,这里用的BAYC
    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接口Id,在之前的课程中计算得出
    var interfaceId = "0x80ac58cd"

    // 注册ABI
    exchange.IO("abi", testContractAddress, testABI)

    // 调用supportsInterface方法
    var isErc721 = exchange.IO("api", testContractAddress, "supportsInterface", interfaceId)

    // 输出信息
    Log("合约地址:", testContractAddress)
    Log("合约名称:", exchange.IO("api", testContractAddress, "name"))
    Log("合约代号:", exchange.IO("api", testContractAddress, "symbol"))
    Log("合约是否为ERC721标准:", isErc721)
}

ڈیبگنگ ٹول میں ٹیسٹ چلایا جا سکتا ہے:

2023-06-13 16:32:57		信息	合约是否为ERC721标准: true
2023-06-13 16:32:57		信息	合约代号: BAYC
2023-06-13 16:32:57		信息	合约名称: BoredApeYachtClub
2023-06-13 16:32:57		信息	合约地址: 0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d

پتہ لگانا0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13dیہ معاہدہ ERC721 معیار پر مبنی ہے۔

اس مضمون میں ہم نے بتایا کہ ERC721 معاہدوں کو کس طرح سمجھا جائے۔ ERC20 جیسے معاہدوں کو جو ERC165 معیارات کی حمایت نہیں کرتے ہیں ان کی شناخت کرنے کے لئے ایک اور طریقہ ہے۔ کیا آپ جانتے ہیں کہ کس طرح چیک کیا جائے کہ معاہدہ ERC20 معیارات کے مطابق ہے؟

کوڈ calldata

کیا ہے؟calldataکیا آپ کو معلوم ہے کہ آپ کے ملک میں کتنے لوگ رہتے ہیں؟

"کال ڈیٹا" ایتھرین میں کسی فنکشن کے کال یا پیرامیٹر کے لئے کوڈ ہے ، "کال ڈیٹا" معاہدے کے مطابق اے بی آئی (ایپلیکیشن بائنری انٹرفیس) کی وضاحت کے مطابق کوڈ کیا گیا ہے۔

مثال کے طور پر ہم ERC20 معاہدوں کے بارے میں سیکھ سکتے ہیں جو ہم نے پچھلے کورس میں سیکھے ہیں۔balanceOftransferطریقہ کار کو کال کرنے کے لئے، اس کے ساتھ ساتھ کال کرنے پر پیرامیٹرز کو ایک کوڈ کے طور پر.calldata◎ کچھ ایپلی کیشنز میں مثال کے طور پر:معاہدوں کے درمیان تعاملاس طرح کے منظر نامے میں استعمال کیا جا سکتا ہے.calldataاس کے علاوہ بھی بہت سی دوسری ایپلی کیشنز ہیں جن کی فہرست یہاں دی گئی ہے۔

اسمارٹ کنٹریکٹ فنکشن کو کیسے کوڈ کیا جائے؟calldata

ایجاد کاروں کی طرف سے استعمال کیا جا کرنے کے لئے ایک مقداری ٹریڈنگ پلیٹ فارمexchange.IO("encode", ...)اسمارٹ کنٹریکٹ فنکشن کالز کو کوڈ کرنے اور استعمال کرنے میں بہت آسان ہے۔exchange.IO("encode", ...)فنکشن کا پہلا پیرامیٹر ایک فکسڈ سٹرنگ ہے"encode"؛ دوسرا پیرامیٹر اسمارٹ معاہدے کا پتہ ہے۔ تیسرا پیرامیٹر اسمارٹ معاہدے کے طریقہ کار کا نام ہے جس کو کوڈ کیا جانا ہے۔ باقی پیرامیٹرز اسمارٹ معاہدے کے طریقہ کار کی مخصوص پیرامیٹر ویلیو کو منتقل کرتے ہیں جسے کوڈ کیا جانا ہے۔

eth_sendRawTransaction

جب ہم ایک سمارٹ معاہدے کے طریقہ کار کو کال کرنے کے لئے کوڈ اور اس کے مطابق پیداcalldataاعداد و شمار کے وقت، اگر یہ ہوشیار معاہدہ طریقہ ایک لکھنے کا طریقہ ہے (یعنی: لکھنے کے آپریشن) ہم پیدا کرنے کے لئے کی ضرورت ہےcalldataاعداد و شمار کے اعداد و شمار کے میدان کے طور پر تجارت کی جاتی ہے اور پھر ایتیروم کے آر پی سی کے طریقہ کار کا استعمال کرتے ہوئےeth_sendRawTransactionایتھرین نیٹ ورک کو اس ٹرانزیکشن پر مشتمل خام ڈیٹا کی درخواست بھیجنا۔

eth_sendRawTransactionاس طریقہ کار کی صرف ایک ہی پیرامیٹر ہےdata

ڈیٹا: دستخط شدہ ٹرانزیکشن (عام طور پر لائبریری کے ساتھ دستخط شدہ، آپ کی نجی کلید کا استعمال کرتے ہوئے)

یہdataایک پیرامیٹر ایک ایسا ڈیٹا ہے جو ٹرانزیکشن کے اعداد و شمار کو دستخط کے بعد حساب لگایا جاتا ہے۔ ایتھرین کے ٹرانزیکشن ڈیٹا کا ڈھانچہ بنیادی طور پر مندرجہ ذیل شعبوں پر مشتمل ہے:

{
    "nonce": "0x1",                         // 交易发送方的账户交易次数
    "gasPrice": "0x12a05f200",              // 交易的Gas价格
    "gasLimit": "0x5208",                   // 交易的Gas限制
    "to": "0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2",    // 目标合约地址或接收方地址
    "value": "0x4563918244F40000",          // 转账的以太币数量
    "data": "0x0123456789ABCDEF",           // 要发送给合约的数据
}

ایتھرین کے لئے سائن اپ کیسے کریں؟

ہم استعمال کرتے ہیں ایک مقدار سازوں کی تجارت پلیٹ فارمEncode()فنکشنز کے لئے دستخط کا حساب لگانا، مثال کے طور پر ہم نے بعد کے سبق میں لکھا ہے "Write طریقہ کار کو کال ڈیٹا پر عمل کریں".

calldata کو پڑھنے کا طریقہ کار چلائیں

Read طریقہ کار کے لئےcalldataہم نے پہلے سیکھے ہوئے آر پی سی کے طریقہ کار کا استعمال کرتے ہوئے ایک عمل انجام دیا:eth_callہم نے پہلے ہی وضاحت کی ہے.eth_callایتھرین کا آر پی سی طریقہ صرف اسمارٹ معاہدے کرتا ہے۔Writeطریقہ کار کا مظاہرہ، اس باب میں استعمالcalldataہم WETH معاہدے کا استعمال کرتے ہیں. ہم WETH معاہدے کا استعمال کرتے ہیں.balanceOfموجودہ بٹوے میں WETH ٹوکن بیلنس پڑھنے کا طریقہ۔

ہم نے ایتھرین نیٹ ورک پر ٹیسٹ کرنے کے لئے ڈیبگنگ ٹولز کا استعمال کیا:

function toAmount(s, decimals) {
    return Number((BigDecimal(BigInt(s)) / BigDecimal(Math.pow(10, decimals))).toString())
}

function main() {
    // WETH合约的ABI
    var abiWETH = `[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"guy","type":"address"},{"name":"wad","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"src","type":"address"},{"name":"dst","type":"address"},{"name":"wad","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"wad","type":"uint256"}],"name":"withdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"dst","type":"address"},{"name":"wad","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"deposit","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"src","type":"address"},{"indexed":true,"name":"guy","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"src","type":"address"},{"indexed":true,"name":"dst","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"dst","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"src","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Withdrawal","type":"event"}]`

    // WETH合约地址
    var wethAddress = "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"

    // 注册WETH合约的ABI
    exchange.IO("abi", wethAddress, abiWETH)

    // 当前配置的交易所对象的钱包地址
    var walletAddress = exchange.IO("address")

    // 编码WETH合约的deposit方法调用
    var calldataForDeposit = exchange.IO("encode", wethAddress, "balanceOf(address)", walletAddress)
    Log("calldataForDeposit:", "0x" + calldataForDeposit)

    // 构造transaction,作为eth_call的第一个参数
    var transaction = {
        "from" : walletAddress,
        "to" : wethAddress,
        "data" : "0x" + calldataForDeposit,
    }

    // eth_call的第二个参数
    var blockNumber = "latest"

    // 使用eth_call调用
    var ret = exchange.IO("api", "eth", "eth_call", transaction, blockNumber)
    var wethBalance = exchange.IO("decode", "uint256", ret)   // 可以使用exchange.IO("decode", ...) 函数解码
    Log("wethBalance:", toAmount(wethBalance, 18))            // 从以wei为单位,换算成WETH个数为单位
}

ڈیبگنگ ٹولز میں چلتا ہے:

2023-06-15 11:51:31		信息	wethBalance: 0.015
2023-06-15 11:51:31		信息	calldataForDeposit: 0x70a082310000000000000000000000006b3f11d807809b0b1e5e3243df04a280d9f94bf4

اگر اسمارٹ کنٹریکٹ کے طریقے میں واپسی کی قدر ہے تو ، یہ استعمال کیا جاسکتا ہے۔exchange.IO("decode", ...)فنکشن ڈیکوڈ.calldataہم نے اس بات کا یقین کر لیا ہے کہ ہم نے اس طرح کے معاہدوں کا استعمال کیا ہے.balanceOfاس کا طریقہ ایک ہی ہے، میرے ٹیسٹ والیٹ کا WETH بیلنس 0.015 WETH ہے۔

calldata کو لکھنے کا طریقہ کار چلائیں

لکھنے کے طریقہ کار کے لئے کال ڈیٹا کو انجام دینے کے لئے ، آر پی سی کا طریقہ استعمال کرنا ضروری ہے:eth_sendRawTransactionمیں نے اسے دیکھا۔

ہم نے ایتھرین نیٹ ورک پر ٹیسٹ کرنے کے لئے ڈیبگنگ ٹولز کا استعمال کیا:

function toAmount(s, decimals) {
    return Number((BigDecimal(BigInt(s)) / BigDecimal(Math.pow(10, decimals))).toString())
}

function toInnerAmount(s, decimals) {
    return (BigDecimal(s)*BigDecimal(Math.pow(10, decimals))).toFixed(0)
}

function main() {
    // WETH合约的ABI
    var abiWETH = `[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"guy","type":"address"},{"name":"wad","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"src","type":"address"},{"name":"dst","type":"address"},{"name":"wad","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"wad","type":"uint256"}],"name":"withdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"dst","type":"address"},{"name":"wad","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"deposit","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"src","type":"address"},{"indexed":true,"name":"guy","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"src","type":"address"},{"indexed

مزید