溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

如何使用Hyperledger Fabric開(kāi)發(fā)ERC20標(biāo)準(zhǔn)的代幣

發(fā)布時(shí)間:2021-12-06 14:08:23 來(lái)源:億速云 閱讀:408 作者:小新 欄目:互聯(lián)網(wǎng)科技

這篇文章給大家分享的是有關(guān)如何使用Hyperledger Fabric開(kāi)發(fā)ERC20標(biāo)準(zhǔn)的代幣的內(nèi)容。小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,一起跟隨小編過(guò)來(lái)看看吧。

用Hyperledger Fabric開(kāi)發(fā)ERC20標(biāo)準(zhǔn)的代幣

  • 利用ca身份用戶名作為代幣地址(通過(guò)stub.GetCreator獲取)

  • 實(shí)現(xiàn)ERC20的標(biāo)準(zhǔn)的所有方法

直接上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"`      //符號(hào)
	Decimals    uint8   `json:"decimals"`    //小數(shù)位
	TotalSupply float64 `json:"totalSupply"` //總數(shù)
}

func (t *TokenChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {

	fcn, args := stub.GetFunctionAndParameters()
	fmt.Printf("方法: %s  參數(shù) : %s \n", fcn, args)
	if len(args) != 1 {
		return shim.Error("參數(shù)個(gè)數(shù)不是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())
	}
	//創(chuàng)建人
	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 {

	//獲取要調(diào)用的方法名和方法參數(shù)
	fn, args := stub.GetFunctionAndParameters()
	fmt.Printf("方法: %s  參數(shù) : %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("參數(shù)個(gè)數(shù)不為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("參數(shù)個(gè)數(shù)不為2")
	}
	to := args[0]
	v, err := strconv.ParseFloat(args[1], 64)
	//v不能小于零
	if v < 0 {
		return shim.Error("v less than 0")
	}
	//檢查是否是創(chuàng)建人
	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")
	}

	//代幣總數(shù)增加
	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())
	}
	// 重新寫(xiě)回賬本
	err = stub.PutState(balanceKey(to), parseDecimals(token.Decimals, a))
	if err != nil {
		return shim.Error(err.Error())
	}
	return shim.Success(nil)
}

//調(diào)用transfer函數(shù)將自己的token轉(zhuǎn)賬給to地址,value為轉(zhuǎn)賬個(gè)數(shù)
func (t *TokenChaincode) transfer(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	if len(args) != 2 {
		return shim.Error("參數(shù)個(gè)數(shù)不為2")
	}
	//to
	to := args[0]
	//交易數(shù)量
	val := args[1]
	//from
	from := initiator(stub)
	//保留獲取小數(shù)位
	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)
}

//實(shí)現(xiàn)賬戶的凍結(jié)和解凍 (true 凍結(jié),false 解凍)
func (t *TokenChaincode) freezeAccount(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	if len(args) != 2 {
		return shim.Error("參數(shù)個(gè)數(shù)不為2")
	}
	to := args[0]
	isFreeze := args[1]
	if isFreeze != "true" && isFreeze != "false" {
		return shim.Error("isFreeze is true or false")
	}
	//檢查是否是創(chuàng)建人
	err := checkOwner(stub)
	if err != nil {
		return shim.Error(err.Error())
	}
	//賬戶凍結(jié)和解凍
	err = stub.PutState(freezeKey(to), []byte(isFreeze))
	if err != nil {
		return shim.Error(err.Error())
	}
	return shim.Success(nil)
}

//轉(zhuǎn)移擁有者
func (t *TokenChaincode) transferOwner(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	if len(args) != 1 {
		return shim.Error("參數(shù)個(gè)數(shù)不為1")
	}
	toOwner := args[0]
	//檢查是否是創(chuàng)建人
	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)
}

//批準(zhǔn)spender賬戶從自己的賬戶轉(zhuǎn)移value個(gè)token。可以分多次轉(zhuǎn)移
func (t *TokenChaincode) approve(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	if len(args) != 2 {
		return shim.Error("參數(shù)個(gè)數(shù)不為2")
	}
	//授權(quán)人
	spender := args[0]
	val := args[1]
	_, err := strconv.ParseFloat(val, 64)
	if err != nil {
		return shim.Error("Invalid transaction amount")
	}
	//發(fā)起人
	sponsor := initiator(stub)
	//批準(zhǔn)
	err = stub.PutState(approveKey(sponsor, spender), []byte(val))
	if err != nil {
		return shim.Error(err.Error())
	}
	return shim.Success(nil)
}

//與approve搭配使用,approve批準(zhǔn)之后,調(diào)用transferFrom函數(shù)來(lái)轉(zhuǎn)移token。
func (t *TokenChaincode) transferFrom(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	if len(args) != 3 {
		return shim.Error("參數(shù)個(gè)數(shù)不為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)
	//授權(quán)數(shù)量
	v, err := getApprove(stub, sponsor, spender)
	if err != nil {
		return shim.Error(err.Error())
	}
	//超出授權(quán)
	if valf > v {
		return shim.Error("approve not enough")
	}
	//保留獲取小數(shù)位
	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())
	}
	//計(jì)算approve剩余
	v -= valf
	//跟新授權(quán)數(shù)量
	err = stub.PutState(approveKey(sponsor, spender), parseDecimals(decimals, v))
	if err != nil {
		return shim.Error(err.Error())
	}
	return shim.Success(nil)
}

//返回spender還能提取sponsor的token的個(gè)數(shù)
func (t *TokenChaincode) allowance(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	if len(args) != 1 {
		return shim.Error("參數(shù)個(gè)數(shù)不為1")
	}
	//批準(zhǔn)人
	sponsor := args[0]
	//發(fā)起人
	spender := initiator(stub)
	val, err := stub.GetState(approveKey(sponsor, spender))
	if err != nil {
		return shim.Error(err.Error())
	}
	return shim.Success(val)
}

//增加spender賬戶從自己的賬戶轉(zhuǎn)移value個(gè)token??梢苑侄啻无D(zhuǎn)移
func (t *TokenChaincode) increaseAllowance(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	return changeAllowance(stub, args, "+")
}

//減少spender賬戶從自己的賬戶轉(zhuǎn)移value個(gè)token??梢苑侄啻无D(zhuǎn)移
func (t *TokenChaincode) decreaseAllowance(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	return changeAllowance(stub, args, "-")
}

//改變spender賬戶從自己的賬戶轉(zhuǎn)移value個(gè)token。可以分多次轉(zhuǎn)移
func changeAllowance(stub shim.ChaincodeStubInterface, args []string, operation string) pb.Response {
	if len(args) != 2 {
		return shim.Error("參數(shù)個(gè)數(shù)不為2")
	}
	//授權(quán)人
	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")
	}
	//發(fā)起人
	sponsor := initiator(stub)
	//獲取當(dāng)前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())
	}
	//批準(zhǔn)
	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("參數(shù)個(gè)數(shù)不為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")
	}
	//代幣總數(shù)減少
	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())
	}
	// 重新寫(xiě)回賬本
	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
	}
	//判斷兩個(gè)帳號(hào)不能相同
	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)
	// 重新寫(xiě)回賬本
	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
}

//獲取批準(zhǔn)數(shù)量
func getApprove(stub shim.ChaincodeStubInterface, sponsor, spender string) (float64, error) {
	//批準(zhǔn)數(shù)量
	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) {
	//檢查帳號(hào)是否凍結(jié)
	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
}

//校驗(yàn)創(chuàng)建人
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
}

//校驗(yàn)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
}

//轉(zhuǎn)換為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
}

//交易發(fā)起人
func initiator(stub shim.ChaincodeStubInterface) string {
	//獲取當(dāng)前用戶
	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)
	}
}

感謝各位的閱讀!關(guān)于“如何使用Hyperledger Fabric開(kāi)發(fā)ERC20標(biāo)準(zhǔn)的代幣”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,讓大家可以學(xué)到更多知識(shí),如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到吧!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI