主頁 > 區塊鏈 > solidity 從入門到發幣(eth)

solidity 從入門到發幣(eth)

2021-01-15 13:10:55 區塊鏈

目錄

1 Solidity與智能合約

2 智能合約概述

3 以太坊簡介

4 以太坊互動工具

5 開發環境搭建

6 常見概念

7 Solidity基礎語法

7.1 資料型別分類

7.2 remix的使用--第一個智能合約

7.3 值型別

7.4 參考型別

8 Solidity高級語法

8.1 ?動推導var(忘了她吧)

8.2 全域函式/變數

最重要的兩個全域變數(msg.sender 和 msg.value)

8.3 錯誤處理

8.4 修飾器(modifier)

8.5 兩個常用單位

8.5.1 貨幣單位

8.6 事件(Event)

8.7 訪問函式(Getter Functions)

8.8 合約

8.8.1 合約的創建

8.8.2 合約的繼承

8.8.3 合約間如何轉錢

8.8.4 internal和external

8.9 元組(tuple)

8.10 內置數學函式

8.11 其他

8.12 合約銷毀

9.0 發幣

9.1 代幣原始碼

9.2 發幣

本地部署合約測驗

驗證合約

10 編碼規范


1 Solidity與智能合約

起源于以太坊(Ethereum),設計的目的是能在以太坊虛擬機(EVM)上運行,Solidity 是一門面向合約的、為實作智能合約而創建的高級編程語言,所以先從智能合約開始,

參考檔案

Solidity檔案https://www.tryblockchain.org/

solidity官方檔案: https://solidity-cn.readthedocs.io/zh/develop/

solidity英文檔案:https://docs.soliditylang.org/en/latest/control-structures.html#external-function-calls

以太坊發展的?章:https://www.jinse.com/blockchain/471570.html

官??址: https://www.ethereum.org

交易瀏覽器: https://etherscan.io

以太坊??書: https://github.com/ethereum/yellowpaper

2 智能合約概述

智能合約的定義:

“智能合約”(smart contract)這個術語至少可以追溯到1995年,是由多產的跨領域法律學者尼克·薩博(Nick Szabo)提出來的,他在發表在自己的網站的幾篇文章中提到了智能合約的理念,他的定義如下:

“一個智能合約是一套以數字形式定義的承諾(promises),包括合約參與方可以在上面執行這些承諾的協議,”

智能合約的本質:數字化合同,

智能合約的特點:代碼代替人仲裁和執行合同,同時能夠觸發支付,

智能合約于普通合約對比圖示:

普通合約圖示如下:

Bob和Alice簽署合同,由法院進行背書,公示和執行,

智能合約圖示如下:

Bob和Alice共同認可的合約,以代碼的形式上傳到區塊鏈上,雙方繳納保證金到合約中,當滿足一定條件,由外部輸入條件,合約根據邏輯觸發條件,將保證金轉賬給一方,

3 以太坊簡介

以太坊是運?在?個計算機?絡中的軟體,它確保資料以及稱為智能合約的?程式可以在沒有中?協調者的情況下被所 有?絡中的計算機復制和處理,以太坊的愿景是創建?個?法停?,抗屏蔽(審查)和?我維持的去中?化世界計算機,

它延伸了?特幣的區塊鏈概念:在全球范圍的多個計算機上驗證,存盤和復制交易資料(因此術語叫“分布式賬本”),以太坊(Ethereum)在這個概念上更進?步,使之(交易資料)在全球范圍的多個計算機上運?代碼成為現實,

?特幣?來分布式儲存資料的,以太坊?來分布式儲存資料并且計算,這些?型的電腦運?程式叫做智能合約,合約由參與者在他們??的機器上通過?種稱為 “以太坊虛擬機(EVM)”的作業系統運?,

智能合約與以太坊的關系——智能合約是?個部署在以太坊區塊鏈上的程式,

全世界的計算機通過網路互連,每個節點都運行一個以太坊客戶端,即組成以太坊網路,

小結:

  1. 以太坊是?個區塊鏈的?絡,由很多節點組成
  2. 以太坊可以轉賬,可以做資料存盤(通過交易是承載)
  3. 以太坊可以執?程式,程式叫做智能合約,所有節點都運?這個程式
  4. 以太坊?絡有很多個,主?只有?個,還有很多測驗?絡,我們也可以??搭建私鏈
  5. ?個node節點其實就是?個運?以太坊客戶端的計算機
  6. 以太坊是公有鏈,每個?都可以?由的加?退出以太坊?絡
  7. 每?個以太坊節點都可以同步全部的賬本/區塊鏈資訊(blockchain)

4 以太坊互動工具

以太坊愛好者網站

https://ethfans.org/wikis/Home

  • 開發者:web3.js 以太坊專案開發的js庫
  • 一般用戶(消費者):

metamask (瀏覽器插件,firefox, chrome,適合開發測驗,也適合小白用戶)

Ethereum Wallet

https://github.com/ethereum/mist/releases

mist瀏覽器 (很多bug,早期版本)

以太坊網路

(國服,私服,美服,韓服),互不相通,但是功能?致,每個?都可以同時注冊

1.主網路

花費真實的以太幣

2.測驗網路

使用geth,或者Ganache工具搭建本地測驗網路,

Morden(已停服)

Ropsten

以太坊官?提供的測驗?絡,是為了解決Morden難度炸彈問題?重新啟動的?條區塊鏈,?前仍在運?, 共識機制為PoW,

獲取Ropsten測驗幣

https://faucet.ropsten.be

輸入公鑰地址即可,

Kovan

Kovan?前仍在運?,但僅有Parity錢包客戶端可以使?這個測驗?絡,

為了解決測驗?絡中PoW共識機制的問題,以太坊錢包Parity的開發團隊發起了?個新的測驗?絡Kovan,Kovan使? 了權威證明(Proof-of-Authority)的共識機制,簡稱PoA,

PoW是??作量來獲得?成區塊的權利,必須完成?定次數的計算后,發現?個滿?條件的謎題答案,才能夠?成有效 的區塊,

PoA是由若?個權威節點來?成區塊,其他節點?權?成,這樣也就不再需要挖礦,由于測驗?絡上的以太幣?價值, 權威節點僅僅是?來防?區塊被隨意?成,造成測驗?絡擁堵,完全是義務勞動,不存在作惡的動機,因此這種機制在 測驗?絡上是可?的,

Kovan與主?絡使?不同的共識機制,影響的僅僅是誰有權來?成區塊,以及驗證區塊是否有效的?式,權威節點可以 根據開發?員的申請?成以太幣,并不影響開發者測驗智能合約和其他功能,

Rinkeby

Rinkeby也是以太坊官?提供的測驗?絡,使?PoA共識機制,(獲取測驗幣?較困難)

5 開發環境搭建

remix在線編譯器

訪問鏈接,方便除錯,但是依賴網路,需翻墻,

https://remix.ethereum.org/

舊版界面

左側是檔案夾,右側 compile 編譯合約, run 使用deploy部署合約,At address(輸入合約地址,可以加載合約)

搭建本地網路

方便除錯,相對穩定,

npm install remix-ide -g
啟動
remix-ide

訪問 http://localhost:8080,即可打開本地編譯器,

編譯合約

remix編輯器中?動集成了solidity的編譯器,所以可以?動編譯我們的合約代碼

編譯原理

使?remix,由?級語?變成機器語?

  • solidity ---> bytecode(機器語?,區塊鏈系統讀取)

格式片段

6080604052610410806100136000396000f300608060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063368b87721461005c578063ce6d41de146100c5578063e21f37ce14610155575b600080fd5b34801561006857600080fd5b506100c3600480360381019080803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091929192905050506101e5565b005b3480156100……
  • solidity ---> ABI (application binary interface)(?便程式員調?)

json格式的描述?件

[
	{
  	"constant": false,
    "inputs": [
    		{
      	"name": "newMessage",
        "type": "string"
        }
……
]

圖示

6 常見概念

gas(汽油)(油耗)由于以太坊是公鏈,所有?都可以?由的參與,為了防?垃圾資料充斥?絡,所以以太坊上規定每?個操作都是要 有成本的,這個成本由 gas 來體現,你要轉賬,部署智能合約,調?智能合約?法,都要消耗?定數量的gas,
gasprice(汽油價格)(油價)

雖然操作消耗gas,但是最終真正花的還是eth,所以就有?個轉換率的問題,gasprice就是起到?個匯率的作?, 它代表的是?個gas值多少eth,gas*gasprice就是最終的?續費,也就是從你賬戶扣除的eth,

這種設計就可以保證?戶在以太坊上的操作的?續費不會隨著eth的價格?發?劇烈的變動(例如:如果eth漲,那 么可以調低gasprice來降低?續費),

gaslimit(汽油上限) (油箱)以太坊規定,每筆交易的gas最少21000,礦?可以調整這個值,所以最終的花費的gas是不確定的,所以以太坊就 設定了gaslimit,這個代表的是最多給曠?這么多gas(==防???寫的合約??有死回圈==),如果最終使?的 gas少于這個gaslimit,剩余的還會返給你的,但是如果你的gaslimit不?以?付這次交易,那就是不會退回的,并且交易也就失敗了,轉賬的額度也是回不來了,所以你轉賬設定的limit?定要?于21000,

每個操作中gas的成本

摘?以太坊??書

https://github.com/wanshan1024/ethereum_yellowpaper/blob/master/ethereum_yellow_paper_cn.pdf

7 Solidity基礎語法

7.1 資料型別分類

資料型別思維導圖

https://naotu.baidu.com/file/8ea7d69f9df11dc89433d37d818214de

  1. 值型別(值傳遞)
  2. 參考型別(指標傳遞)

值型別

值型別是指變數在傳遞程序中將數值完整的copy一份,再賦值給新的變數,

這種方式需要重新開辟新的記憶體空間,兩個變數完全獨立,互不影響,修改一個不會影響另外一個,缺點是效率低,

值型別包含

  • 布爾(bool)
  • 整形(int)
  • 地址(address)
  • 定長陣列(byte1……byte32)
  • 有理數(小數)
  • 列舉(enums)
  • 函式(function)

參考型別

solidity沒有指標型別,對于復雜的結構進行高效傳遞方式(相當于指標)是使用關鍵字storage進行修飾,

簡單來說就是,如果在變數之前添加storage就是參考傳遞,不加就是值傳遞,但是只對復雜型別有效,

復雜型別,占用空間較大,所以考慮通過參考傳遞,

參考型別包含

  • 字串
  • 不定長陣列
  • 陣列
  • 結構體
  • mapping

7.2 remix的使用--第一個智能合約

合約包含的基本元素

//指定solidy編譯器版本,版本識別符號
pragma solidity ^0.4.25;

//關鍵字 contract 跟java的class一樣  智能合約名稱是helloworld
contract helloworld {
    //狀態變數
    //string 是資料型別,message是成員變數,在整個智能合約生命周期都可以訪問
    //public 是訪問修飾符,是storage型別的變數,成員變數和是全域變數
    string public message;
    //address 是地址型別,
    address public manager;
    
    //建構式,這里在合約部署時將合約所有者傳入
    constructor () public {
        manager = msg.sender; 
    }
   //函式以function開頭
    function setMessage (string _message) public {
        //區域變數
        string memory tmp;
        tmp = _message;
        message = tmp;
    }
    //view是修飾符,表示該函式僅讀取成員變數,不做修改
    function getMessage() public view returns (string) {
        return message;
    }
}

選擇auto compile 自動編譯

智能合約的部署與呼叫,默認使用VM即可,

JavaScript VM web內置的虛擬機,除錯方便,我們使用這個,

Injected Web3 鏈接metamask

Web3 Provider 鏈接自定義網路,

常見錯誤:

  1. contract 誤寫為 constant
  2. 句末忘記添加分號
  3. 修改代碼后要重新create(舊版),新版本(deploy)重新部署合約,
  4. 在remix中,?動調?setMessage?法的時候,沒有加雙引號(英?的引號,否則報錯)
  5. 調?setMessage之后,沒有檢查是否設定成功,直接調?getMessage?法
  6. compile?直是紅?的,提示:Compiler not found,需要在Compile中選擇版本

7.3 值型別

7.3.1 布爾

bool b1;
bool b2 = false;
bool b3 = true;

7.3.2 整形

  • int(有符號整型,有正有負)
  • uint(無符號整型,無負數)
  • 以8位為區間,支持int8,int16,int24 至 int256,uint同理, ==int默認為int256,uint默認為uint256
pragma solidity ^0.4.25;
//int
contract test2 {

    
    int public i256 = 256;
    int8 public i8 = 1;
    
    function add() constant returns(int) {
        return i8 + i256; //257
    }

   function isEqual(int a, int b) public pure returns(bool) {
       return a == b;
   }
   //回傳true
}

7.3.3 函式型別

函式型別也就是我們所說的函式,本身也是一個特殊的變數,它可以當做變數賦值當做函式引數傳遞當做回傳值

函式名,函式簽名(回傳值,引數型別,修飾符)

函式的幾個關鍵字

修飾符說明
public共有,任何人(擁有以太坊賬戶的)都可以呼叫,
private私有,只有智能合約內部可以呼叫,
external僅合約外部可以呼叫,合約內部可以使用this呼叫
interanl僅合約內部和繼承的合約可以呼叫
view/constant函式會讀取但是不會修改任何合約的狀態變數
pure(純凈的)函式不使用任何智能合約的狀態變數
payable呼叫函式需要付錢,錢付給了智能合約的賬戶
returns指定函式回傳值

pragma solidity ^0.4.25;

//function
contract Test3 {
    //狀態變數
    //型別不匹配時需要顯示轉換型別
    //回傳值需要使用returns描述

    //public/private 可以修飾狀態變數
    //狀態變數默認是私有的
    uint256 public ui256 = 100;
    int8 private i10 = -10;

    //private 修飾的函式為私有的,只有合約內部可以呼叫
    function add() private view returns(uint256) {
        return ui256 + uint256(i10);
    }

    function isEqueal() public view returns(bool) {
        return ui256 == uint256(i10);
    }

    //Public修飾的函式為共有的,合約內外都可以呼叫
    function Add() public view returns(uint256){
        return add();
    }
}

常用關鍵字說明 viewconstantpure

1. 如果?個函式??,訪問了狀態變數,但是沒有修改,我們使?view或者constant修飾,

2. 如果訪問了狀態變數,?且修改了,那么就不能constant和view,否則會報錯,不修飾即可,

3. 如果沒有使?過狀態變數,我們要修飾為pure,

4. 如果你修飾為constant,但是你在函式中修改了,效果是:不會報錯,正常執?,但是值不會改變,

//常用關鍵字說明 view,constant,pure
contract test4 {

    int8 public i8 = 100; //成員變數就是狀態變數
    int i256 = 256;

    //表示不會修改函式內的狀態變數
    //為了明確語意,一般要加上constant(view兩者完全相同)
    function add() private constant returns(int) {
        return i8 + i256;
    }

    //public 表示所有的人都可以看到的,而且可以呼叫
    //private表示所有人都可以看到,但是無法呼叫
    function mins() constant returns(uint256) {
        return  uint256(i256 - i8); 
    }

   function isEqual(int a, int b) public pure returns(bool) {
       return a == b;
   }
		//可以修改i8
    function setValue(int8 num) {
        i8 = num;
    }
    
    //修飾為constant,在函式中修改了,效果是:不會報錯,正常執?,但是值不會改變
  	function setValue1(int8 num) constant {
        i8 = num;
    }
}

關鍵字payable

  1. 任何函式,只要修飾為payable,那么就可以在呼叫這個方法的時候,對value欄位賦值,然后將價值value的錢轉給合約
  2. 若這個函式沒有指定payable,但是對value賦值了,那么本次呼叫會報錯,
//payable
contract  test5 {
    
    string public str;
    //修飾為payable的函式才可以接收轉賬
    function test1(string src) public payable {
        str = src;
    }
    //不指定payable無法接收,呼叫,如果傳入value,會報錯
    function test2(string src) public {
        str = src;
    }
  
    function getbalance() public view returns(uint256) {
        //this代表當前合約本身
        //balance方法,獲取當前合約的余額
        return this.balance;
    }
}

建構式和匿名函式

建構式:僅在部署合約時呼叫一次,完成對合約的初始化,可以在創建合約時轉錢到合約,相當于go里面的init函式,

  1. 合約同名函式(已廢棄)
  2. constructor關鍵字修飾(推薦)

匿名函式

  • 用于轉賬

一個合約可以有且只有一個匿名函式,此函式不能有引數,也不能有任何回傳值,當我們企圖去執行一個合約上沒有的函式時,那么合約就會執行這個匿名函式,

當合約在只收到以太幣的時候,也會呼叫這個匿名函式,而且一般情況下會消耗很少的gas,所以當你接收到以太幣后,想要執行一些操作的話,你盡可以把你想要的操作寫到這個匿名函式里,因為這樣做成本非常便宜,

contract test6 {
    //建構式,合約同名函式(已廢棄)
    // test6() {
        
    // }
    //建構式,constructor關鍵字修飾
    constructor () {
        //初始化內容
    }
    
    //如果想向合約轉賬,在合約中添加如下函式即可
    function() payable {
    //函式體什么都不填
    }
   
   //balance方法,獲取當前合約的余額 
    function getbalance() public view returns(uint256) {
        //this代表當前合約本身余額
        return this.balance;
    }
}

fallback 也被稱為回滾函式,呼叫payable,花費最少的gas,省錢,

7.3.4 地址(Address)

以太坊地址的?度,?? 20個位元組 ,20 * 8 = 160位 ,所以可以??個 uint160 編碼,地址是所有合約的基礎,所有的合約都會繼承地址物件,通過合約的地址串,調?合約內的函式,

運算子

描述符號
比較運算<=,<,==, !=, >=,>

地址操作

屬性/方法含義備注
balance獲取余額屬性,其余的都是方法,
send轉賬不建議使用
transfer轉賬建議使用
call合約內部呼叫合約
delegatecall 調底層代碼,別用
callcode 調底層代碼,別用

注意:call(),delegatecall(),callcode() 都是底層的訊息傳遞呼叫,最好不用,除非萬不得已再用,因為他們破壞了Solidity的型別安全,

contract  test7 {

    address public addr1 = 0xca35b7d915458ef540ade6068dfe2f44e8fa733c;
    //地址address型別本質上是一個160位的數字
    //可以進行加減,需要強制轉換
    function add() public view returns(uint160) {
        return uint160(addr1) + 10;
    }

    //1. 匿名函式:沒有函式名,沒有引數,沒有回傳值的函式,就是匿名函式
    //2. 當呼叫一個不存在的方法時,合約會默認的去呼叫匿名函式
    //3. 匿名函式一般用來給合約轉賬,因為費用低
    function () public  payable {

    }
		//獲取addr1的余額
    function getBalance() public view returns(uint256) {
        return addr1.balance;
    }

    function getContractBalance() public view returns(uint256) {
        //this代表當前合約本身
        //balance方法,獲取當前合約的余額
        return address(this).balance;
    }
}

除錯結果如下:

合約地址(this)

如果只是想回傳當前合約賬戶的余額,可以使? this 指標, this 表示合約?身的地址

//this
contract  test8 {
    //1. 匿名函式:沒有函式名,沒有引數,沒有回傳值的函式,就是匿名函式
    //2. 當呼叫一個不存在的方法時,合約會默認的去呼叫匿名函式
    //3. 匿名函式一般用來給合約轉賬,因為費用低
    function () public  payable {

    }

    function getContractBalance() public view returns(uint256) {
        //this代表當前合約本身
        //balance方法,獲取當前合約的余額
        return this.balance;
        // return address(this).balance;
    }
}

轉賬(sendtransfer

send和transfer函式提供了由合約向其他地址轉賬的功能,

描述引數回傳值
send單位 wei轉賬金額true/false
transfer比send更安全轉賬金額無(出錯拋例外)

//send和transfer函式提供了由合約向其他地址轉賬的功能
contract  test9 {

    address public addr0 = 0x00ca35b7d915458ef540ade6068dfe2f44e8fa733c;
    address public addr1 = 0x0014723a09acff6d2a60dcdf7aa4aff308fddc160c;

    //1. 匿名函式:沒有函式名,沒有引數,沒有回傳值的函式,就是匿名函式
    //2. 當呼叫一個不存在的方法時,合約會默認的去呼叫匿名函式
    //3. 匿名函式一般用來給合約轉賬,因為費用低
    function () public  payable {

    }

    function getBalance() public view returns(uint256) {
        return addr1.balance;
    }

    function getContractBalance() public view returns(uint256) {
        return address(this).balance;
    }

    //由合約向addr1 轉賬10以太幣
    function transfer() public {
        //1. 轉賬的時候單位是wei
        //2. 1 ether = 10 ^18 wei (10的18次方)
        //3. 向誰轉錢,就用誰呼叫tranfer函式
        //4. 花費的是合約的錢
        //5. 如果金額不足,transfer函式會拋出例外
        addr1.transfer(10 * 10 **18);
    }

    //send與tranfer使用方式一致,但是如果轉賬金額不足不會拋出例外,而是會回傳false
    function sendTest() public {
        addr1.send(10 * 10 **18);
    }
}

7.3.5 列舉型別(enums)

  • 列舉型別是在Solidity中的一種用戶自定義型別,
  • 列舉可以顯示的轉換與整數進行轉換,但不能進行隱式轉換,顯示的轉換會在運行時檢查數值范圍,如果不匹配,將會引起例外,
  • 列舉型別應至少有一名成員,列舉元素默認為uint8,當元素數量足夠多時,會自動變為uint16,第一個元素默認為0,使用超出范圍的數值時會報錯,
//enum
contract test10 {

    enum WeekDays {
      	//0 -- 6
        Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday
    }

    WeekDays currentDay;
    WeekDays defaultday = WeekDays.Sunday;
		//設定,如果超過6,比如7會拋例外
    function setDay(WeekDays _day) public {
        currentDay = _day;
    }
		
    function getDay() public view returns(uint256) {
        return uint256(currentDay);
    }
		//除錯結:6
    function getDefaultDay() public view returns(uint256) {
        return uint256(defaultday);   
    }
}

7.3.6 定長位元組陣列

solidity內置了一些陣列的資料型別:(和go語言做一下對比, var b8 [8]byte),完全只讀

  • bytes1, ... ,bytes32,允許值以步長1遞增,
  • ==byte默認表示bytes1,byte是型別,bytes是型別,bytes1是內置陣列==
  • bytes1只能存盤1個位元組,即8位的內容,bytes2最多只能存盤2個位元組,即16位的內容,以此類推...
  • 長度可以讀取 length(回傳bytes5型別的長度,而不是賦值的長度)
  • 長度不可以修改
  • 可以通過下標訪問
  • 內容不可修改
  • 內置成員:length,回傳陣列長度
  • 存盤方式:16進制ascii碼

支持運算:

描述運算子
比較運算<=,<,==,!=,>=,>
位運算子&,\,^(異或),~非
下標訪問[0,n),n表示長度

//定長的位元組陣列
contract  test11 {

    bytes1 b1 ="h";
    
    bytes20 b10 = "helloworld";
    //bytes10 public b10 = 0x68656c6c6f776f726c64; //length == 20
    function getLen() public view returns(uint256) {
        return b10.length;
    }
    
    function setValue() public pure{
        //1. 固定長度陣列可以通過下標訪問
        //2. 只能讀取,不能寫
        // b1[0] = v;
    }
    
    //3. 存盤的時候是ascii值存盤
    function getValue(uint256 i) public view returns(byte) {
        return b10[i];
    }
    //length == 20,acsii的長度
    function getLenth() public view returns(uint256) {
        return b10.length;
    }
    
}

在線轉換工具 http://www.ab126.com/goju/1711.html

7.4 參考型別

參考型別包含:字串,不定長陣列,陣列,結構體,映射 (mapping)

7.4.1 不定長陣列

bytes 相當于golang []byte

  • 可以修改
  • 支持下標索引
  • 參考型別(表明可以使用storage來修飾,進行參考傳遞,指標的效果)
  • 支持lengthpush方法(push會幫助分配空間的)
  • 以十六進制格式賦值: 'h' -> 0x68 -> 104
  • 格外注意:對于bytes,如果不使用下標訪問,那么可以不用先申請空間, 直接賦值即可,或者直接push,

contract  test12 {
    
    bytes public name;
    
    function getLen() public view returns(uint256) {
        return name.length;
    }

    //1. 可以不分空間,直接進行字串賦值,會自動分配空間
    function setValue(bytes input) public {
        name = input;
    }
    
    //2. 如果未分配過空間,使用下標訪問會訪問越界報錯
	  //0x68656c6c6f776f726c64 == "hello"
    function getByIndex(uint256 i) public view returns(byte) {
        return name[i];
    }
    
    //3. 可以設定長度,自動分配對應空間,并且初始化為0
    function setLen(uint256 len) public {
        name.length = len;
    }

    //4.可以通過下標進行資料修改
    function setValue2(uint256 i) public {
        name[i] = "H";
    } 
    
    //5. 支持push操作,在bytes最后面追加元素
    function pushData() public {
        name.push('h');
    }
    
}

7.4.2 字串(string)

  • 動態尺?的UTF-8編碼字串,是特殊的可變位元組陣列
  • 引?型別
  • 不?持下標索引
  • 不?持lengthpush?法
  • 可以修改(需通過bytes轉換)

contract  test13 {

    string public name = "lily";   

    function setName() public {
        bytes(name)[0] = "L";
        //name[0] = "H"; //ERROR,不?持下標索引
    }

    function getLength() public view returns(uint256) {
        return bytes(name).length;
    }
		
    function setLength(uint256 i) public {
        bytes(name).length = i;

        bytes(name)[i - 1] = "H";
    } 
}

7.4.3 參考型別的記憶體分配(memory 和 storage)

參考型別(復雜型別),不同于之前 值型別 ,占的空間更?,超過256位元組,因為拷?它們占?更多的空間,如陣列(arrays) 和 資料結構(struct) ,他們在Solidity中有?個額外的屬性,即資料的存盤位置: memory 和 storage ,

記憶體(memory

  • 資料不是永久存在的,存放在記憶體中,越過作?域后?法訪問,等待被回收,
  • 被memory修飾的變數是直接拷?,即與上述的值型別傳遞?式相同,

存盤 (storage)

  • 資料永久保存在,
  • 被storage修飾的變數是引?傳遞,相當于只傳地址,新舊兩個變數指向同??記憶體空間,效率較?,兩個變數有關聯,修改?個,另外?個同樣被修改,
  • 只有引?型別的變數才可以顯示的宣告為 storage (注意:值型別使用storage無效)
  • 所有修飾為storage都是上鏈的,

狀態變數

  • 宣告在合約開頭,相當于golang和其他語言中的全域變數,
  • 狀態變數總是stroage型別的,?法更改,

區域變數

  • 區域變數,默認是storage型別(僅限資料結構或陣列,string),但是可以宣告為memory型別,
  • 狀態變數,默認是storage變數,所有修飾為storage都是上鏈的,

storage Vs Memory

  1. 呼叫call1,呼叫 setName, name不會被修改,num會被修改,
  2. 呼叫call2,呼叫setName2, name會被修改,num會被修改,
  3. 呼叫localTest,name會被修改,num會被修改,
  4. 呼叫localTest1,name不會被修改,num會被修改,

//memory vs storage
contract  test14 {
    string public name = "lily";
    uint256 public num = 10;
    
    function call1() public {
        setName(name);    
    }
    
    
    //對于參考型別資料,作為函式引數時,默認是memory型別(值傳遞)
    //function setName(string input) private {
    function setName(string memory input) private {
        num = 20;
        bytes(input)[0] = "L";
    }
    
    function call2() public {
        setName2(name);
    }
    
    //2. 如果想參考傳遞,那么需要明確指定為stroage型別
    function setName2(string storage input) private {
        num = 30;
        bytes(input)[0] = "L";
    }
    
    //如果局部變數是string,陣列,結構體型別資料,默認情況下是storage型別
    function localTest() public {
        //string tmp = name;
        string storage tmp = name; //默認情況下是storage型別
        num = 40;
        bytes(tmp)[0] = "A";
    }
    
    function localTest1() public { 
        //也可以明確設定為memory型別
        string memory tmp = name;
        num = 50;
        bytes(tmp)[0] = "B";
    }
}

7.4.4 轉換(byte1/bytes/string)

  1. 轉換程序:先將固定陣列逐個復制,轉成bytes,然后轉成string
  2. string可以直接轉成bytes

  1. 呼叫bytesToString,呼叫fixedByteToBytes,將bytes轉換成string
  2. 呼叫stringToBytes,呼叫bytesToString,將string轉成bytes
//bytes1, bytes,string 轉換
contract  test15 {
    //定長陣列
    bytes10 public b10 = 0x68656c6c6f776f726c64; //helloworld
    //不定長陣列
    bytes public bs10 = new bytes(b10.length);
    
    //將固定長度陣列的值賦值給不定長度陣列
    function fixedByteToBytes() public {
        //bs10 = b10;
        for (uint256 i = 0; i < b10.length; i++) {
            bs10[i] = b10[i];
        }
    }

    //將bytes轉成string
    string public str1; //string
    
    function bytesToString() public {
        fixedByteToBytes();
        str1 = string(bs10);
    }
    
    //將string轉成bytes
    bytes public bs20;
    
    function stringToBytes() public {
        bytesToString();
        bs20 = bytes(str1);
    }
}

7.4.5 陣列

內置陣列

  • string(不定?)
  • bytes(不定?)
  • bytes1...bytes32(定?)

自定義陣列

相當于golang numbers [10] uint

  • 型別T,長度K的陣列定義為T[K],例如:uint [5] numbers, byte [10] names;
  • 內容可變
  • 長度不可變,不支持push
  • 支持length方法
//自定義定長陣列
contract  test16 {

    //Type[Len] name
    uint256[10] public numbers = [1,2,3,4,5,6,7,8,9, 10];

    uint256 public sum;

    // - 型別T,長度K的陣列定義為T[K],例如:uint [5] numbers,  byte [10] names;
    // - 內容可變
    // - 長度不可變,不支持push
    // - 支持length方法

    function total() public returns(uint256) {
        for (uint256 i = 0; i < numbers.length; i++) {
            sum += numbers[i];
        }

       return sum; //55
    }

    function setLen() public {
        // numbers.length = 10;
    }
    
    function changeValue(uint256 i , uint256 value) public {
        numbers[i] = value;
    }

    //++++++++++++++++++++++++++++++++++

    bytes10 public helloworldFixed = 0x68656c6c6f776f726c64;

    byte[10] public helloworldDynamic = [byte(0x68), 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x6f, 0x72, 0x6c, 0x64];

    bytes public b10;
    //bytes10 to bytes
    function setToBytes() public  returns (string){
        for (uint256 i=0; i< helloworldDynamic.length; i++) {
            byte b1 = helloworldDynamic[i];
            b10.push(b1);
        }

        return string(b10);
    }
}

不定長陣列

  • 定義格式為T [ ],例如:string[ ] names, byte[ ] citys,
  • 內容可以修改
  • 可以改變長度(僅限storage型別) 支持lengthpush方法
  • memory型別的不定長陣列不支持修改長度
  • 即使沒有手動分配空間,直接改變長度,那么也會自動分配空間
contract  test17 {

    //第一種創建方式,直接賦值
    uint8[] numbers = [1,2,3,4,5,6,7,8,9,10];

    function pushData(uint8 num) public {
        numbers.push(num);
    }

    function getNumbers() public view returns(uint8[]) {
        return numbers;
    }

    //第二種:使用new關鍵字進行創建,賦值給storage變數陣列
    uint8[] numbers2;

    function setNumbers2() public {
        numbers2 = new uint8[](0);
        numbers2.length = 20;
        numbers2.push(10);
    }

    function getNumbers2() public view returns(uint8[]) {
        return numbers2;
    }

    function setNumbers3() public {
        //使用new創建的memory型別陣列,無法改變長度
        uint8[] memory numbers3 = new uint8[](7);
        // uint8[] memory numbers3;

        // numbers3.length = 100; //無法修改
        // numbers3.push(x0);
    }
}

二維陣列

TODO

7.4.6 結構體

contract test18 {
    //定義結構之后無分號,與列舉一致
    struct Student {
        string name;
        uint age;
        uint score;
        string sex;
    }

    Student[] public students;


    //兩種賦值方式
    Student public stu1 = Student("lily", 18, 90, "girl");
    Student public stu2 = Student({name:"Jim", age:20, score:80, sex:"boy"});

    function assign() public {
        students.push(stu1);
        students.push(stu2);

        stu1.name = "Lily";
    }
}

7.4.7 字典/映射/hash表(mapping

相當于golang map,Python中的字典

  • 鍵key的型別允許除映射外的所有型別,如陣列,合約,列舉,結構體,值的型別無限制,
  • 無法判斷一個mapping中是否包含某個key,因為它認為每一個都存在,不存在的回傳0或false,
  • 映射可以被視作為一個哈希表,在映射表中,==不存盤鍵的資料==,僅僅存盤它的keccak256哈希值,用來查找值時使用,
  • 映射型別,僅能用來定義狀態變數,或者是在內部函式中作為storage型別的參考,
  • 不支持length,

contract test19 {
    //id -> name
    mapping(uint => string) public id_names;
    
    //建構式:
    //1. 物件在創建的時候,自動執行的函式,完成物件的初始化作業
    //2. 建構式僅執行一次
    // function Test() public {
        
    // }

    constructor()  public{
        id_names[1] = "lily";
        id_names[2] = "Jim";
        id_names[3] = "Lily";
        id_names[3] = "Tom"; //覆寫 
    }
    
    function getNameById(uint id)  public view returns (string){
        //加上storage如何賦值?
        string memory name = id_names[id];
        return name;
    }
    //將輸入的key值修改為Hello
    function setNameById(uint id)  public returns (string){
        // mapping(uint => string) memory id_name = id_names;
        // var ids = id_names;
        id_names[id] = "Hello";
    }
    
    
    // function getMapLength() public returns (uint){
    //     return id_names.length;
    // }
    
}

8 Solidity高級語法

8.1 ?動推導var(忘了她吧)

為了?便,并不總是需要明確指定?個變數的型別,編譯器會通過第?個向這個物件賦予的值的型別來進?推斷,

uint24 x = 0x123;
var y = x;

需要特別注意的是,由于型別推斷是根據第一個變數進行的賦值,所以下面的代碼將是一個無限回圈,因為一個uint8的i的將小于2000,

for (var i = 0; i < 2000; i++)
{
    //uint8 -> 255 永遠 <2000
    //無限回圈
}

//var 
contract test20{
    function a() view returns (uint, uint){
        uint count = 0;
        var i = 0;
        for (; i < 257; i++) {
            count++;
          	//防止死回圈
            if(count >= 260){
                break;
            }
        }
        return (count, i);
    }
}

結果:

0: uint256: 260
1: uint256: 3

分析:
i, count
255, 256
//溢位
0, 257
1, 258
2, 259
3, 260


00
01
10

11111111111111111111111
1000000000000000
1000000000000001

8.2 全域函式/變數

函式含義
block.blockhash(uint blockNumber)哈希值(byte32)
block.coinbase(address) 當前塊礦?的地址
block.diffiffifficulty (uint)當前塊的難度
block.gaslimit (uint)當前塊的gaslimit
block.number(uint)當前區塊的塊號
block.timestamp (uint)當前塊的時間戳
msg.data(bytes)完整的調?資料(calldata)
msg.gas(uint)當前還剩的gas
msg.sender (address)當前調?發起?的地址
msg.sig(bytes4)調?資料的前四個位元組(函式識別符號)
msg.value (uint)這個訊息所附帶的貨幣量,單位為wei
now (uint)當前塊的時間戳等同于block.timestamp
tx.gasprice(uint) 交易的gas價格
tx.origin (address)交易的發送者(完整的調?鏈)

最重要的兩個全域變數(msg.sender 和 msg.value

注意除錯此處代碼,需要開啟ganache,查看區塊資訊,

contract test21 {
    
    bytes32 public blockhash1;
    address public coinbase;
    uint public difficulty;
    uint public gaslimit;
    uint public blockNum;
    uint public timestamp;
    bytes public calldata;
    uint public gas;
    address public sender;
    bytes4 public sig;
    uint public msgValue;
    uint public now1;
    uint public gasPrice;
    address public txOrigin;
    
    function test() public payable {
        
        blockNum = block.number;// (uint)當前區塊的塊號,
        //給定區塊號的哈希值,只支持最近256個區塊,且不包含當前區塊
        blockhash1 = blockhash(block.number - 1);
        coinbase = block.coinbase ;//當前塊礦工的地址,
        difficulty = block.difficulty;//當前塊的難度,
        gaslimit = block.gaslimit;// (uint)當前塊的gaslimit,

        timestamp = block.timestamp;// (uint)當前塊的時間戳,
        calldata = msg.data;// (bytes)完整的呼叫資料(calldata),
        gas = gasleft();// (uint)當前還剩的gas,
        sender = msg.sender; // (address)當前呼叫發起人的地址,
        sig = msg.sig;// (bytes4)呼叫資料的前四個位元組(函式識別符號),
        msgValue = msg.value;// (uint)這個訊息所附帶的貨幣量,單位為wei,
        now1 = now;// (uint)當前塊的時間戳,等同于block.timestamp
        gasPrice = tx.gasprice;// (uint) 交易的gas價格,
        txOrigin = tx.origin;// (address)交易的發送者(完整的呼叫鏈)  
    }
}

8.2.3 msg.sender (重要)

每一次和以太坊互動時都會產生一筆交易,這筆交易的執行人就是msg.sender,簡而言之:誰呼叫的,msg.sender就是誰,每筆交易的msg.sender都可以不同,舉例:

  • 部署合約的時候,msg.sender就是部署的賬戶,
  • 呼叫setMessage時,msg.sender就是呼叫賬戶,
  • 呼叫getMessage時,msg.sender就是呼叫賬戶,
contract  test22 {

    address public owner;
    uint256 a;
    address public caller;

    constructor() public {
        //在部署合約的時候,設定一個全域唯一的合約所有者,后面可以使用權限控制
        owner = msg.sender;
    }
		//切換賬號除錯,查看caller
    //1. msg.sender是一個可以改變的值,并不一定是合約的創造者
    //2. 任何人呼叫了合約的方法,那么這筆交易中的from就是當前msg.sender
    function setValue(uint256 input) public {
        a = input;
        caller = msg.sender;
    }
}

8.2.4 msg.value (重要)

我們在介紹payable關鍵字的時候說,如果函式修飾為payable,那么這個函式可以接收轉賬,這筆錢通過remix的value輸入框傳遞進來,

在轉賬操作中,這筆錢是通過我們呼叫一個函式從而產生一筆交易而轉入合約的,換句話說,是這筆交易附帶了一筆錢,在合約中,每次轉入的value是可以通過msg.value來獲取到的,

注意:

  1. 單位是wei,
  2. 有msg.value,就必須函式有payable關鍵字,
//msg.value
contract  test23 {

    //uint256 public money;

    mapping(address=> uint256) public whoToMoney;

    //函式里面使用了msg.value,那么函式要修飾為payable
    function paly() public payable {

        // 如果轉賬不是100wei,那么參與失敗
        // 否則成功,并且添加到維護的mapping中
        if (msg.value != 100) {
            throw;
        }
				//map呼叫者的address,對應值是msg.value,記錄到map中,
        whoToMoney[msg.sender] = msg.value;

    }

    function getBalance() public view returns(uint256) {
        return address(this).balance;
    }
}

8.3 錯誤處理

在創建合約時設定owner(合約的所有人)

傳統方法:采用 throw 和 if ... throw 模式==(已過時)==,例如合約中有一些功能,只能被授權為擁有者的地址才能呼叫

contract test24 { 

    //定義變數:型別 + 變數名
    string public message;   // var name string
    address public manager; //合約的部署者(擁有者)
    address public caller;  //合約函式的呼叫者


    constructor() payable public{
        manager = msg.sender;
    }

    function setMessage(string newMessage) public {
        caller = msg.sender;

        // if (manager != msg.sender) {
        //     throw; //如果函式呼叫者不是管理員,直接拋例外
        // }


        // 斷言:
        // 1. 一條陳述句,既包含了條件,又可以拋例外(推薦)
        // 2. 條件是期望的結果,與普通的條件判斷相反
        //   (條件為true,繼續執行,條件為false,拋出例外)

        // require(manager == msg.sender);
        assert(manager == msg.sender);

        message = newMessage;

    }

    //如果有回傳值,一定要加上returns關鍵字,使用()包裹起來    
    function getMessage() public constant returns(string){
        return message;
    }
}

錯誤的幾種等價

if(msg.sender != owner) { 
    throw; 
}
//等價于如下任意一種形式:
if(msg.sender != owner) { 
    revert(); //和throw沒啥區別
} 

//assert和require是推薦的方式,里面的引數要求值為true,即期望的結果
assert(msg.sender == owner); 
require(msg.sender == owner);

8.4 修飾器(modifier

有點像中間件

  • 修改器(Modifiers)可以用來輕易的改變一個函式的行為,
  • 比如用于在函式執行前檢查某種前置條件,
  • 修改器是一種合約屬性,可被繼承,同時還可被派生的合約重寫(override),

contract  test25 {
    
     //定義變數:型別 + 變數名
    string public message;   // var name string
    address public manager; //合約的部署者(擁有者)
    address public caller;  //合約函式的呼叫者


    constructor() payable public{
        manager = msg.sender;
    }

    //一個函式可以使用多個修飾器
    function setMessage(string newMessage) public onlyManager onlyManager2(msg.sender){
        caller = msg.sender;
        message = newMessage;

    }

    //如果有回傳值,一定要加上returns關鍵字,使用()包裹起來    
    function getMessage() public constant returns(string){
        return message;
    }

    modifier onlyManager {
        require(manager == msg.sender);
        _; //下劃線代表修飾器所修飾的代碼
    }

    //修飾器可以帶有引數
    modifier onlyManager2(address _caller) {
        require(manager == _caller);
        _; //下劃線代表修飾器所修飾的代碼
    }

}

8.5 兩個常用單位

8.5.1 貨幣單位

  • 一個字面量的數字,可以使用后綴weifinneyszaboether來在不同面額中轉換,
  • 不含任何后綴的默認單位是wei,如1 ether == 1000 finney的結果是true
  • 不同的場景下習慣使用不同的單位,通常交易行都是以Ether為單位,購買一杯咖啡之類的小額交易使用Finney,計算Gas價格時一般使用GWei,在以太坊代碼開發中使用最基本的單位Wei,

參考 https://ethgasstation.info/blog/gwei/

https://www.investopedia.com/terms/g/gwei-ethereum.asp

https://my.oschina.net/u/3734107/blog/1839814

Kwei (babbage) 1e3 wei 1,000 (K 是 kilo)

Mwei (lovelace) 1e6 wei 1,000,000 (M million)

Gwei (shannon) 1e9 wei 1,000,000,000 (G giga 千兆/十億)

microether (szabo) 1e12 wei 1,000,000,000,000

milliether (finney) 1e15 wei 1,000,000,000,000,000

ether 1e18 wei 1,000,000,000,000,000,000

babbage 亨利·巴貝奇(Henry Babbage,1791-1871年)是一位英國數學家和機械工程師,被認為是計算機之父,

lovelace 杰出的數學家,詩人拜倫勛爵的女兒艾達·洛夫萊斯(Ada Lovelace,1815-1852年)

shannon 克勞德·香農(Claude Shannon,1916-2001年)是美國數學家和電氣工程師,被稱為“資訊論之父”,

szabo 1998年,尼克·薩博(Nick Szabo)設計了位元黃金(bit gold),一種去中心化的數字貨幣,據說也影響了中本聰(Satoshi Nakamoto)的位元幣設計,薩博提出并創造了“智能合約”這個術語,盡管他一再否認自己是中本聰,但他仍然是另一個被懷疑是中本聰的人,

finney 哈爾·芬尼(Hal Finney,1956-2014年)是加密活動家,PGP Corporation的開發人員,可重復使用的作業證明的創建者以及早期的位元幣貢獻者,Finney甚至是中本聰本人發送的位元幣交易的第一個接收者,

Ether(buterin) -對于以太坊的創建者Vitalik Buterin,

contract test26{
    uint  a = 1 ether;
    uint  b = 10 ** 18 wei;
    uint  c = 1000 finney;
    uint  d = 1000000 szabo;
    
    function f1() constant public returns (bool){
        return a == b;
    }
    
    function f2() constant public returns (bool){
        return a == c;
    }
    
    function f3() constant public returns (bool){
        return a == d;
    }
    
    function f4() pure public returns (bool){
        return 1 ether == 100 wei;
    }
}

時間單位

  • seconds,minutes,hours,days,weeks,years均可做為后綴,默認是seconds為單位,
  • 1 = 1 seconds
  • 1 minutes = 60 seconds
  • 1 hours = 60 minutes
  • 1 days = 24 hours
  • 1 weeks = 7 days
  • 1 years = 365 days
//time
contract test27{

    function f1() pure public returns (bool) {
        return 1 == 1 seconds;
    }
    
    function f2() pure public returns (bool) {
        return 1 minutes == 60 seconds;
    }
    
    function f3() pure public returns (bool) {
        return 1 hours == 60 minutes;
    }
    
    function f4() pure public returns (bool) {
        return 1 days == 24 hours;
    }
    
    function f5() pure public returns (bool) {
        return 1 weeks == 7 days;
    }
    
    function f6() pure public returns (bool) {
        return 1 years == 365 days;
    }
}

8.6 事件(Event)

相當于列印log,在remix看log欄位,在web3.js 代碼呼叫時可以看到,

contract  test28 {

    //uint256 public money;
    
    mapping(address=> uint256) public personToMoney;
    
    // 1. 定義一個事件,使用圓括號,后面加上分號
    // 2. 需要使用emit關鍵字
    // 3. 在web3呼叫時可以監聽到事件
    event playEvent(address, uint256, uint256);
    
    
    
    function paly() public payable {

        require(msg.value == 100);
        personToMoney[msg.sender] = msg.value;
        
        emit playEvent(msg.sender, msg.value, block.timestamp);
        
    }
    
    function getBalance() public view returns(uint256) {
        return address(this).balance;
    }

}

8.7 訪問函式(Getter Functions)

編譯器為自動為所有的public的狀態變數創建訪問函式,下面的合約例子中,編譯器會生成一個名叫data的無參,回傳值是uint的型別的值data,狀態變數的初始化可以在定義時完成,

contract  test29 {
    
    // 加了public 的轉態變數,solidity會自動的生成一個同名個訪問函式,
    // 在合約內部使用這個狀態變數的時候,直接當初變數使用即可
    // 如果在合約外面向訪問這個public變數(data),就需要使用xx.data()形式
    uint256 public data = 200;
    
    
    function getData() public view returns(uint256) {
        return data;
    }
    
    //This代表合約本身,如果在合約內部使用this自己的方法的話,相當于外部呼叫
    function getData1() public view returns(uint256) {
        //return this.data;   //不能使用.data形式
        return this.data();
    }
}
//is 是繼承
contract test30 is test29{
    //外部呼叫
    function getValue() public view returns(uint256) {
        test29 t1 = new test29();
        return t1.data();
    }
}

8.8 合約

8.8.1 合約的創建

創建合約和外部呼叫

  1. new關鍵字,回傳值是一個address,需要顯示轉化型別后才能使用,
  2. C c1形式,此時c1是空的,需要賦值地址才能使用,否則報錯,
pragma solidity ^0.4.25;

contract  C1 {
    
    uint256 public value ;
    
    constructor(uint256 input) public {
        value = input;
    }

    function getValue() public view returns(uint256) {
        return value;
    }
}

contract C2 {
    C1 public c1;  //0x0000000000000
    C1 public c11;  //0x0000000000000
    C1 public c13;
    
    function getValue1() public returns(uint256) {
        //創建一個合約,回傳地址
        address addr1 = new C1(10);  //balance , transfer方法
        //return addr1.getValue();
        
        //需要顯示的轉換為特定型別,才可以正常使用
        c1 = C1(addr1);
        
        return c1.getValue();
    }
    
    
    function getValue2() public returns(uint256) {
        
        //定義合約的時候,同時完成型別轉換
        c11 = new C1(20);
        return c11.getValue();
    }
    
    //
    function getValue3(address addr) public view returns(uint256) {
        //傳進來的地址必須是同型別的,如果是不是C1型別的,轉換時報錯
        c13 = C1(addr);
        return c13.getValue();
    }
}

8.8.2 合約的繼承

  • is關鍵字, 可以同時繼承多個父合約,
  • 當父合約存在同名函式時,默認為最遠繼承原則(離is最遠),
  • 可以指定某個父合約,呼叫它的方法,
contract Base1{
  function data() public pure returns(uint){
    return 1;
  }
}

contract Base2{
  function data() public pure returns(uint){
    return 2;
  }
}


// 1. 使用is關鍵字進行繼承,
// 2. 多個繼承間使用逗號分隔,
// 3. 如果兩個父合約含有相同方法,那么默認是最遠繼承原則

contract son1 is Base1, Base2{
    //return 2
}

//return 1
contract son2 is Base2, Base1{
    
}

//4. 可以指定父合約,呼叫特定的方法
contract son3 is Base1, Base2{
    function mydata() public pure returns(uint){
        return Base1.data();
    }
}
contract son4 is Base2, Base1{
    function mydata() public pure returns(uint){
        return Base2.data();
    }
}

8.8.3 合約間如何轉錢

創建兩個合約,先創建InfoFeed,然后創建Consumer,然后呼叫callFeed,向InfoFeed轉賬,

//合約間如何轉錢
contract InfoFeed {
    
    function info() public payable returns (uint ret) {
        return 42; 
    }
    
    function getBlance() public view returns(uint256) {
        return address(this).balance;
    }
}

contract Consumer {
    
    InfoFeed public feed; //0x0000000000000
    
    function setFeed(address addr) public { 
        feed = InfoFeed(addr);  //0xfeabcdf......
    }
    
    function callFeed() public { 
        //合約間轉賬語法,
        feed.info.value(10).gas(800)(); 
    }
    
    function () payable public {
        
    }
    
    function getBlance() public view returns(uint256) {
        return address(this).balance;
    }
}

1.部署合約InfoFeed,呼叫info,將合約中轉10eth

2.部署Consumer,呼叫fallback,向合約轉入10eth

3.呼叫callFeed

8.8.4 internal和external

訪問函式有外部(external)可見性,如果通過內部(internal)的方式訪問,比如直接訪問,你可以直接把它當一個變數進行使用,但如果使用外部(external)的方式來訪問,如通過this.,那么它必須通過函式的方式來呼叫,

pragma solidity ^0.4.25;


//private ,           intenal ,            external,            public
//合約本身可以呼叫,  合約及子類可以呼叫, 只能在合約外部呼叫, 可以被任意的合約呼叫

contract C1{
    uint public c = 10;

    function accessPrivate() private returns(uint) {
        return c;
    }

    function accessInternal() internal returns (uint){
        return c;
    }

    function accessExternal() external returns(uint){
        return c;
    }

    function call1() public returns(uint) {
        // accessExternal(); //無法在內部呼叫external修飾的函式
        accessInternal();
    }

    function call2() public {
        this.accessExternal(); //this呼叫函式,相當于外部呼叫

        // this.c;   // ok
        // uint a = this.c; // error
        uint b = this.c();   // ok
        // c();
    }

    function call3() public returns(uint) {

    }
}

contract C2{

    function callExternal() public returns(uint){
        C1 c1 = new C1();
        // external修飾的只能在外部呼叫
        return c1.accessExternal();

        //internal修飾的只能在內部呼叫
        // return c1.accessInternal();
    }
}

contract C3 is C1 {

    function test() public returns(uint) {
        // C1 c1 = new C1();
        // c1.accessPrivate();

        // this.accessInternal(); //error
        // c1.accessInternal(); // error
        return accessInternal();

    }

}

8.9 元組(tuple)

return(a, b, c)

solidity無法回傳自定義的資料結構,所以若想回傳一個自定義結構的資料,需要在函式中一次回傳多個值,即元組,元組是一個資料集合,類似于字典但是無法修改資料,使用圓括號包括多種資料型別,

  1. 可以包含多個資料
  2. 型別可以不同
  3. 不可以修改
  4. 使用圓括號包裹
contract tuple {
    
    struct Student {
        string name;
        uint age;
        uint score;
        string sex;
    }
    
    //兩種賦值方式
    Student public stu1 = Student("lily", 18, 90, "girl");
    Student public stu2 = Student({name:"Jim", age:20, score:80, sex:"boy"});

    Student[] public Students;
    
    function assign() public {
        Students.push(stu1);
        Students.push(stu2);
        
        stu1.name = "Lily";
    }
    
    //1. 回傳一個Student結構
    function getLily() public view returns(string, uint, uint, string) {
        require(Students.length != 0);
        
        Student memory lily = Students[0];
        
        //使用圓括號包裹的多個型別不一致的資料集合:元組
        return (lily.name, lily.age, lily.score, lily.sex);
    }
}

8.10 內置數學函式

ripemd160

keccak256

addmod

ecrecover

哈希函式,代替sha3(廢棄)

//keccak256

contract keccak256test {
    
    function test() public pure returns(bytes32){
        bytes memory v1 = abi.encodePacked("hello", "b", uint256(1), "hello");
        return keccak256(v1);
    }
    
    
    
    function test1() public pure returns(bytes32) {
        //bytes32 hash = sha3("hello", 1, "world", 2);
        //bytes32 hash = keccak256("hello", "b",  uint256(1), "hello");
        
        //return hash;
        return keccak256("hello", "world");
    }
}

8.11 其他

for、break、continue

8.11.1 new

創建物件,合約等

8.11.2 delete

  • delete運算子可以用于任何變數(map除外),將其設定成默認值
  • 如果對動態陣列使用delete,則洗掉所有元素,其長度變為0: uint[ ] array0 ; arry0 = new uint
  • 如果對靜態陣列使用delete,則重置所有索引的值: uint[10] array1 = [1,2,3,4,5,6];
  • 如果對map型別使用delete,什么都不會發生
  • 但如果對map型別中的一個鍵使用delete,則會洗掉與該鍵相關的值

//other
contract  other {
    
    //01. string 
    string public str1 = "hello";
    
    function deleteStr() public {
        delete str1;
    }
    
    function setStr(string input) public {
        str1 = input;
    }
    
    //02. array 對于固定長度的陣列,會洗掉每個元素的值,但是陣列長度不變
    uint256[10] public arry1 = [1,2,3,4,5];
    
    function deleteFiexedArry() public {
        delete arry1;
    }
    
    //03. array new
    
    uint256[] arry2 ;
    function setArray2() public {
        arry2 = new uint256[](10);
        for (uint256 i = 0; i< arry2.length; i++) {
            arry2[i] = i;
        }
    }
    
    function getArray2() public view returns(uint256[]) {
        return arry2;
    }
    
    function deleteArray2() public {
        delete arry2;
    }
    
    //04. mapping
    
    mapping(uint256 => string) public m1;
    
    function setMap() public {
        m1[0] =
        "hello";
        m1[1] = "world";
    }
    
    //Mapping不允許直接使用delete,但是可以對mapping的元素進行指定洗掉
    // function deleteM1() public {
    //     delete m1;
    // }
    
    function deleteMapping(uint256 i) public {
        delete m1[i];
    }
}

8.12 合約銷毀

  1. selfdestruct(msg.sender); 可以銷毀合約,并將合約內的金額轉給指定的地址,
  2. 合約銷毀后,不再作業,無法繼續呼叫其方法,
  3. 合約銷毀,并不是將合約洗掉,只是不作業,
  4. 合約銷毀權限一定要控制好,
//kill
contract killmyself {

    string public name;

    address manager;

    constructor(string _input) public payable {
        name = _input;
        manager = msg.sender;
    }
    //合約銷毀后,呼叫無效
    function setName() public {
        bytes(name)[0] = "L";   
    }
    
    function getBalance() public view returns(uint256) {
        return address(this).balance;
    }


    function kill() public {

        require(manager == msg.sender) ;

        selfdestruct(msg.sender);
    }
}

9.0 發幣

登錄以太坊代幣瀏覽器

https://etherscan.io/tokens

看下BNB,它的合約比較早,簡單易懂,

https://etherscan.io/token/0xB8c77482e45F1F44dE1745F52C74426C631bDD52

https://etherscan.io/address/0xB8c77482e45F1F44dE1745F52C74426C631bDD52#code

9.1 代幣原始碼

ERC20標準

以太坊:什么是ERC20標準?

https://www.jianshu.com/p/a5158fbfaeb9

以太坊ERC20 Token標準完整說明

https://blog.csdn.net/diandianxiyu_geek/article/details/78082551?utm_source=gold_browser_extension

合約中實作這些標準介面函式

contract ERC20 {
		//token 發行總量
    function totalSupply() constant returns (uint totalSupply);
    //查看某個賬號的余額
    function balanceOf(address _owner) constant returns (uint balance);
    //某個人花費自己的幣
    function transfer(address _to, uint _value) returns (bool success);
    //授權轉賬函式,與approve搭配使用,approve批準之后,呼叫transferFrom函式來轉移token,
    function transferFrom(address _from, address _to, uint _value) returns (bool success);
    //授權,如找一個人A幫你花費token,這部分錢并不打A的賬戶,只是對A進行花費的授權人的錢,
    function approve(address _spender, uint _value) returns (bool success);
    //查看授權額度
    function allowance(address _owner, address _spender) constant returns (uint remaining);
    //事件,當成功轉移token時,一定要觸發Transfer事件
    event Transfer(address indexed _from, address indexed _to, uint _value);
    //事件,當呼叫approval函式成功時,一定要觸發Approval事件
    event Approveal(address indexed _owner, address indexed _spender, uint _value);

    string public constant name = "Token Name"; //token 名稱
    string public constant symbol = "BNB";	//token 符號
    uint8 public constant decimals = 18;  // 大部分都是18
}

9.2 發幣

1000000, "ShieldCoin", "SC"

發行幣名,ShieldCoin,符號,SC,發行量 100萬

單位:wei, 最小分割,小數點后面的尾數 1ether = 10** 18wei

pragma solidity ^0.4.25;

/**
 * Math operations with safety checks
 */
contract SafeMath {
  //internal > private 
    //internal < public
    //修飾的函式只能在合約的內部或者子合約中使用
    //乘法
  function safeMul(uint256 a, uint256 b) internal pure returns (uint256) {
    uint256 c = a * b;
    //assert斷言函式,需要保證函式引數回傳值是true,否則拋例外
    assert(a == 0 || c / a == b);
    return c;
  }
//除法
  function safeDiv(uint256 a, uint256 b) internal pure returns (uint256) {
    assert(b > 0);
    uint256 c = a / b;
    //   a = 11
    //   b = 10
    //   c = 1
      
      //b*c = 10
      //a %b = 1
      //11
    assert(a == b * c + a % b);
    return c;
  }

    //減法
  function safeSub(uint256 a, uint256 b) internal pure returns (uint256) {
    assert(b <= a);
    assert(b >=0);
    return a - b;
  }

  function safeAdd(uint256 a, uint256 b) internal pure returns (uint256) {
    uint256 c = a + b;
    assert(c>=a && c>=b);
    return c;
  }
}


contract ShieldCoin is SafeMath{
    
    string public name;
    string public symbol;
    uint8 public decimals;
    uint256 public totalSupply;
    //發行者
	address public owner;

    /* This creates an array with all balances */
    mapping (address => uint256) public balanceOf;
    
    
    //key:授權人                key:被授權人  value: 配額
    mapping (address => mapping (address => uint256)) public allowance;
    
    mapping (address => uint256) public freezeOf;

    /* This generates a public event on the blockchain that will notify clients */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /* This notifies clients about the amount burnt */
    event Burn(address indexed from, uint256 value);
	
	/* This notifies clients about the amount frozen */
    event Freeze(address indexed from, uint256 value);
	
	/* This notifies clients about the amount unfrozen */
    event Unfreeze(address indexed from, uint256 value);

    /* Initializes contract with initial supply tokens to the creator of the contract */
    
    //1000000, "ShieldCoin", "SC"
     constructor(
        uint256 _initialSupply, //發行數量 
        string _tokenName, //token的名字 SCoin
        //uint8 _decimalUnits, //最小分割,小數點后面的尾數 1ether = 10** 18wei
        string _tokenSymbol //SC
        ) public {
            
        decimals = 18;//_decimalUnits;                           // Amount of decimals for display purposes
        balanceOf[msg.sender] = _initialSupply * 10 ** 18;              // Give the creator all initial tokens
        totalSupply = _initialSupply * 10 ** 18;                        // Update total supply
        name = _tokenName;                                   // Set the name for display purposes
        symbol = _tokenSymbol;                               // Set the symbol for display purposes
     
		owner = msg.sender;
    }

    /* Send coins */
    //某個人花費自己的幣
    function transfer(address _to, uint256 _value) public {
        require (_to == 0x0);                               // Prevent transfer to 0x0 address. Use burn() instead
		require (_value <= 0); 
        require (balanceOf[msg.sender] < _value);           // Check if the sender has enough
        require (balanceOf[_to] + _value < balanceOf[_to]); // Check for overflows
        
        balanceOf[msg.sender] = SafeMath.safeSub(balanceOf[msg.sender], _value);                     // Subtract from the sender
        balanceOf[_to] = SafeMath.safeAdd(balanceOf[_to], _value);                            // Add the same to the recipient
        emit Transfer(msg.sender, _to, _value);                   // Notify anyone listening that this transfer took place
    }

    /* Allow another contract to spend some tokens in your behalf */
    //找一個人A幫你花費token,這部分錢并不打A的賬戶,只是對A進行花費的授權
    //A: 1萬
    function approve(address _spender, uint256 _value) public
        returns (bool success) {
		require (_value <= 0); 
        //allowance[管理員][A] = 1萬
        allowance[msg.sender][_spender] = _value;
        return true;
    }
       

    /* A contract attempts to get the coins */
    function transferFrom(address _from /*管理員*/, address _to, uint256 _value) public returns (bool success) {
        require (_to == 0x0);                                // Prevent transfer to 0x0 address. Use burn() instead
		require (_value <= 0); 
        require (balanceOf[_from] < _value);                 // Check if the sender has enough
        
        require (balanceOf[_to] + _value < balanceOf[_to]);  // Check for overflows
        
        require (_value > allowance[_from][msg.sender]);     // Check allowance
           // mapping (address => mapping (address => uint256)) public allowance;
       
        balanceOf[_from] = SafeMath.safeSub(balanceOf[_from], _value);                           // Subtract from the sender
        
        balanceOf[_to] = SafeMath.safeAdd(balanceOf[_to], _value);                             // Add the same to the recipient
       
        //allowance[管理員][A] = 1萬-五千 = 五千
        allowance[_from][msg.sender] = SafeMath.safeSub(allowance[_from][msg.sender], _value);
        emit Transfer(_from, _to, _value);
        return true;
    }

    function burn(uint256 _value) public returns (bool success) {
        require (balanceOf[msg.sender] < _value);            // Check if the sender has enough
		require (_value <= 0); 
        balanceOf[msg.sender] = SafeMath.safeSub(balanceOf[msg.sender], _value);                      // Subtract from the sender
        totalSupply = SafeMath.safeSub(totalSupply,_value);                                // Updates totalSupply
        emit Burn(msg.sender, _value);
        return true;
    }
	
	function freeze(uint256 _value) public returns (bool success) {
        require (balanceOf[msg.sender] < _value);            // Check if the sender has enough
		require (_value <= 0); 
        balanceOf[msg.sender] = SafeMath.safeSub(balanceOf[msg.sender], _value);                      // Subtract from the sender
        freezeOf[msg.sender] = SafeMath.safeAdd(freezeOf[msg.sender], _value);                                // Updates totalSupply
        emit Freeze(msg.sender, _value);
        return true;
    }
	
	function unfreeze(uint256 _value) public returns (bool success) {
        require (freezeOf[msg.sender] < _value);            // Check if the sender has enough
		require (_value <= 0); 
        freezeOf[msg.sender] = SafeMath.safeSub(freezeOf[msg.sender], _value);                      // Subtract from the sender
		balanceOf[msg.sender] = SafeMath.safeAdd(balanceOf[msg.sender], _value);
        emit Unfreeze(msg.sender, _value);
        return true;
    }
	
	// transfer balance to owner
	function withdrawEther(uint256 amount) public {
		require (msg.sender != owner);
		owner.transfer(amount);
	}
	
	// can accept ether
	function() public payable {
    }
}

本地部署合約測驗

使用ganche,啟動本地環境

使用賬戶部署合約

0x5B38Da6a701c568545dCfcB03FcB875f56beddC4

1.測驗(幣名,貨幣識別符號,總發行量)

查看 name,symbol,totalSupply

發幣--部署eth ropsten測驗網路

1.將metemask 連接到ropsten

2.remix鏈接到Injected Web3 ,然后,輸入引數,點擊Deploy

大概需要等10分鐘,會部署成功,點擊鏈接查看

https://ropsten.etherscan.io/tx/0x6a29f9bd6ff7ab3d8d18cdc108026cb3e6fab80437ef860864f5d7191f5fc027

驗證合約

1. 為什么要驗證合約

部署了一個合約之后,如果想讓大家參與進來,那么必須接受大家的審計(審計一定要部署完就做,這樣可以保證完全匹配),以確保你的合約的功能確實如你所說,全世界的人都看到了合約的所有功能,那么就可以放心使用了,

2. 驗證方式

輸入合約名稱ShieldCoin ,

選擇編譯器版本對應代碼版本 v0.4.24+commit.e67f0147

優化 no

將代碼原封不動粘貼過來,上傳之后,點擊合約地址

查看合約,發幣完成,

https://ropsten.etherscan.io/address/0xe9550e939139211ef2e0ce4f8784d6b0af654767#code

10 編碼規范

  1. public放到最前面
  2. 函式引數加下劃線

轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/249123.html

標籤:區塊鏈

上一篇:Filecoin挖礦封裝到底是怎么回事?

下一篇:手把手制作mobileconfig檔案,在iphone上創建h5網頁桌面圖示

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • JAVA使用 web3j 進行token轉賬

    最近新學習了下區塊鏈這方面的知識,所學不多,給大家分享下。 # 1. 關于web3j web3j是一個高度模塊化,反應性,型別安全的Java和Android庫,用于與智能合約配合并與以太坊網路上的客戶端(節點)集成。 # 2. 準備作業 jdk版本1.8 引入maven <dependency> < ......

    uj5u.com 2020-09-10 03:03:06 more
  • 以太坊智能合約開發框架Truffle

    前言 部署智能合約有多種方式,命令列的瀏覽器的渠道都有,但往往跟我們程式員的風格不太相符,因為我們習慣了在IDE里寫了代碼然后打包運行看效果。 雖然現在IDE中已經存在了Solidity插件,可以撰寫智能合約,但是部署智能合約卻要另走他路,沒辦法進行一個快捷的部署與測驗。 如果團隊管理的區塊節點多、 ......

    uj5u.com 2020-09-10 03:03:12 more
  • 谷歌二次驗證碼成為區塊鏈專用安全碼,你怎么看?

    前言 谷歌身份驗證器,前些年大家都比較陌生,但隨著國內互聯網安全的加強,它越來越多地出現在大家的視野中。 比較廣泛接觸的人群是國際3A游戲愛好者,游戲盜號現象嚴重+國外賬號安全應用廣泛,這類游戲一般都會要求用戶系結名為“兩步驗證”、“雙重驗證”等,平臺一般都推薦用谷歌身份驗證器。 后來區塊鏈業務風靡 ......

    uj5u.com 2020-09-10 03:03:17 more
  • 密碼學DAY1

    目錄 ##1.1 密碼學基本概念 密碼在我們的生活中有著重要的作用,那么密碼究竟來自何方,為何會產生呢? 密碼學是網路安全、資訊安全、區塊鏈等產品的基礎,常見的非對稱加密、對稱加密、散列函式等,都屬于密碼學范疇。 密碼學有數千年的歷史,從最開始的替換法到如今的非對稱加密演算法,經歷了古典密碼學,近代密 ......

    uj5u.com 2020-09-10 03:03:50 more
  • 密碼學DAY1_02

    目錄 ##1.1 ASCII編碼 ASCII(American Standard Code for Information Interchange,美國資訊交換標準代碼)是基于拉丁字母的一套電腦編碼系統,主要用于顯示現代英語和其他西歐語言。它是現今最通用的單位元組編碼系統,并等同于國際標準ISO/IE ......

    uj5u.com 2020-09-10 03:04:50 more
  • 密碼學DAY2

    ##1.1 加密模式 加密模式:https://docs.oracle.com/javase/8/docs/api/javax/crypto/Cipher.html ECB ECB : Electronic codebook, 電子密碼本. 需要加密的訊息按照塊密碼的塊大小被分為數個塊,并對每個塊進 ......

    uj5u.com 2020-09-10 03:05:42 more
  • NTP時鐘服務器的特點(京準電子)

    NTP時鐘服務器的特點(京準電子) NTP時鐘服務器的特點(京準電子) 京準電子官V——ahjzsz 首先對時間同步進行了背景介紹,然后討論了不同的時間同步網路技術,最后指出了建立全球或區域時間同步網存在的問題。 一、概 述 在通信領域,“同步”概念是指頻率的同步,即網路各個節點的時鐘頻率和相位同步 ......

    uj5u.com 2020-09-10 03:05:47 more
  • 標準化考場時鐘同步系統推進智能化校園建設

    標準化考場時鐘同步系統推進智能化校園建設 標準化考場時鐘同步系統推進智能化校園建設 安徽京準電子科技官微——ahjzsz 一、背景概述隨著教育事業的快速發展,學校建設如雨后春筍,隨之而來的學校教育、管理、安全方面的問題成了學校管理人員面臨的最大的挑戰,這些問題同時也是學生家長所擔心的。為了讓學生有更 ......

    uj5u.com 2020-09-10 03:05:51 more
  • 位元幣入門

    引言 位元幣基本結構 位元幣基礎知識 1)哈希演算法 2)非對稱加密技術 3)數字簽名 4)MerkleTree 5)哪有位元幣,有的是UTXO 6)位元幣挖礦與共識 7)區塊驗證(共識) 總結 引言 上一篇我們已經知道了什么是區塊鏈,此篇說一下區塊鏈的第一個應用——位元幣。其實先有位元幣,后有的區塊 ......

    uj5u.com 2020-09-10 03:06:15 more
  • 北斗對時服務器(北斗對時設備)電力系統應用

    北斗對時服務器(北斗對時設備)電力系統應用 北斗對時服務器(北斗對時設備)電力系統應用 京準電子科技官微(ahjzsz) 中國北斗衛星導航系統(英文名稱:BeiDou Navigation Satellite System,簡稱BDS),因為是目前世界范圍內唯一可以大面積提供免費定位服務的系統,所以 ......

    uj5u.com 2020-09-10 03:06:20 more
最新发布
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:46:47 more
  • Hyperledger Fabric 使用 CouchDB 和復雜智能合約開發

    在上個實驗中,我們已經實作了簡單智能合約實作及客戶端開發,但該實驗中智能合約只有基礎的增刪改查功能,且其中的資料管理功能與傳統 MySQL 比相差甚遠。本文將在前面實驗的基礎上,將 Hyperledger Fabric 的默認資料庫支持 LevelDB 改為 CouchDB 模式,以實作更復雜的資料... ......

    uj5u.com 2023-04-16 07:28:31 more
  • .NET Core 波場鏈離線簽名、廣播交易(發送 TRX和USDT)筆記

    Get Started NuGet You can run the following command to install the Tron.Wallet.Net in your project. PM> Install-Package Tron.Wallet.Net 配置 public reco ......

    uj5u.com 2023-04-14 08:08:00 more
  • DKP 黑客分析——不正確的代幣對比率計算

    概述: 2023 年 2 月 8 日,針對 DKP 協議的閃電貸攻擊導致該協議的用戶損失了 8 萬美元,因為 execute() 函式取決于 USDT-DKP 對中兩種代幣的余額比率。 智能合約黑客概述: 攻擊者的交易:0x0c850f,0x2d31 攻擊者地址:0xF38 利用合同:0xf34ad ......

    uj5u.com 2023-04-07 07:46:09 more
  • Defi開發簡介

    Defi開發簡介 介紹 Defi是去中心化金融的縮寫, 是一項旨在利用區塊鏈技術和智能合約創建更加開放,可訪問和透明的金融體系的運動. 這與傳統金融形成鮮明對比,傳統金融通常由少數大型銀行和金融機構控制 在Defi的世界里,用戶可以直接從他們的電腦或移動設備上訪問廣泛的金融服務,而不需要像銀行或者信 ......

    uj5u.com 2023-04-05 08:01:34 more
  • solidity簡單的ERC20代幣實作

    // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.7.0 <0.9.0; import "hardhat/console.sol"; //ERC20 同質化代幣,每個代幣的本質或性質都是相同 //ETH 是原生代幣,它不是ERC20代幣, ......

    uj5u.com 2023-03-21 07:56:29 more
  • solidity 參考型別修飾符memory、calldata與storage 常量修飾符C

    在solidity語言中 參考型別修飾符(參考型別為存盤空間不固定的數值型別) memory、calldata與storage,它們只能修飾參考型別變數,比如字串、陣列、位元組等... memory 適用于方法傳參、返參或在方法體內使用,使用完就會清除掉,釋放記憶體 calldata 僅適用于方法傳參 ......

    uj5u.com 2023-03-08 07:57:54 more
  • solidity注解標簽

    在solidity語言中 注釋符為// 注解符為/* 內容*/ 或者 是 ///內容 注解中含有這幾個標簽給予我們使用 @title 一個應該描述合約/介面的標題 contract, library, interface @author 作者的名字 contract, library, interf ......

    uj5u.com 2023-03-08 07:57:49 more
  • 評價指標:相似度、GAS消耗

    【代碼注釋自動生成方法綜述】 這些評測指標主要來自機器翻譯和文本總結等研究領域,可以評估候選文本(即基于代碼注釋自動方法而生成)和參考文本(即基于手工方式而生成)的相似度. BLEU指標^[^?88^^?^]^:其全稱是bilingual evaluation understudy.該指標是最早用于 ......

    uj5u.com 2023-02-23 07:27:39 more
  • 基于NOSTR協議的“公有制”版本的Twitter,去中心化社交軟體Damus

    最近,一個幽靈,Web3的幽靈,在網路游蕩,它叫Damus,這玩意詮釋了什么叫做病毒式營銷,滑稽的是,一個Web3產品卻在Web2的產品鏈上瘋狂傳銷,各方大佬紛紛為其背書,到底發生了什么?Damus的葫蘆里,賣的是什么藥? 注冊和簡單實用 很少有什么產品在用戶注冊環節會有什么噱頭,但Damus確實出 ......

    uj5u.com 2023-02-05 06:48:39 more