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" "encoding/base64"
"strconv" "encoding/json"
"encoding/base64" "fmt"
"encoding/json" "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 {
@ -19,39 +19,39 @@ type MarketplaceContract struct {
} }
type ListingItem struct { type ListingItem struct {
TokenAddr string `json:"tokenAddr"` TokenAddr string `json:"tokenAddr"`
Id string `json:"id"` Id string `json:"id"`
} }
type Listing struct { type Listing struct {
ListingId string `json:"listingId"` ListingId string `json:"listingId"`
Creator string `json:"creator"` Creator string `json:"creator"`
Price int `json:"price"` Price int `json:"price"`
CurrencyAddr string `json:"currencyAddr"` CurrencyAddr string `json:"currencyAddr"`
} }
type ListingCreated struct { type ListingCreated struct {
ListingId string `json:"listingId"` ListingId string `json:"listingId"`
Creator string `json:"creator"` Creator string `json:"creator"`
Price int `json:"price"` Price int `json:"price"`
CurrencyAddr string `json:"currencyAddr"` CurrencyAddr string `json:"currencyAddr"`
Nfts []ListingItem `json:"nfts"` Nfts []ListingItem `json:"nfts"`
Batches []ListingItem `json:"batches"` Batches []ListingItem `json:"batches"`
Collections []ListingItem `json:"collections"` Collections []ListingItem `json:"collections"`
} }
type ListingItemSold struct { type ListingItemSold struct {
ListingId string `json:"listingId"` ListingId string `json:"listingId"`
Creator string `json:"creator"` Creator string `json:"creator"`
Price int `json:"price"` Price int `json:"price"`
TokenAddr string `json:"tokenAddr"` TokenAddr string `json:"tokenAddr"`
CurrencyAddr string `json:"currencyAddr"` CurrencyAddr string `json:"currencyAddr"`
TokenId string `json:"tokenId"` TokenId string `json:"tokenId"`
Buyer string `json:"buyer"` Buyer string `json:"buyer"`
} }
type ListingCanceled struct { type ListingCanceled struct {
ListingId string `json:"listingId"` ListingId string `json:"listingId"`
} }
const listingPrefix = "listing" const listingPrefix = "listing"
@ -78,179 +78,180 @@ func _readListing(ctx contractapi.TransactionContextInterface, listingId string)
func (c *MarketplaceContract) List(ctx contractapi.TransactionContextInterface, creator string, listingId string, currencyAddr string, nfts []ListingItem, batches []ListingItem, collections []ListingItem, price int) (*Listing, error) { func (c *MarketplaceContract) List(ctx contractapi.TransactionContextInterface, creator string, listingId string, currencyAddr string, nfts []ListingItem, batches []ListingItem, collections []ListingItem, price int) (*Listing, error) {
listing := new(Listing) listing := new(Listing)
listing.ListingId = listingId listing.ListingId = listingId
listing.Creator = creator listing.Creator = creator
listing.Price = price listing.Price = price
listing.CurrencyAddr = currencyAddr listing.CurrencyAddr = currencyAddr
listingKey, err := ctx.GetStub().CreateCompositeKey(listingPrefix, []string{listingId}) listingKey, err := ctx.GetStub().CreateCompositeKey(listingPrefix, []string{listingId})
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to CreateCompositeKey to nftKey: %v", err) return nil, fmt.Errorf("failed to CreateCompositeKey to nftKey: %v", err)
} }
listingBytes, err := json.Marshal(listing) listingBytes, err := json.Marshal(listing)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to marshal listing: %v", err) return nil, fmt.Errorf("failed to marshal listing: %v", err)
} }
err = ctx.GetStub().PutState(listingKey, listingBytes) err = ctx.GetStub().PutState(listingKey, listingBytes)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to PutState listingBytes %s: %v", listingBytes, err) return nil, fmt.Errorf("failed to PutState listingBytes %s: %v", listingBytes, err)
} }
listingCreated := new(ListingCreated) listingCreated := new(ListingCreated)
listingCreated.ListingId = listingId listingCreated.ListingId = listingId
listingCreated.Creator = creator listingCreated.Creator = creator
listingCreated.Price = price listingCreated.Price = price
listingCreated.CurrencyAddr = currencyAddr listingCreated.CurrencyAddr = currencyAddr
listingCreated.Nfts = nfts listingCreated.Nfts = nfts
listingCreated.Batches = batches listingCreated.Batches = batches
listingCreated.Collections = collections listingCreated.Collections = collections
listingCreatedBytes, err := json.Marshal(listingCreated) listingCreatedBytes, err := json.Marshal(listingCreated)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to marshal listingCreatedBytes: %v", err) return nil, fmt.Errorf("failed to marshal listingCreatedBytes: %v", err)
} }
err = ctx.GetStub().SetEvent("ListingCreated", listingCreatedBytes) err = ctx.GetStub().SetEvent("ListingCreated", listingCreatedBytes)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to SetEvent listingCreatedBytes %s: %v", listingCreatedBytes, err) return nil, fmt.Errorf("failed to SetEvent listingCreatedBytes %s: %v", listingCreatedBytes, err)
} }
return listing, nil return listing, nil
} }
func (c *MarketplaceContract) CancelListing(ctx contractapi.TransactionContextInterface, listingId string) (bool, error) { func (c *MarketplaceContract) CancelListing(ctx contractapi.TransactionContextInterface, listingId string) (bool, error) {
sender64, err := ctx.GetClientIdentity().GetID() sender64, err := ctx.GetClientIdentity().GetID()
if err != nil { if err != nil {
return false, fmt.Errorf("failed to GetClientIdentity: %v", err) return false, fmt.Errorf("failed to GetClientIdentity: %v", err)
} }
senderBytes, err := base64.StdEncoding.DecodeString(sender64) senderBytes, err := base64.StdEncoding.DecodeString(sender64)
if err != nil { if err != nil {
return false, fmt.Errorf("failed to DecodeString senderBytes: %v", err) return false, fmt.Errorf("failed to DecodeString senderBytes: %v", err)
} }
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")
} }
listingKey, err := ctx.GetStub().CreateCompositeKey(listingPrefix, []string{listingId}) listingKey, err := ctx.GetStub().CreateCompositeKey(listingPrefix, []string{listingId})
if err != nil { if err != nil {
return false, fmt.Errorf("failed to CreateCompositeKey to nftKey: %v", err) return false, fmt.Errorf("failed to CreateCompositeKey to nftKey: %v", err)
} }
err = ctx.GetStub().DelState(listingKey) err = ctx.GetStub().DelState(listingKey)
if err != nil { if err != nil {
return false, fmt.Errorf("failed to DelState %s: %v", listingKey, err) return false, fmt.Errorf("failed to DelState %s: %v", listingKey, err)
} }
listingCanceled := new(ListingCanceled) listingCanceled := new(ListingCanceled)
listingCanceled.ListingId = listingId listingCanceled.ListingId = listingId
listingCanceledBytes, err := json.Marshal(listingCanceled) listingCanceledBytes, err := json.Marshal(listingCanceled)
if err != nil { if err != nil {
return false, fmt.Errorf("failed to marshal listingCanceledBytes: %v", err) return false, fmt.Errorf("failed to marshal listingCanceledBytes: %v", err)
} }
err = ctx.GetStub().SetEvent("ListingCanceled", listingCanceledBytes) err = ctx.GetStub().SetEvent("ListingCanceled", listingCanceledBytes)
if err != nil { if err != nil {
return false, fmt.Errorf("failed to SetEvent listingCanceledBytes %s: %v", listingCanceledBytes, err) return false, fmt.Errorf("failed to SetEvent listingCanceledBytes %s: %v", listingCanceledBytes, err)
} }
return true, nil return true, nil
} }
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)
} }
// payment // payment
stub := ctx.GetStub() stub := ctx.GetStub()
params := []string{"TransferFrom", buyer, listing.Creator, strconv.Itoa(listing.Price)} if listing.Price > 0 {
invokeArgs := make([][]byte, len(params)) params := []string{"TransferFrom", buyer, listing.Creator, strconv.Itoa(listing.Price)}
invokeArgs := make([][]byte, len(params))
for i, arg := range params { for i, arg := range params {
invokeArgs[i] = []byte(arg) invokeArgs[i] = []byte(arg)
} }
response := stub.InvokeChaincode(listing.CurrencyAddr, invokeArgs, "firefly") response := stub.InvokeChaincode(listing.CurrencyAddr, invokeArgs, "firefly")
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}
tokenTransferInvokeArgs := make([][]byte, len(tokenTransferParams)) tokenTransferInvokeArgs := make([][]byte, len(tokenTransferParams))
for i, arg := range tokenTransferParams { for i, arg := range tokenTransferParams {
tokenTransferInvokeArgs[i] = []byte(arg) tokenTransferInvokeArgs[i] = []byte(arg)
} }
tokenTransferResponse := stub.InvokeChaincode(tokenAddr, tokenTransferInvokeArgs, "firefly") tokenTransferResponse := stub.InvokeChaincode(tokenAddr, tokenTransferInvokeArgs, "firefly")
if tokenTransferResponse.Status != shim.OK { if tokenTransferResponse.Status != shim.OK {
return false, fmt.Errorf("Failed to invoke erc-721 chaincode. Got error: %s", tokenTransferResponse.Payload) return false, fmt.Errorf("Failed to invoke erc-721 chaincode. Got error: %s", tokenTransferResponse.Payload)
} }
listingItemSold := new(ListingItemSold) listingItemSold := new(ListingItemSold)
listingItemSold.ListingId = listingId listingItemSold.ListingId = listingId
listingItemSold.Creator = listing.Creator listingItemSold.Creator = listing.Creator
listingItemSold.Price = listing.Price listingItemSold.Price = listing.Price
listingItemSold.CurrencyAddr = listing.CurrencyAddr listingItemSold.CurrencyAddr = listing.CurrencyAddr
listingItemSold.TokenAddr = tokenAddr listingItemSold.TokenAddr = tokenAddr
listingItemSold.Buyer = buyer listingItemSold.Buyer = buyer
listingItemSold.TokenId = tokenId listingItemSold.TokenId = tokenId
listingItemSoldBytes, err := json.Marshal(listingItemSold) listingItemSoldBytes, err := json.Marshal(listingItemSold)
if err != nil { if err != nil {
return false, fmt.Errorf("failed to marshal listingItemSoldBytes: %v", err) return false, fmt.Errorf("failed to marshal listingItemSoldBytes: %v", err)
} }
err = ctx.GetStub().SetEvent("ListingItemSold", listingItemSoldBytes) err = ctx.GetStub().SetEvent("ListingItemSold", listingItemSoldBytes)
if err != nil { if err != nil {
return false, fmt.Errorf("failed to SetEvent listingItemSoldBytes %s: %v", listingItemSoldBytes, err) return false, fmt.Errorf("failed to SetEvent listingItemSoldBytes %s: %v", listingItemSoldBytes, err)
} }
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"
marketplaceContract.Info.Description = "MarketplaceContract fabric port" marketplaceContract.Info.Description = "MarketplaceContract fabric port"
marketplaceContract.Info.License = new(metadata.LicenseMetadata) marketplaceContract.Info.License = new(metadata.LicenseMetadata)
marketplaceContract.Info.License.Name = "Apache-2.0" marketplaceContract.Info.License.Name = "Apache-2.0"
marketplaceContract.Info.Contact = new(metadata.ContactMetadata) marketplaceContract.Info.Contact = new(metadata.ContactMetadata)
marketplaceContract.Info.Contact.Name = "Marketplace" marketplaceContract.Info.Contact.Name = "Marketplace"
chaincode, err := contractapi.NewChaincode(marketplaceContract) chaincode, err := contractapi.NewChaincode(marketplaceContract)
chaincode.Info.Title = "Marketplace chaincode" chaincode.Info.Title = "Marketplace chaincode"
chaincode.Info.Version = "0.0.1" chaincode.Info.Version = "0.0.1"
if err != nil { if err != nil {
panic("Could not create chaincode from MarketplaceContract." + err.Error()) panic("Could not create chaincode from MarketplaceContract." + err.Error())
} }
err = chaincode.Start() err = chaincode.Start()
if err != nil { if err != nil {
panic("Failed to start chaincode. " + err.Error()) panic("Failed to start chaincode. " + err.Error())
} }
} }

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

@ -230,30 +230,29 @@ func (c *TokenERC721Contract) SetLock(ctx contractapi.TransactionContextInterfac
} }
lockUnlockEvent := new(LockUnlock) lockUnlockEvent := new(LockUnlock)
lockUnlockEvent.Owner = sender lockUnlockEvent.Owner = sender
lockUnlockEvent.TokenId = nft.TokenId lockUnlockEvent.TokenId = nft.TokenId
lockUnlockEventBytes, err := json.Marshal(lockUnlockEvent) lockUnlockEventBytes, err := json.Marshal(lockUnlockEvent)
if err != nil { if err != nil {
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)
} }
} else { } else {
err = ctx.GetStub().SetEvent("Unlock", lockUnlockEventBytes) err = ctx.GetStub().SetEvent("Unlock", lockUnlockEventBytes)
if err != nil { if err != nil {
return false, fmt.Errorf("failed to SetEvent Unlock: %v", err) return false, fmt.Errorf("failed to SetEvent Unlock: %v", err)
} }
} }
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,9 +403,9 @@ 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)
} }
owner := nft.Owner owner := nft.Owner
operator := nft.Approved operator := nft.Approved
@ -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,9 +758,9 @@ 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)
} }
// Delete the token // Delete the token
nftKey, err := ctx.GetStub().CreateCompositeKey(nftPrefix, []string{tokenId}) nftKey, err := ctx.GetStub().CreateCompositeKey(nftPrefix, []string{tokenId})

View file

@ -26,11 +26,17 @@ type Transfer struct {
} }
type LockUnlock struct { type LockUnlock struct {
Owner string `json:"owner"` Owner string `json:"owner"`
TokenId string `json:"tokenId"` TokenId string `json:"tokenId"`
} }
type Burn struct { 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