【主要內容】
今天嘗試解決交易NFT時的購買操作不能完成,仍然失敗了,同時學習solidity0.7版,共耗時30分鐘。
(此外整理作筆記花費了約36分鐘)
詳細學習過程見文末學習過程屏幕錄像。
【solidity0.7.0學習筆記】
https://learnblockchain.cn/docs/solidity/layout-of-source-files.html
一、版本標識Pragmas
認真閱讀官方文檔,才明白過來,^符號在版本標識中意思 只是,在當前二級版本號範圍內有效。
如:
pragma solidity ^0.5.2;
這樣,源文件將既不允許低於 0.5.2 版本的編譯器編譯, 也不允許高於(包含) 0.6.0 版本的編譯器編譯(第二個條件因使用 ^ 被添加)。 這種做法的考慮是,編譯器在 0.6.0 版本之前不會有重大變更,所以可確保源代碼始終按預期被編譯。 上面例子中不固定編譯器的具體版本號,因此編譯器的補丁版也可以使用。
不是我之前理解 的那樣,只要版本高於0.5.2就可以,原來是有上限的(到0.6之下)
二、ABI增強測試功能標識 ABIEncoderV2
新的 ABI 編碼器可以用來編碼和解碼嵌套的數組和結構體,當然這部分代碼還在優化之中,他沒有像之前 ABI 編碼器 那樣經過嚴格的測試,我們可以使用下面的語法來啓用它 pragma experimental ABIEncoderV2; 。
三、文件引用 import
今天才發現solidity的文件引用其實非常的豐富,完全參照 了javascript語言,甚至我個人感覺與python語言也非常類似。
因爲缺乏實踐,所以簡單引用以下筆記:
“
Solidity 支持的導入語句來模塊化代碼,其語法跟 JavaScript(從 ES6 起)非常類似。 儘管 Solidity 不支持 default export 。
註解
ES6 即 ECMAScript 6.0,ES6是 JavaScript 語言的下一代標準,已經在 2015 年 6 月正式發佈。
在全局層面上,可使用如下格式的導入語句:
import "filename";
此語句將從 “filename” 中**導入所有的全局符號到當前全局作用域**中(不同於 ES6,Solidity 是向後兼容的)。
這種形式已經不建議使用,因爲它會無法預測地污染當前命名空間。 如果在“filename”中添加新的符號,則會自動添加出現在所有導入 “filename” 的文件中。 更好的方式是明確導入的具體 符號。
向下面這樣,創建了新的 symbolName 全局符號,他的成員都來自與導入的 "filename" 文件中的全局符號,如:
import * as symbolName from "filename";
然後所有全局符號都以``symbolName.symbol``格式提供。 此語法的變體不屬於ES6,但可能有用:
import "filename" as symbolName;
它等價於 import * as symbolName from "filename";。
如果存在命名衝突,則可以在導入時重命名符號。例如,下面的代碼創建了新的全局符號 alias 和 symbol2 ,引用的 symbol1 和 symbol2 來自 “filename” 。
import {symbol1 as alias, symbol2} from "filename";
路徑
上文中的 filename 總是會按路徑來處理,以 / 作爲目錄分割符、以 . 標示當前目錄、以 .. 表示父目錄。 當 . 或 .. 後面跟隨的字符是 / 時,它們才能被當做當前目錄或父目錄。 只有路徑以當前目錄 . 或父目錄 .. 開頭時,才能被視爲相對路徑。
用 import "./filename" as symbolName; 語句導入當前源文件同目錄下的文件 filename 。 如果用 import "filename" as symbolName; 代替,可能會引入不同的(如在全局 include directory 中)文件。
最終導入哪個文件取決於編譯器(見下文 在實際的編譯器中使用)到底是怎樣解析路徑的。 通常,目錄層次不必嚴格映射到本地文件系統, 它也可以映射到能通過諸如 ipfs,http 或者 git 發現的資源。
註解
通常使用相對引用 import "./filename.sol"; 並且避免使用 .. ,後面這種方式可以使用全局路徑並設置映射
”
【找到了exchange.sol智能合約文件調用buy方法總不成功的原因】
一、首先進行了重複測試,昨天 的測試發現eth費用支付與收錢都沒有執行,今天重複測試一次昨天 發佈的智能合約,發現支付與收錢操作是成功完成的。
二、先是修改了了資產轉移 的方法調用:
```
//購買指定ID的NFT資產的方法
function buy(uint256 assetId) payable public {
require(msg.value >= _orders[assetId]); //驗證當前調用合約的節點 發送的 代幣(ETH)的數量是否大於等於這個指定ID資產的 當前 定價
require(_orders[assetId] > 0); //還得驗證這個資產的定價是否不是 0,這兒默認認爲如果價格是0那就不是出售狀態
//---把第一句註釋掉的代碼換成下面的寫法:https://www.cnblogs.com/zhizaixingzou/p/10122209.html
//if(msg.value < _orders[assetId]){
// revert("沒有足夠的ether來支付");
//return ; //這種寫法未經驗證
//}
//if(_orders[assetId] == 0){
// revert("this nft is unselled.");
// return ; //這種寫法未經驗證
//}
address owner = nonFungible.ownerOf(assetId); //在購買完成前,這個資產是屬於哪個節點的
owner.transfer(_orders[assetId]); //原擁有資產的節點 獲得 ETH (就是賣方收錢了)
uint remaining = msg.value - _orders[assetId]; //如果當前調用合約的節點發送的ETH大於此資產的實際定價,那麼求出 要找零 的餘額。
if (remaining > 0) {
msg.sender.transfer(remaining); //找零給買家
}
//下面這個語句轉移資產出錯:檢查代碼發現,使用safeTransFrom少傳了一個實參,這個方法的最後一個形參是data
//nonFungible.safeTransferFrom(owner, msg.sender, assetId); //完成這個NFT資產的歸屬節點的轉移 (交貨)
//現在使用方法transferFrom
nonFungible.transferFrom(owner, msg.sender, assetId);
//下面把資產的出售狀態去除
_orders[assetId]=0;
//從在售列表中把當前資產刪除
int256 intindex=ghlhsuintarraylib.uintarraygetindexbyvalue(idlst,assetId);
if(intindex>=0){
ghlhsuintarraylib.uintarrayremovebyindex(idlst,intindex);
ghlhsuintarraylib.uintarrayremovebyindex(valuelst,intindex);
//ghlhsuintarraylib.uintarrayremovebyindex(datalst,intindex);
}
}
```
部署成功,然而調用bug方法仍然失敗了
好在今天發現了真實的原因:
所有資產轉移 的方法,最終都調用了
ERC721Base.sol
文件中的方法
_doTransferFrom
而
_doTransferFrom
方法最終調用的是另一個方法:
_moveToken
問題就出在
_doTransferFrom
方法使用了一個函數修改器:
onlyAuthorized
因爲這個函數修改器要求執行資產轉移時,調用合約的節點必須是要轉移 的資產ID的擁有者(OWNER)或已被授權(approved),而購買者節點調用合約,不能保證已經被授權,所以資產轉移是不會成功的。
當然可以去除這個函數修改器:onlyAuthorized
然而這會造成重大的安全問題,目前我想到的方法是,得在節點決定出售自己的資產時就加上授權操作語句,然而新的問題是,出售方節點在決定出售資產時,它把資產授權給誰呢?它又不知道誰要購買這個節點?
是不是需要引入 第三方節點(中介節點)?
這是接下來要研究的問題。
【歡迎大家加入[就是要學]社羣】
如今,這個世界的變化與科技的發展就像一個機器猛獸,它跑得越來越快,跑得越來越快,在我們身後追趕着我們。
很多人很早就放棄了成長,也就放棄了繼續奔跑,多數人保持終身不變的樣子,原地不動,成爲那猛獸的肚中餐——當然那也不錯,在猛獸的逼迫下,機械的重複着自我感覺還良好地穩定工作與生活——而且多半感覺不到這有什麼不正常的地方,因爲在猛獸肚子裏的是大多數人,就好像大多數人都在一個大坑裏,也就感覺不出來這是一個大坑了,反而坑外的世界顯得有些不大正常。
爲什麼我們不要做坑裏的大多數人?
因爲真正的人生,應當有百萬種可能 ;因爲真正的一生可以有好多輩子組成,每一輩子都可以做自己喜歡的事情;因爲真正的人生,應當有無數種可以選擇的權利,而不是總覺得自己別無選擇。因爲我們要成爲一九法則中爲數不多的那個一;因爲我們要成爲自己人生的導演而不是被迫成爲別人安排的戲目中的演員。
【請注意】
就是要學社羣並不會告訴你怎樣一夜暴富!也不會告訴你怎樣不經努力就實現夢想!
【請注意】
就是要學社羣並沒有任何可以應付未來一切變化的獨門絕技,也沒有值得吹噓的所謂價值連城的成功學方法論!
【請注意】
社羣只會互相幫助,讓每個人都看清自己在哪兒,自己是怎樣的,重新看見心中的夢想,喚醒各自內心中的那個英雄,然後勇往直前,成爲自己想要成爲的樣子!
期待與你並肩奔赴未來!
QQ羣:646854445 (【就是要學】終身成長)
【原文地址】
https://www.941xue.com/content.aspx?k=941XUEUPUKYV90637311510941615967
【同步語音筆記】
https://www.ximalaya.com/keji/19103006/369612322
【學習過程屏幕錄屏】
https://www.bilibili.com/video/BV14h41127Hs/
筆記合集在github上:
https://github.com/lhghroom/Self-learning-blockchain-from-scratch