您好,登錄后才能下訂單哦!
這篇文章給大家分享的是有關如何使用Hyperledger Fabric開發ERC20標準的代幣的內容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。
利用ca身份用戶名作為代幣地址(通過stub.GetCreator獲取)
實現ERC20的標準的所有方法
直接上chaincode源碼
package main import ( "fmt" "strconv" "github.com/hyperledger/fabric/core/chaincode/shim" pb "github.com/hyperledger/fabric/protos/peer" "encoding/json" "bytes" "encoding/pem" "crypto/x509" ) const ( TokenId = "MyToken" TokenOwner = TokenId + "-Owner" TokenBalance = TokenId + "-%s-Balance" TokenFreeze = TokenId + "-%s-Freeze" TokenApprove = TokenId + "-%s-Approve-%s" ) type TokenChaincode struct { } type ERC20Token struct { Name string `json:"name"` //名稱 Symbol string `json:"symbol"` //符號 Decimals uint8 `json:"decimals"` //小數位 TotalSupply float64 `json:"totalSupply"` //總數 } func (t *TokenChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response { fcn, args := stub.GetFunctionAndParameters() fmt.Printf("方法: %s 參數 : %s \n", fcn, args) if len(args) != 1 { return shim.Error("參數個數不是1") } tokenBts := []byte(args[0]) var token ERC20Token err := json.Unmarshal(tokenBts, &token) if err != nil { return shim.Error(err.Error()) } //檢查 err = checkToken(token) if err != nil { return shim.Error(err.Error()) } //添加代幣 err = stub.PutState(TokenId, tokenBts) if err != nil { return shim.Error(err.Error()) } //創建人 creator := initiator(stub) err = stub.PutState(TokenOwner, []byte(creator)) if err != nil { return shim.Error(err.Error()) } //擁有者初始化擁有所有代幣 err = stub.PutState(balanceKey(creator), parseDecimals(token.Decimals, token.TotalSupply)) if err != nil { return shim.Error(err.Error()) } return shim.Success(nil) } func (t *TokenChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response { //獲取要調用的方法名和方法參數 fn, args := stub.GetFunctionAndParameters() fmt.Printf("方法: %s 參數 : %s \n", fn, args) if fn == "tokenInfo" { return t.tokenInfo(stub) } else if fn == "balanceOf" { return t.balanceOf(stub, args) } else if fn == "minter" { return t.minter(stub, args) } else if fn == "transfer" { return t.transfer(stub, args) } else if fn == "freezeAccount" { return t.freezeAccount(stub, args) } else if fn == "approve" { return t.approve(stub, args) } else if fn == "transferFrom" { return t.transferFrom(stub, args) } else if fn == "allowance" { return t.allowance(stub, args) } else if fn == "transferOwner" { return t.transferOwner(stub, args) } else if fn == "increaseAllowance" { return t.increaseAllowance(stub, args) } else if fn == "decreaseAllowance" { return t.decreaseAllowance(stub, args) } else if fn == "burn" { return t.burn(stub, args) } return shim.Error("方法不存在") } //獲取token信息 func (t *TokenChaincode) tokenInfo(stub shim.ChaincodeStubInterface) pb.Response { token, err := stub.GetState(TokenId) if err != nil { return shim.Error(err.Error()) } return shim.Success(token) } //輸入地址,可以獲取該地址代幣的余額 func (t *TokenChaincode) balanceOf(stub shim.ChaincodeStubInterface, args []string) pb.Response { if len(args) != 1 { return shim.Error("參數個數不為1") } name := args[0] balance, err := stub.GetState(balanceKey(name)) if err != nil { return shim.Error(err.Error()) } return shim.Success(balance) } //挖礦 func (t *TokenChaincode) minter(stub shim.ChaincodeStubInterface, args []string) pb.Response { if len(args) != 2 { return shim.Error("參數個數不為2") } to := args[0] v, err := strconv.ParseFloat(args[1], 64) //v不能小于零 if v < 0 { return shim.Error("v less than 0") } //檢查是否是創建人 err = checkOwner(stub) if err != nil { return shim.Error(err.Error()) } //獲取to的balance a, err := getBalance(stub, to) if err != nil { return shim.Error(err.Error()) } a += v if a < 0 { return shim.Error("a balance less than 0") } //代幣總數增加 tks, err := stub.GetState(TokenId) if err != nil { return shim.Error(err.Error()) } var token ERC20Token err = json.Unmarshal(tks, &token) if err != nil { return shim.Error(err.Error()) } token.TotalSupply += v tks, err = json.Marshal(token) if err != nil { return shim.Error(err.Error()) } //跟新代幣 err = stub.PutState(TokenId, tks) if err != nil { return shim.Error(err.Error()) } // 重新寫回賬本 err = stub.PutState(balanceKey(to), parseDecimals(token.Decimals, a)) if err != nil { return shim.Error(err.Error()) } return shim.Success(nil) } //調用transfer函數將自己的token轉賬給to地址,value為轉賬個數 func (t *TokenChaincode) transfer(stub shim.ChaincodeStubInterface, args []string) pb.Response { if len(args) != 2 { return shim.Error("參數個數不為2") } //to to := args[0] //交易數量 val := args[1] //from from := initiator(stub) //保留獲取小數位 decimals, err := getDecimals(stub) if err != nil { return shim.Error(err.Error()) } //交易 err = deal(stub, from, to, val, decimals) if err != nil { return shim.Error(err.Error()) } return shim.Success(nil) } //實現賬戶的凍結和解凍 (true 凍結,false 解凍) func (t *TokenChaincode) freezeAccount(stub shim.ChaincodeStubInterface, args []string) pb.Response { if len(args) != 2 { return shim.Error("參數個數不為2") } to := args[0] isFreeze := args[1] if isFreeze != "true" && isFreeze != "false" { return shim.Error("isFreeze is true or false") } //檢查是否是創建人 err := checkOwner(stub) if err != nil { return shim.Error(err.Error()) } //賬戶凍結和解凍 err = stub.PutState(freezeKey(to), []byte(isFreeze)) if err != nil { return shim.Error(err.Error()) } return shim.Success(nil) } //轉移擁有者 func (t *TokenChaincode) transferOwner(stub shim.ChaincodeStubInterface, args []string) pb.Response { if len(args) != 1 { return shim.Error("參數個數不為1") } toOwner := args[0] //檢查是否是創建人 err := checkOwner(stub) if err != nil { return shim.Error(err.Error()) } //改變owner err = stub.PutState(TokenOwner, []byte(toOwner)) if err != nil { return shim.Error(err.Error()) } return shim.Success(nil) } //批準spender賬戶從自己的賬戶轉移value個token。可以分多次轉移 func (t *TokenChaincode) approve(stub shim.ChaincodeStubInterface, args []string) pb.Response { if len(args) != 2 { return shim.Error("參數個數不為2") } //授權人 spender := args[0] val := args[1] _, err := strconv.ParseFloat(val, 64) if err != nil { return shim.Error("Invalid transaction amount") } //發起人 sponsor := initiator(stub) //批準 err = stub.PutState(approveKey(sponsor, spender), []byte(val)) if err != nil { return shim.Error(err.Error()) } return shim.Success(nil) } //與approve搭配使用,approve批準之后,調用transferFrom函數來轉移token。 func (t *TokenChaincode) transferFrom(stub shim.ChaincodeStubInterface, args []string) pb.Response { if len(args) != 3 { return shim.Error("參數個數不為3") } //from sponsor := args[0] //to to := args[1] //val val := args[2] valf, err := strconv.ParseFloat(val, 64) if err != nil { return shim.Error("Invalid transaction amount") } //spender spender := initiator(stub) //授權數量 v, err := getApprove(stub, sponsor, spender) if err != nil { return shim.Error(err.Error()) } //超出授權 if valf > v { return shim.Error("approve not enough") } //保留獲取小數位 decimals, err := getDecimals(stub) if err != nil { return shim.Error(err.Error()) } //交易 err = deal(stub, sponsor, to, val, decimals) if err != nil { return shim.Error(err.Error()) } //計算approve剩余 v -= valf //跟新授權數量 err = stub.PutState(approveKey(sponsor, spender), parseDecimals(decimals, v)) if err != nil { return shim.Error(err.Error()) } return shim.Success(nil) } //返回spender還能提取sponsor的token的個數 func (t *TokenChaincode) allowance(stub shim.ChaincodeStubInterface, args []string) pb.Response { if len(args) != 1 { return shim.Error("參數個數不為1") } //批準人 sponsor := args[0] //發起人 spender := initiator(stub) val, err := stub.GetState(approveKey(sponsor, spender)) if err != nil { return shim.Error(err.Error()) } return shim.Success(val) } //增加spender賬戶從自己的賬戶轉移value個token。可以分多次轉移 func (t *TokenChaincode) increaseAllowance(stub shim.ChaincodeStubInterface, args []string) pb.Response { return changeAllowance(stub, args, "+") } //減少spender賬戶從自己的賬戶轉移value個token。可以分多次轉移 func (t *TokenChaincode) decreaseAllowance(stub shim.ChaincodeStubInterface, args []string) pb.Response { return changeAllowance(stub, args, "-") } //改變spender賬戶從自己的賬戶轉移value個token。可以分多次轉移 func changeAllowance(stub shim.ChaincodeStubInterface, args []string, operation string) pb.Response { if len(args) != 2 { return shim.Error("參數個數不為2") } //授權人 spender := args[0] v, err := strconv.ParseFloat(args[1], 64) if err != nil { return shim.Error("Invalid transaction amount") } //v不能小于零 if v < 0 { return shim.Error("v less than 0") } //發起人 sponsor := initiator(stub) //獲取當前allowance val, err := stub.GetState(approveKey(sponsor, spender)) if err != nil { return shim.Error(err.Error()) } a, err := strconv.ParseFloat(string(val), 64) if err != nil { return shim.Error(err.Error()) } if operation == "+" { //增加 a += v } if operation == "-" { //減少 a -= v } //不能溢出 if a < 0 { return shim.Error("a less than 0") } decimals, err := getDecimals(stub) if err != nil { return shim.Error(err.Error()) } //批準 err = stub.PutState(approveKey(sponsor, spender), parseDecimals(decimals, a)) if err != nil { return shim.Error(err.Error()) } return shim.Success(nil) } //銷毀代幣 func (t *TokenChaincode) burn(stub shim.ChaincodeStubInterface, args []string) pb.Response { if len(args) != 1 { return shim.Error("參數個數不為1") } v, err := strconv.ParseFloat(args[0], 64) //v不能小于零 if v < 0 { return shim.Error("v less than 0") } from := initiator(stub) //獲取from的balance a, err := getBalance(stub, from) if err != nil { return shim.Error(err.Error()) } a -= v if a < 0 { return shim.Error("a balance less than 0") } //代幣總數減少 tks, err := stub.GetState(TokenId) if err != nil { return shim.Error(err.Error()) } var token ERC20Token err = json.Unmarshal(tks, &token) if err != nil { return shim.Error(err.Error()) } token.TotalSupply -= v tks, err = json.Marshal(token) if err != nil { return shim.Error(err.Error()) } //跟新代幣 err = stub.PutState(TokenId, tks) if err != nil { return shim.Error(err.Error()) } // 重新寫回賬本 err = stub.PutState(balanceKey(from), parseDecimals(token.Decimals, a)) if err != nil { return shim.Error(err.Error()) } return shim.Success(nil) } //交易處理 from to val decimals func deal(stub shim.ChaincodeStubInterface, from, to, val string, decimals uint8) (error) { v, err := strconv.ParseFloat(val, 64) if err != nil { return err } //v不能小于零 if v < 0 { return fmt.Errorf("v less than 0") } //獲取from的balance a, err := getBalance(stub, from) if err != nil { return err } //判斷兩個帳號不能相同 if from == to { return fmt.Errorf("from and to is the same address") } //獲取to的balance b, err := getBalance(stub, to) if err != nil { return err } //execution a b v 交易 a -= v if a < 0 { return fmt.Errorf("from balance not enough") } b += v if b < 0 { return fmt.Errorf("to balance less than 0") } fmt.Println(" a: ", a, " b: ", b) // 重新寫回賬本 err = stub.PutState(balanceKey(from), parseDecimals(decimals, a)) if err != nil { return err } err = stub.PutState(balanceKey(to), parseDecimals(decimals, b)) if err != nil { return err } return nil } //獲取批準數量 func getApprove(stub shim.ChaincodeStubInterface, sponsor, spender string) (float64, error) { //批準數量 val, err := stub.GetState(approveKey(sponsor, spender)) if err != nil { return 0, err } b, err := strconv.ParseFloat(string(val), 64) if err != nil { return 0, err } return b, nil } //獲取balance func getBalance(stub shim.ChaincodeStubInterface, addr string) (float64, error) { //檢查帳號是否凍結 isFreeze, err := stub.GetState(freezeKey(addr)) if err != nil { return 0, err } if isFreeze != nil && bytes.Equal(isFreeze, []byte("true")) { return 0, fmt.Errorf("addr is freeze") } //查詢balance addrVal, err := stub.GetState(balanceKey(addr)) if err != nil { return 0, err } //為空返回0 if addrVal == nil { return 0, nil } b, err := strconv.ParseFloat(string(addrVal), 64) if err != nil { return 0, err } return b, nil } //校驗創建人 func checkOwner(stub shim.ChaincodeStubInterface) error { creator := initiator(stub) owner, err := stub.GetState(TokenOwner) if err != nil { return err } if !bytes.Equal([]byte(creator), owner) { return fmt.Errorf("is not owner") } return nil } //校驗token func checkToken(token ERC20Token) error { if token.Name == "" { return fmt.Errorf("name不能為空") } if token.Symbol == "" { return fmt.Errorf("symbol不能為空") } if token.TotalSupply <= 0 { return fmt.Errorf("totalSupply要大于0") } return nil } //轉換為token decimals func parseDecimals(decimals uint8, value float64) []byte { val := strconv.FormatFloat(value, 'f', int(decimals), 64) return []byte(val) } //獲取token decimals func getDecimals(stub shim.ChaincodeStubInterface) (uint8, error) { tokenBts, err := stub.GetState(TokenId) if err != nil { return 0, err } var token ERC20Token err = json.Unmarshal(tokenBts, &token) if err != nil { return 0, err } return token.Decimals, nil } //交易發起人 func initiator(stub shim.ChaincodeStubInterface) string { //獲取當前用戶 creatorByte, _ := stub.GetCreator() certStart := bytes.IndexAny(creatorByte, "-----BEGIN") if certStart == -1 { fmt.Println("No certificate found") } certText := creatorByte[certStart:] bl, _ := pem.Decode(certText) if bl == nil { fmt.Println("Could not decode the PEM structure") } cert, err := x509.ParseCertificate(bl.Bytes) if err != nil { fmt.Println("ParseCertificate failed") } name := cert.Subject.CommonName fmt.Println("initiator:" + name) return name } //封裝balance key func balanceKey(name string) string { return fmt.Sprintf(TokenBalance, name) } //封裝freeze key func freezeKey(name string) string { return fmt.Sprintf(TokenFreeze, name) } //封裝approve key func approveKey(from, to string) string { return fmt.Sprintf(TokenApprove, from, to) } func main() { err := shim.Start(new(TokenChaincode)) if err != nil { fmt.Printf("Error starting Token chaincode: %s", err) } }
感謝各位的閱讀!關于“如何使用Hyperledger Fabric開發ERC20標準的代幣”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。