timezone |
---|
Asia/Taipei |
- 自我介绍
My name is 0x3f3f3f3f3f3f i'm interesting in smart contract.
- 你认为你会完成本次残酷学习吗? i'll do my Best to complete this course.
- 學習了如何使用remixIDE,以及compile到deploy的流程
- 值變量裡面比較特別的是address有分成單純的address跟address payable 兩種
- 宣告函式需要使用可見性 以及狀態修飾符,狀態修飾符有一個特別的payable代表這是一個能給合約收錢的function
- 可見性中 private跟internal的差異是在於繼承的合約能不能使用
- 宣告返回值前面記得要加上returns; 命名式返回跟解構式賦值都是新學到的語法
今天沒有到solidity101上學東西,主要是完成了一份課堂上的作業,比較有收穫的是完成了一個 reentrancy attack的流程,我覺得收穫蠻多的具體了解了調用閃電貸的流程用solidity操作了一遍 ,然後學到用calldata以及solidity撰寫讓設計不完善的閃電貸項目轉移token權限 搞了很久一部分,最後答案也沒幾行,感覺是對語法不太熟悉導致對原理有誤解,進而有太多奇怪的想法 明天開始繼續基礎學習solidity101
- 對結構的初始化都要再函示裡面
- 初始化struct 的四種方法,第一種用storage來創造一個引用然後對她初始化,第二種直接引入在外面的函數變量,第三種跟第四種很像,差別是第四種用了一種叫做key value的方法
- 在mapping的結構裡面 不能使用struct來mapping,mapping沒有定義初值的話她會默認是各個型別的初始值,初始化mapping的時候都是storage也就是狀態變量
- 變量初值的部分bool默認是false其他都蠻正常的,delete可以讓變量變成初始值
- immutable constant都不能在初始化後改變值 差別在於 immutable可以在constructor裡面在初始化邊量比較靈活 另外能聲明成immutable的只有數值變量,像是byte string這種的不行
- event的用法有 在emmit裡面有加上index的也就是topic部分的之後可以直接檢索但是只能有最多三個,且每個最大256 bits多的都會被丟到剩下data的部分,event可以理解為他在做broadcast而不是把數據保存到鍊上,這樣做可以節省gas,topic除了包含三個index以外還有多一組哈希,這組哈希是用你emit的事件名稱哈希的例如emit transfer(xxx,xxx,xxx)就會用keccak256(”transfer(xxx,xxx,xxx)”)來處理
- 繼承的寫法蠻特別的要注意繼承的輩份關係由左到右由大到小,super可以用來調用最近的父合約,重載父合約的函數要用overrider關鍵字,然後如果父合約希望讓子合約重載他的函數他要加上virtual不然子合約是無法重載的,假如重載的函數在多個父輩都存在則要把父輩都打出來在override後面
- 知道了interface的用法以及要怎麼跟別人部署好的合約互動 如果是符合特定IERC可以直接import來用不用自己手打interface 如果不是那你可以去etherscan裡面看他的abi在按照他提供的內容打出他的interface
- 理解了異常的差別,之前只用過require 學了才知道require是gas消耗量最高的 然後error感覺跟require很像,只是把revert的部分分開來寫但是他的gas消耗量是最小的
今天的學習內容主要是在delegate call上面,delegatecall是讓呼叫合約可以在自己的上下文執行被呼叫合約的函數,那有個問題是,這樣呼叫合約不就要有跟被呼叫合約一樣的狀態變量以及名稱,事實上delegatecall的用法中他辨認的是slot的位置,例如你在被呼叫合約裡面作用的是slot1,他就會作用在呼叫合約裡面的slot1,這意味的如果呼叫合約的slot沒有跟被呼叫合約的slot對齊就可能會發生嚴重的錯誤
昨天的補充 不是所有狀態變數都會存在slot裡面,immutable還有constant都不會存在slot內而是直接內嵌在合約的byte code裡面,對於其他動態的結構例如陣列要計算array[n] slot的位置要把起始slot作encode在hash然後加上offset(n*element size假如元素是uint256 element size可以當作1因為每個slot只能存一個元素),mapping的算法可以直接調用keccak256(encodewithpacked(a,b)),a放的是key value,b放的是起始的slot
今天看了solidity 101關於編碼的部分,包括abi.encodePacked,abi.encode , abi.encodeWithSignature , abi.encodeWithSelector,encode 跟 encodewithpacked的差別在於encode會把個別資料填充到32個零,而encodeWithPacked會把他們緊湊的包再一起不會填充0,而encodewithsignature相當於是結合了encodeWithselector的功能你不需要自己把它轉成function selector他會自動幫你處理,encodewithselector在根本上也是由encodePacked來達成,他只是把前面得到的四個byte function selector跟後面要傳入的參數經過abi.encode後在concatenate再一起
function my_encodeWithSelector() public view returns(bytes memory result) {
result = bytes.concat(
bytes4(keccak256("foo(uint256,address,string,uint256[2])")), // 加入函數選擇器
abi.encode(x, addr, name, array) // 使用標準 ABI 編碼
);
function encodeWithSignature() public view returns(bytes memory result) {
result = abi.encodeWithSignature("foo(uint256,address,string,uint256[2])", x, addr, name, array);
}
function encodeWithSelector() public view returns(bytes memory result) {
result = abi.encodeWithSelector(bytes4(keccak256("foo(uint256,address,string,uint256[2])")), x, addr, name, array);
}
以上三個function的輸出是一樣的
記錄一下遇到的問題
keccak256((keccak256(abi.encode(leaf, proof[1]))));
原本想說這樣可以成功編譯結果一直有問題看了一下發現keccak256要傳入的是bytes可是返回的是固定只有32字節的bytes32,要解決這個問題可以加上一個bytes.concat它會自動幫你轉成bytes型別
寫作業狠狠踩了一個坑 用kecca256跟encodewithpacked來算merkel tree想說怎麼一直跟答案不一樣是不是他有問題,後來才發現在encodepack的時候順序沒有注意,要按照在樹裡面的結構來做才會跟答案一樣
複習了一下interface相關的用法,在我們知道一個合約的地址後我們沒有辦法直接在solidity裡面調用他的函數,我們要先聲明他的interface然後把地址做type casting之後就可以進行調用,假如是一些比較通用的的ERC模板可以繼承openzeppline的函數庫
今天複習了一下ERC20,包括transfer transferfrom approve等等,比較關鍵的大概是approve函數可以授權給其他地址使用指定數量你的帳戶持有的代幣,approve 加上 transferfrom讓合約可能出現風險所以需要多注意