Updated erc721 by additin TokenMinted event, changed marketplace buy method to not invoke erc20 transfer if price is 0, updated dependencies for erc20/721 to overcome deployment problem

This commit is contained in:
Serhii Romaniv 2023-05-18 19:20:58 +03:00
parent aa27103fbe
commit d003a24291
10 changed files with 904 additions and 2316 deletions

View file

@ -2,6 +2,17 @@
# Hyperledger Fabric Samples # Hyperledger Fabric Samples
## To build using docker image use the following command
`docker run --platform linux/amd64 --rm -v $(pwd)/token-erc-20/chaincode-go:/source golang:1.20-alpine /bin/sh -c "cd /source; go mod tidy; go mod vendor"`
`docker run --platform linux/amd64 --rm -v $(pwd)/token-erc-721/chaincode-go:/source golang:1.20-alpine /bin/sh -c "cd /source; go mod tidy; go mod vendor"`
`docker run --platform linux/amd64 --rm -v $(pwd)/marketplace/chaincode-go:/source golang:1.20-alpine /bin/sh -c "cd /source; go mod tidy; go mod vendor"`
`export PACKAGE_NAME=token-erc-20-v1; docker run --platform linux/amd64 --rm -v $(pwd)/token-erc-20/chaincode-go:/source -v $(pwd)/output:/output hyperledger/fabric-tools:2.5 peer lifecycle chaincode package -p /source --label $PACKAGE_NAME /output/$PACKAGE_NAME.zip`
`export PACKAGE_NAME=token-erc-721-v4; docker run --platform linux/amd64 --rm -v $(pwd)/token-erc-721/chaincode-go:/source -v $(pwd)/output:/output hyperledger/fabric-tools:2.5 peer lifecycle chaincode package -p /source --label $PACKAGE_NAME /output/$PACKAGE_NAME.zip`
`export PACKAGE_NAME=marketplace-v5; docker run --platform linux/amd64 --rm -v $(pwd)/marketplace/chaincode-go:/source -v $(pwd)/output:/output hyperledger/fabric-tools:2.5 peer lifecycle chaincode package -p /source --label $PACKAGE_NAME /output/$PACKAGE_NAME.zip`
`export PACKAGE_NAME=marketplace-v5; ff deploy fabric firefly-dev ./output/$PACKAGE_NAME.zip firefly $PACKAGE_NAME 0.0.1`
[![Build Status](https://dev.azure.com/Hyperledger/Fabric-Samples/_apis/build/status/Fabric-Samples?branchName=main)](https://dev.azure.com/Hyperledger/Fabric-Samples/_build/latest?definitionId=28&branchName=main) [![Build Status](https://dev.azure.com/Hyperledger/Fabric-Samples/_apis/build/status/Fabric-Samples?branchName=main)](https://dev.azure.com/Hyperledger/Fabric-Samples/_build/latest?definitionId=28&branchName=main)
You can use Fabric samples to get started working with Hyperledger Fabric, explore important Fabric features, and learn how to build applications that can interact with blockchain networks using the Fabric SDKs. To learn more about Hyperledger Fabric, visit the [Fabric documentation](https://hyperledger-fabric.readthedocs.io/en/latest). You can use Fabric samples to get started working with Hyperledger Fabric, explore important Fabric features, and learn how to build applications that can interact with blockchain networks using the Fabric SDKs. To learn more about Hyperledger Fabric, visit the [Fabric documentation](https://hyperledger-fabric.readthedocs.io/en/latest).

View file

@ -5,13 +5,13 @@
package main package main
import ( import (
"fmt"
"strconv"
"encoding/base64" "encoding/base64"
"encoding/json" "encoding/json"
"fmt"
"github.com/hyperledger/fabric-chaincode-go/shim"
"github.com/hyperledger/fabric-contract-api-go/contractapi" "github.com/hyperledger/fabric-contract-api-go/contractapi"
"github.com/hyperledger/fabric-contract-api-go/metadata" "github.com/hyperledger/fabric-contract-api-go/metadata"
"github.com/hyperledger/fabric-chaincode-go/shim" "strconv"
) )
type MarketplaceContract struct { type MarketplaceContract struct {
@ -135,12 +135,12 @@ func (c *MarketplaceContract) CancelListing(ctx contractapi.TransactionContextIn
} }
sender := string(senderBytes) sender := string(senderBytes)
listing, err := _readListing(ctx, listingId); listing, err := _readListing(ctx, listingId)
if err != nil { if err != nil {
return false, fmt.Errorf("failed to _readListing: %v", err) return false, fmt.Errorf("failed to _readListing: %v", err)
} }
if (listing.Creator != sender) { if listing.Creator != sender {
return false, fmt.Errorf("sender is not owner of listing") return false, fmt.Errorf("sender is not owner of listing")
} }
@ -173,7 +173,7 @@ func (c *MarketplaceContract) CancelListing(ctx contractapi.TransactionContextIn
func (c *MarketplaceContract) Buy(ctx contractapi.TransactionContextInterface, buyer string, listingId string, tokenAddr string, tokenId string) (bool, error) { func (c *MarketplaceContract) Buy(ctx contractapi.TransactionContextInterface, buyer string, listingId string, tokenAddr string, tokenId string) (bool, error) {
listing, err := _readListing(ctx, listingId); listing, err := _readListing(ctx, listingId)
if err != nil { if err != nil {
return false, fmt.Errorf("failed to _readListing: %v", err) return false, fmt.Errorf("failed to _readListing: %v", err)
} }
@ -181,6 +181,7 @@ func (c *MarketplaceContract) Buy(ctx contractapi.TransactionContextInterface, b
// payment // payment
stub := ctx.GetStub() stub := ctx.GetStub()
if listing.Price > 0 {
params := []string{"TransferFrom", buyer, listing.Creator, strconv.Itoa(listing.Price)} params := []string{"TransferFrom", buyer, listing.Creator, strconv.Itoa(listing.Price)}
invokeArgs := make([][]byte, len(params)) invokeArgs := make([][]byte, len(params))
@ -193,6 +194,7 @@ func (c *MarketplaceContract) Buy(ctx contractapi.TransactionContextInterface, b
if response.Status != shim.OK { if response.Status != shim.OK {
return false, fmt.Errorf("Failed to invoke erc-20 chaincode. Got error: %v %s %s %s", response, buyer, listing.Creator, strconv.Itoa(listing.Price)) return false, fmt.Errorf("Failed to invoke erc-20 chaincode. Got error: %v %s %s %s", response, buyer, listing.Creator, strconv.Itoa(listing.Price))
} }
}
// transfer tokens // transfer tokens
tokenTransferParams := []string{"TransferFrom", listing.Creator, buyer, tokenId} tokenTransferParams := []string{"TransferFrom", listing.Creator, buyer, tokenId}
@ -230,7 +232,6 @@ func (c *MarketplaceContract) Buy(ctx contractapi.TransactionContextInterface, b
return true, nil return true, nil
} }
func main() { func main() {
marketplaceContract := new(MarketplaceContract) marketplaceContract := new(MarketplaceContract)
marketplaceContract.Info.Version = "0.0.1" marketplaceContract.Info.Version = "0.0.1"

View file

@ -0,0 +1,305 @@
{
"namespace": "default",
"name": "marketplace",
"description": "Spec interface for the Marketplace golang chaincode",
"version": "0.0.1",
"methods": [
{
"name": "List",
"pathname": "",
"description": "Lists tokens",
"params": [
{
"name": "creator",
"schema": {
"type": "string"
}
},
{
"name": "listingId",
"schema": {
"type": "string"
}
},
{
"name": "currencyAddr",
"schema": {
"type": "string"
}
},
{
"name": "nfts",
"schema": {
"type": "array",
"items": {
"type": "object",
"properties": {
"TokenAddr": {
"type": "string"
},
"Id": {
"type": "string"
}
}
}
}
},
{
"name": "batches",
"schema": {
"type": "array",
"items": {
"type": "object",
"properties": {
"TokenAddr": {
"type": "string"
},
"Id": {
"type": "string"
}
}
}
}
},
{
"name": "collections",
"schema": {
"type": "array",
"items": {
"type": "object",
"properties": {
"TokenAddr": {
"type": "string"
},
"Id": {
"type": "string"
}
}
}
}
},
{
"name": "price",
"schema": {
"type": "integer"
}
}
],
"returns": [
{
"name": "success",
"schema": {
"type": "string"
}
},
{
"name": "error",
"schema": {
"type": "string"
}
}
]
},
{
"name": "CancelListing",
"pathname": "",
"description": "Cancel Listing",
"params": [
{
"name": "listingId",
"schema": {
"type": "string"
}
}
],
"returns": [
{
"name": "success",
"schema": {
"type": "boolean"
}
},
{
"name": "error",
"schema": {
"type": "string"
}
}
]
},
{
"name": "Buy",
"pathname": "",
"description": "Buy tokens",
"params": [
{
"name": "buyer",
"schema": {
"type": "string"
}
},
{
"name": "listingId",
"schema": {
"type": "string"
}
},
{
"name": "tokenAddr",
"schema": {
"type": "string"
}
},
{
"name": "tokenId",
"schema": {
"type": "string"
}
}
],
"returns": [
{
"name": "success",
"schema": {
"type": "string"
}
},
{
"name": "error",
"schema": {
"type": "string"
}
}
]
}
],
"events": [
{
"name": "ListingCreated",
"params": [
{
"name": "listingId",
"schema": {
"type": "string"
}
},
{
"name": "creator",
"schema": {
"type": "string"
}
},
{
"name": "price",
"schema": {
"type": "integer"
}
},
{
"name": "currencyAddr",
"schema": {
"type": "string"
}
},
{
"name": "nfts",
"schema": {
"type": "array",
"items": {
"type": "object",
"properties": {
"TokenAddr": {
"type": "string"
},
"Id": {
"type": "string"
}
}
}
}
},
{
"name": "batches",
"schema": {
"type": "array",
"items": {
"type": "object",
"properties": {
"TokenAddr": {
"type": "string"
},
"Id": {
"type": "string"
}
}
}
}
},
{
"name": "collections",
"schema": {
"type": "array",
"items": {
"type": "object",
"properties": {
"TokenAddr": {
"type": "string"
},
"Id": {
"type": "string"
}
}
}
}
}
]
},
{
"name": "ListingItemSold",
"params": [
{
"name": "listingId",
"schema": {
"type": "string"
}
},
{
"name": "creator",
"schema": {
"type": "string"
}
},
{
"name": "price",
"schema": {
"type": "integer"
}
},
{
"name": "tokenAddr",
"schema": {
"type": "string"
}
},
{
"name": "currencyAddr",
"schema": {
"type": "string"
}
},
{
"name": "tokenId",
"schema": {
"type": "string"
}
},
{
"name": "buyer",
"schema": {
"type": "string"
}
}
]
}
]
}

View file

@ -1,8 +1,8 @@
module github.com/hyperledger/fabric-samples/token-erc-20/chaincode-go module github.com/hyperledger/fabric-samples/token-erc-20/chaincode-go
go 1.17 go 1.18
require github.com/hyperledger/fabric-contract-api-go v1.2.1 require github.com/hyperledger/fabric-contract-api-go v1.2.0
require ( require (
github.com/go-openapi/jsonpointer v0.19.5 // indirect github.com/go-openapi/jsonpointer v0.19.5 // indirect

File diff suppressed because it is too large Load diff

363
token-erc-20/erc20_ffi.json Normal file
View file

@ -0,0 +1,363 @@
{
"namespace": "default",
"name": "token_erc_20",
"description": "Spec interface for the TokenERC20 golang chaincode",
"version": "0.0.2",
"methods": [
{
"name": "BalanceOf",
"pathname": "",
"description": "returns the balance of the given account",
"params": [
{
"name": "account",
"schema": {
"type": "string"
}
}
],
"returns": [
{
"name": "balance",
"schema": {
"type": "integer"
}
}
]
},
{
"name": "Approve",
"pathname": "",
"description": "allows the spender to withdraw from the calling client's token account",
"params": [
{
"name": "spender",
"schema": {
"type": "string"
}
},
{
"name": "value",
"schema": {
"type": "integer"
}
}
],
"returns": [
{
"name": "success",
"schema": {
"type": "boolean"
}
}
]
},
{
"name": "Approve",
"pathname": "",
"description": "allows the spender to withdraw from the calling client's token account",
"params": [
{
"name": "spender",
"schema": {
"type": "string"
}
},
{
"name": "value",
"schema": {
"type": "integer"
}
}
],
"returns": [
{
"name": "success",
"schema": {
"type": "boolean"
}
}
]
},
{
"name": "TransferFrom",
"pathname": "",
"description": "transfers the value amount from the \"from\" address to the \"to\" address",
"params": [
{
"name": "from",
"schema": {
"type": "string"
}
},
{
"name": "to",
"schema": {
"type": "string"
}
},
{
"name": "value",
"schema": {
"type": "integer"
}
}
],
"returns": [
{
"name": "success",
"schema": {
"type": "boolean"
}
}
]
},
{
"name": "Initialize",
"pathname": "",
"description": "Initialize the contract with the name and symbol of the token",
"params": [
{
"name": "name",
"schema": {
"type": "string"
}
},
{
"name": "symbol",
"schema": {
"type": "string"
}
},
{
"name": "decimals",
"schema": {
"type": "string"
}
}
],
"returns": [
{
"name": "success",
"schema": {
"type": "boolean"
}
}
]
},
{
"name": "Name",
"pathname": "",
"description": "Returns the name of the token",
"params": [],
"returns": [
{
"name": "name",
"schema": {
"type": "string"
}
}
]
},
{
"name": "Symbol",
"pathname": "",
"description": "Returns the symbol of the token",
"params": [],
"returns": [
{
"name": "symbol",
"schema": {
"type": "string"
}
}
]
},
{
"name": "TotalSupply",
"pathname": "",
"description": "Returns the total supply of tokens",
"params": [],
"returns": [
{
"name": "count",
"schema": {
"type": "integer"
}
}
]
},
{
"name": "Burn",
"pathname": "",
"description": "redeems tokens the minter's account balance",
"params": [
{
"name": "amount",
"schema": {
"type": "integer"
}
}
],
"returns": [
{
"name": "success",
"schema": {
"type": "boolean"
}
}
]
},
{
"name": "ClientAccountBalance",
"pathname": "",
"description": "Returns the balance of the requesting client's account",
"params": [],
"returns": [
{
"name": "balance",
"schema": {
"type": "integer"
}
}
]
},
{
"name": "ClientAccountID",
"pathname": "",
"description": "Returns the ID of the requesting client's account",
"params": [],
"returns": [
{
"name": "clientAccountID",
"schema": {
"type": "string"
}
}
]
},
{
"name": "Mint",
"pathname": "",
"description": "creates new tokens and adds them to minter's account balance",
"params": [
{
"name": "amount",
"schema": {
"type": "integer"
}
}
],
"returns": [
{
"name": "success",
"schema": {
"type": "boolean"
}
}
]
},
{
"name": "Transfer",
"pathname": "",
"description": "transfers tokens from client account to recipient account",
"params": [
{
"name": "recipient",
"schema": {
"type": "string"
}
},
{
"name": "amount",
"schema": {
"type": "integer"
}
}
],
"returns": [
{
"name": "success",
"schema": {
"type": "boolean"
}
}
]
},
{
"name": "Allowance",
"pathname": "",
"description": "returns the amount still available for the spender to withdraw from the owner",
"params": [
{
"name": "owner",
"schema": {
"type": "string"
}
},
{
"name": "spender",
"schema": {
"type": "string"
}
}
],
"returns": [
{
"name": "allowance",
"schema": {
"type": "integer"
}
}
]
}
],
"events": [
{
"name": "Transfer",
"params": [
{
"name": "from",
"schema": {
"type": "string"
}
},
{
"name": "to",
"schema": {
"type": "string"
}
},
{
"name": "value",
"schema": {
"type": "integer"
}
}
]
},
{
"name": "Approval",
"params": [
{
"name": "from",
"schema": {
"type": "string"
}
},
{
"name": "to",
"schema": {
"type": "string"
}
},
{
"name": "value",
"schema": {
"type": "integer"
}
}
]
}
]
}

View file

@ -238,7 +238,7 @@ func (c *TokenERC721Contract) SetLock(ctx contractapi.TransactionContextInterfac
return false, fmt.Errorf("failed to marshal lockUnlockEventBytes: %v", err) return false, fmt.Errorf("failed to marshal lockUnlockEventBytes: %v", err)
} }
if (nft.Locked) { if nft.Locked {
err = ctx.GetStub().SetEvent("Lock", lockUnlockEventBytes) err = ctx.GetStub().SetEvent("Lock", lockUnlockEventBytes)
if err != nil { if err != nil {
return false, fmt.Errorf("failed to SetEvent Lock: %v", err) return false, fmt.Errorf("failed to SetEvent Lock: %v", err)
@ -253,7 +253,6 @@ func (c *TokenERC721Contract) SetLock(ctx contractapi.TransactionContextInterfac
return true, nil return true, nil
} }
// SetApprovalForAll enables or disables approval for a third party ("operator") // SetApprovalForAll enables or disables approval for a third party ("operator")
// to manage all the message sender's assets // to manage all the message sender's assets
// param {String} operator A client to add to the set of authorized operators // param {String} operator A client to add to the set of authorized operators
@ -404,7 +403,7 @@ func (c *TokenERC721Contract) TransferFrom(ctx contractapi.TransactionContextInt
return false, fmt.Errorf("failed to _readNFT : %v", err) return false, fmt.Errorf("failed to _readNFT : %v", err)
} }
if (nft.Locked) { if nft.Locked {
return false, fmt.Errorf("Token %s is locked", nft.TokenId) return false, fmt.Errorf("Token %s is locked", nft.TokenId)
} }
@ -707,19 +706,19 @@ func (c *TokenERC721Contract) MintWithTokenURI(ctx contractapi.TransactionContex
} }
// Emit the Transfer event // Emit the Transfer event
transferEvent := new(Transfer) mintedEvent := new(TokenMinted)
transferEvent.From = "0x0" mintedEvent.To = minter
transferEvent.To = minter mintedEvent.TokenId = tokenId
transferEvent.TokenId = tokenId mintedEvent.TokenURI = tokenURI
transferEventBytes, err := json.Marshal(transferEvent) mintedEventBytes, err := json.Marshal(mintedEvent)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to marshal transferEventBytes: %v", err) return nil, fmt.Errorf("failed to marshal transferEventBytes: %v", err)
} }
err = ctx.GetStub().SetEvent("Transfer", transferEventBytes) err = ctx.GetStub().SetEvent("TokenMinted", mintedEventBytes)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to SetEvent transferEventBytes %s: %v", transferEventBytes, err) return nil, fmt.Errorf("failed to SetEvent mintedEventBytes %s: %v", mintedEventBytes, err)
} }
return nft, nil return nft, nil
@ -759,7 +758,7 @@ func (c *TokenERC721Contract) Burn(ctx contractapi.TransactionContextInterface,
return false, fmt.Errorf("non-fungible token %s is not owned by %s", tokenId, owner) return false, fmt.Errorf("non-fungible token %s is not owned by %s", tokenId, owner)
} }
if (nft.Locked) { if nft.Locked {
return false, fmt.Errorf("Token %s is locked", nft.TokenId) return false, fmt.Errorf("Token %s is locked", nft.TokenId)
} }

View file

@ -34,3 +34,9 @@ type Burn struct {
Owner string `json:"owner"` Owner string `json:"owner"`
TokenId string `json:"tokenId"` TokenId string `json:"tokenId"`
} }
type TokenMinted struct {
To string `json:"to"`
TokenId string `json:"tokenId"`
TokenURI string `json:"tokenURI"`
}

View file

@ -1,10 +1,10 @@
module github.com/hyperledger/fabric-samples/token-erc-721/chaincode-go module github.com/hyperledger/fabric-samples/token-erc-721/chaincode-go
go 1.17 go 1.18
require ( require (
github.com/hyperledger/fabric-chaincode-go v0.0.0-20230228194215-b84622ba6a7a github.com/hyperledger/fabric-chaincode-go v0.0.0-20220720122508-9207360bbddd
github.com/hyperledger/fabric-contract-api-go v1.2.1 github.com/hyperledger/fabric-contract-api-go v1.2.0
github.com/hyperledger/fabric-protos-go v0.3.0 github.com/hyperledger/fabric-protos-go v0.3.0
github.com/stretchr/testify v1.8.2 github.com/stretchr/testify v1.8.2
) )
@ -13,7 +13,7 @@ require (
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/jsonreference v0.20.0 // indirect github.com/go-openapi/jsonreference v0.20.0 // indirect
github.com/go-openapi/spec v0.20.8 // indirect github.com/go-openapi/spec v0.20.6 // indirect
github.com/go-openapi/swag v0.21.1 // indirect github.com/go-openapi/swag v0.21.1 // indirect
github.com/gobuffalo/envy v1.10.1 // indirect github.com/gobuffalo/envy v1.10.1 // indirect
github.com/gobuffalo/packd v1.0.1 // indirect github.com/gobuffalo/packd v1.0.1 // indirect
@ -28,11 +28,11 @@ require (
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xeipuuv/gojsonschema v1.2.0 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect
golang.org/x/net v0.7.0 // indirect golang.org/x/net v0.0.0-20220708220712-1185a9018129 // indirect
golang.org/x/sys v0.5.0 // indirect golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect
golang.org/x/text v0.7.0 // indirect golang.org/x/text v0.3.7 // indirect
google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect google.golang.org/genproto v0.0.0-20220719170305-83ca9fad585f // indirect
google.golang.org/grpc v1.53.0 // indirect google.golang.org/grpc v1.48.0 // indirect
google.golang.org/protobuf v1.28.1 // indirect google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect

File diff suppressed because it is too large Load diff