mirror of
https://github.com/hyperledger/fabric-samples.git
synced 2026-06-23 01:55:10 +00:00
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:
parent
aa27103fbe
commit
d003a24291
10 changed files with 904 additions and 2316 deletions
11
README.md
11
README.md
|
|
@ -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`
|
||||||
|
|
||||||
[](https://dev.azure.com/Hyperledger/Fabric-Samples/_build/latest?definitionId=28&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).
|
||||||
|
|
|
||||||
|
|
@ -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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
305
marketplace/marketplace_ffi.json
Normal file
305
marketplace/marketplace_ffi.json
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -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
363
token-erc-20/erc20_ffi.json
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -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})
|
||||||
|
|
|
||||||
|
|
@ -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"`
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
Loading…
Reference in a new issue