timezone |
---|
Asia/Shanghai |
请在上边的 timezone 添加你的当地时区,这会有助于你的打卡状态的自动化更新,如果没有添加,默认为北京时间 UTC+8 时区
-
自我介绍 有些許DeFi相關經驗,也學過wtf的solidity課程,這次決定參與共學,並藉此機會產出相關的學習筆記。
-
你认为你会完成本次残酷学习吗? 會!
- 完成了"hello web3!" -第一行:license -第二行:版本,會使用“^”表示 -第三行後是合約內容
- Solidity的變量類型包括三種: -value type:布爾、整型 -reference type:數組 -mapping type: -enum
- 聲明函數可見性的關鍵字有4種:public, private, external, internal
- 聲明函數所擁有的權限:pure(不能讀寫鏈上狀態的變量)、view(能讀取但不能寫入狀態變量)、默認寫法(自由讀取和寫入狀態變量)
- 引用pure和view:節省gas、控制函數權限
- 函數輸出: -returns加在函數名後面,聲明返回的變量類型和變量名 -return用在函數主體,返回指定的變量
- 命名式返回
- 解構式返回: -讀取所有返回值(聲明變量),要賦值的變量用“,”隔開 -讀取部分返回值:不讀取的部分留白
- 數據位置:storage、memory、calldata
- storage:狀態變量默認,存在鏈上
- memory:函數中的參數、臨時變量使用,存在內存、不上鏈
- calldata:不能被修改,存在內存、不上鏈
- 狀態變量:存在鏈上的變量,消耗較多gas
- 局部變量:函數執行過程中有效的變量,不上鏈,gas消耗小
- 全局變量:在函數內不聲明直接使用,常用:msg.sender、block.number、msg.data
- 數組是常用的一種變量類型,分為固定長度數組、可變長度數組
- 固定長度數組:T[k],T是元素的類型、k是長度
- 可變長度數組:T[ ],T是元素類型
- 注意bytes是特例,類似動態數組類型,但聲明時不用加上[]
- 創建數組的規則:memory型的動態數組,可用new操作符創鍵,需聲明長度(聲明後的長度不能改變)
- 數組字(array literal):eg.[1,2,3],逗號分隔、方括號包裹、每一個元素的類型是以第一個元素為準;如果一個值沒有指定類型的話,默認會指定為最小單位的類型
- 動態的memory數組不能用固定長度的memory數組或者數組字面量賦值
- 數組: -length:存儲類型memory存儲數組,長度在創建後固定 -push():用在數組最後添加一個0元素,並返回該元素的引用 -push(x):用在數組最後添加一個值為x的元素 -pop():用在移除數組的最後一個元素 5.結構體賦值: -在函數中創建一個storage的struct引用 -直接對結構體的成員變量賦值 -用類似函數的方式初始化一個結構體,用於整體賦值 -用鍵值對(key-value pair)的形式構造結構體,並整體賦值
- 映射(mapping):在映射中,透過鍵(key),查詢對應的值(value)
- _KeyType只能選擇Solidity內置的值類型,uint、address
- _ValueType可以使用自定義類型
- 缺省值(default value):已聲明但尚未賦值的變量在運行時會獲得初始值
- 可以為變量聲明public,調用getter函數獲取其值,驗證各種類型初始值的正確性
- 映射結構、結構體、數組
- constant(常量)變量須在聲明時初始化,之後再也不能改變
- 用immutable(不變量)聲明的變量可在聲明時初始化,或在合約構造時初始化
- 控制流
- if-else條件語句
- for循環
- while循環
- do-while循環
- 三元運算符
- 插入排序
- 構造函數:每個合約定義一個,在部署合約時定義一次(在不同版本的語法不一致)
- 修飾器是用來聲明函數擁有的特性,減少代碼冗余
- event有兩個特點:(1)在前端做響應、(2)是EVM上比較經濟的做法
- 事件的聲明:event關鍵字開頭、事件名稱、括號裡面寫好事件需要紀錄的變量類型和變量名
- transfer事件記錄了3個變量:from(代幣轉帳地址)、to(接收地址)、value(轉帳數量)
- emit釋放事件
- 用log來儲存solidity事件,每條log都包括topics、data
- virtual: 父合約中的函数,如果希望子合約重寫,需要加上virtual關鍵字
- override:子合約重寫了父合約中的函數,需要加上override關鍵字
- 多重繼承,Solidity的合約可以繼承多個合約:(1)繼承時要按輩分最高到最低的順序排(2)如果某一個函數在多個繼承的合約裡都存在,在子合約裡必須重寫,不然會報錯(3)重寫在多個父合約中都重名的函數時,override關鍵字後面要加上所有父合約名字
- 抽象合約:如果一個智能合約裡至少有一個未實現的函數,即某個函數缺少主體{}中的内容,則必須將該合約標為abstract,不然編譯會報錯
- 接口的規則:(1)不能包含狀態變量(2)不能包含構造函數(3)不能繼承除接口外的其他合約(4)所有函數都必須是external且不能有函數體(5)繼承接口的非抽象合約必須實現接口定義的所有功能
- 何時使用接口?如果我們知道一個合約實現了IERC721接口,我們不需要知道它具體代碼實現,就可以與它交互
- gas花費:error< assert< require
- Solidity中允許函數進行重載(overloading),名字相同但輸入參數類型不同的函數可以並存,被視為不同函數。但Solidity不允許修飾器(modifier)重載。
- 實参匹配(Argument Matching):在調用重載函數時,會把輸入的實際參數和函數參數的變量類型做匹配。出現多個匹配的重載函數,就報錯。
- 庫合約:提升Solidity代碼的複用性和减少gas
- 庫合約和普通合約的差別:不能存在狀態變量、不能夠繼承或被繼承、不能接收以太幣、不可以被銷毀
- 庫合約重的函数可見性,如果被設成public或external,調用函數時會觸發一次delegatecall;被設成internal,則不會
- import語句,可以幫助我們在一個文件中引用另一個文件的内容,增加代碼的可重用性和組織性
- 通過源文件相對位置導入
- 通過源文件網址導入網上的合約的全局符號
- 通過npm的目錄導入
- 通過指定全局符號導入合約特定的全局符號
- 引用(import)在代碼中的位置:在聲明版本號之後,在其他代碼之前
- Solidity支持兩種特殊的回調函數,receive()和fallback(),他們主要在兩種情況下被使用:(1)接收ETH(2)處理合約中不存在的函數調用(代理合約proxy contract)
- 惡意合約,會在receive() 函數(舊版本的fallback() 函數)嵌入惡意消耗gas的内容或者使得執行故意失敗的代碼,讓一些退款、轉帳邏輯的合約不能正常工作
- receive()和payable fallback()都不存在的時候,向合約直接發送ETH將會報錯(你仍可以通過帶有payable的函數向合約發送ETH)
- Solidity有三種方法可以向其他合约約發送ETH:transfer()、send()、call()
- call()是最推薦的做法
- transfer()如果轉帳失敗,會自動revert(回滾交易),gas限制是2300
- send()如果轉帳失敗,不會revert,gas限制是2300
- call()如果轉帳失敗,不會revert,没有gas限制
- 可以在函數裡傳入目標合約地址,生成目標合約的引用,然後調用目標函數
- 在函數裡傳入合約的引用,只需要把上面参數的address類型改為目標合約名
- 創建合約變量,接著通過它來調用目標函數
- 如果目標合約的函數是payable的,我們可以通過調用它來給合約轉帳:_Name(_Address).f{value: _Value}()
- _Name:合約名,_Address:合約地址,f:目標函數名,_Value:要轉的ETH數額(以wei為單位)
- call是Solidity官方推荐的通過觸發fallback或receive函數發送ETH的方式
- 利用call調用目標合約:Response事件、調用setX函數、調用getX函數、調用不存在的函數、
- 目前delegatecall主要的應用場景:代理合約(Proxy Contract)、EIP-2535 Diamonds(鑽石)
- 代理合約(Proxy Contract)儲存所有相關變量後保存邏輯合約的地址。升級時,只需要將代理合約指向新的邏輯合約即可。
- 有兩種方法可以在合約中創建新合約,create和create2
- Pair合約,包含3個狀態變量:factory(工廠合約地址)、token0、token1
- CREATE2的目的:讓合約地址獨立於未來的事件。不管未來區塊鏈上發生了什麼,你都可以把合約部署在事先計算好的地址上
- 用CREATE2創建的合約地址由4個部分决定:(1)0xFF:常數,避免和CREATE衝突;(2)CreatorAddress: 調用CREATE2的當前合約地址(3)salt(鹽):影響新創建的合約地址(4)initcode: 新合約的初始字節碼
- 已經部署的合約無法被SELFDESTRUCT
- 如果要使用原先的SELFDESTRUCT功能,必須在同一筆交易中創建並SELFDESTRUCT
- 調用deleteContract()函數,合約將觸發selfdestruct操作,只是將合約包含的ETH轉移到指定地址,而合約依然能夠調用
- selfdestruct能銷毀合約並將剩餘ETH轉移到指定帳戶
- Solidity中的ABI編碼有4個函數:abi.encode, abi.encodePacked, abi.encodeWithSignature, abi.encodeWithSelector
- 在以太坊中,數據必須編碼成字節碼才能和智能合約交互
- Hash的應用:生成數據唯一標誌、加密簽名、安全加密
- msg.data是Solidity中的一個全局變量,值為完整的calldata(調用函數時傳入的數據)
- 在Solidity中,函數的參數類型主要分為:基礎類型參數,固定長度類型參數,可變長度類型參數和映射類型參數。