From 6c9d40ddf02d7190d5cbd7566849bc24036729ad Mon Sep 17 00:00:00 2001 From: luc662 Date: Wed, 2 Apr 2025 20:52:15 +0000 Subject: [PATCH] se eliminaron mas ejemplos que no necesitariamos --- asset-transfer-abac/README.md | 173 - asset-transfer-abac/chaincode-go/go.mod | 32 - asset-transfer-abac/chaincode-go/go.sum | 132 - .../chaincode-go/smart-contract/abac.go | 214 - .../chaincode-go/smartContract.go | 23 - asset-transfer-events/README.md | 84 - .../application-gateway-go/app.go | 170 - .../application-gateway-go/connect.go | 114 - .../application-gateway-go/go.mod | 19 - .../application-gateway-go/go.sum | 32 - .../application-gateway-java/build.gradle | 26 - .../gradle/wrapper/gradle-wrapper.jar | Bin 63721 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 - .../application-gateway-java/gradlew | 249 - .../application-gateway-java/gradlew.bat | 92 - .../application-gateway-java/settings.gradle | 10 - .../src/main/java/App.java | 173 - .../src/main/java/Connections.java | 70 - .../application-gateway-typescript/.gitignore | 14 - .../application-gateway-typescript/.npmrc | 1 - .../eslint.config.mjs | 13 - .../package.json | 33 - .../application-gateway-typescript/src/app.ts | 157 - .../src/connect.ts | 58 - .../tsconfig.json | 15 - .../chaincode-go/assetTransferEvents.go | 23 - .../chaincode-go/chaincode/smartcontract.go | 134 - asset-transfer-events/chaincode-go/go.mod | 32 - asset-transfer-events/chaincode-go/go.sum | 132 - .../chaincode-java/build.gradle | 69 - .../config/checkstyle/checkstyle.xml | 171 - .../config/checkstyle/suppressions.xml | 8 - .../gradle/wrapper/gradle-wrapper.jar | Bin 63721 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 - asset-transfer-events/chaincode-java/gradlew | 249 - .../chaincode-java/gradlew.bat | 92 - .../chaincode-java/settings.gradle | 5 - .../fabric/samples/events/Asset.java | 158 - .../fabric/samples/events/AssetTransfer.java | 299 -- .../chaincode-javascript/.eslintignore | 5 - .../chaincode-javascript/.eslintrc.js | 39 - .../chaincode-javascript/.gitignore | 15 - .../chaincode-javascript/index.js | 12 - .../lib/assetTransferEvents.js | 128 - .../chaincode-javascript/npm-shrinkwrap.json | 3982 --------------- .../chaincode-javascript/package.json | 48 - .../test/assetTransferEvents.test.js | 229 - auction-dutch/README.md | 615 --- .../application-javascript/.eslintignore | 5 - .../application-javascript/.eslintrc.js | 36 - auction-dutch/application-javascript/bid.js | 98 - .../application-javascript/closeAuction.js | 90 - .../application-javascript/createAuction.js | 78 - .../application-javascript/endAuction.js | 91 - .../endAuctionwithAuditor.js | 83 - .../application-javascript/enrollAdmin.js | 62 - .../application-javascript/package.json | 26 - .../application-javascript/queryAuction.js | 68 - .../application-javascript/queryBid.js | 69 - .../registerEnrollUser.js | 63 - .../application-javascript/revealBid.js | 100 - .../application-javascript/submitBid.js | 89 - auction-dutch/chaincode-go-auditor/go.mod | 34 - auction-dutch/chaincode-go-auditor/go.sum | 132 - .../smart-contract/auction.go | 440 -- .../smart-contract/auctionQueries.go | 91 - .../smart-contract/utils.go | 203 - .../chaincode-go-auditor/smartContract.go | 23 - auction-dutch/chaincode-go/go.mod | 34 - auction-dutch/chaincode-go/go.sum | 132 - .../chaincode-go/smart-contract/auction.go | 512 -- .../smart-contract/auctionQueries.go | 136 - .../chaincode-go/smart-contract/utils.go | 205 - auction-dutch/chaincode-go/smartContract.go | 23 - auction-simple/README.md | 410 -- .../application-javascript/.eslintignore | 5 - .../application-javascript/.eslintrc.js | 36 - auction-simple/application-javascript/bid.js | 101 - .../application-javascript/closeAuction.js | 93 - .../application-javascript/createAuction.js | 79 - .../application-javascript/endAuction.js | 93 - .../application-javascript/enrollAdmin.js | 67 - .../application-javascript/package.json | 22 - .../application-javascript/queryAuction.js | 72 - .../application-javascript/queryBid.js | 73 - .../registerEnrollUser.js | 68 - .../application-javascript/revealBid.js | 103 - .../application-javascript/submitBid.js | 104 - auction-simple/chaincode-go/go.mod | 34 - auction-simple/chaincode-go/go.sum | 132 - .../chaincode-go/smart-contract/auction.go | 448 -- .../smart-contract/auctionQueries.go | 137 - .../chaincode-go/smart-contract/utils.go | 121 - auction-simple/chaincode-go/smartContract.go | 23 - token-erc-1155/README.md | 276 -- .../chaincode-go/chaincode/contract.go | 1161 ----- token-erc-1155/chaincode-go/erc1155.go | 27 - token-erc-1155/chaincode-go/go.mod | 32 - token-erc-1155/chaincode-go/go.sum | 132 - token-erc-20/README.md | 466 -- .../chaincode-go/chaincode/token_contract.go | 733 --- token-erc-20/chaincode-go/go.mod | 32 - token-erc-20/chaincode-go/go.sum | 132 - token-erc-20/chaincode-go/token_erc_20.go | 23 - token-erc-20/chaincode-java/Dockerfile | 32 - token-erc-20/chaincode-java/build.gradle | 94 - .../config/checkstyle/checkstyle.xml | 171 - .../config/checkstyle/suppressions.xml | 10 - .../docker/docker-entrypoint.sh | 16 - .../gradle/wrapper/gradle-wrapper.jar | Bin 63721 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 - token-erc-20/chaincode-java/gradlew | 249 - token-erc-20/chaincode-java/gradlew.bat | 92 - token-erc-20/chaincode-java/settings.gradle | 5 - .../samples/erc20/ContractConstants.java | 28 - .../fabric/samples/erc20/ContractErrors.java | 19 - .../samples/erc20/ERC20TokenContract.java | 526 -- .../fabric/samples/erc20/model/Approval.java | 58 - .../fabric/samples/erc20/model/Transfer.java | 58 - .../samples/erc20/utils/ContractUtility.java | 19 - .../samples/erc20/TokenERC20ContractTest.java | 590 --- .../org.mockito.plugins.MockMaker | 1 - .../chaincode-javascript/.editorconfig | 16 - .../chaincode-javascript/.eslintignore | 5 - .../chaincode-javascript/.eslintrc.js | 39 - token-erc-20/chaincode-javascript/.gitignore | 78 - token-erc-20/chaincode-javascript/index.js | 12 - .../chaincode-javascript/lib/tokenERC20.js | 503 -- .../chaincode-javascript/npm-shrinkwrap.json | 4396 ----------------- .../chaincode-javascript/package.json | 51 - .../test/tokenERC20.test.js | 296 -- token-erc-721/README.md | 477 -- .../chaincode-go/chaincode/erc721-contract.go | 789 --- .../chaincode/erc721-contract_test.go | 282 -- .../chaincode-go/chaincode/erc721.go | 25 - token-erc-721/chaincode-go/go.mod | 38 - token-erc-721/chaincode-go/go.sum | 132 - token-erc-721/chaincode-go/main.go | 35 - token-erc-721/chaincode-java/Dockerfile | 30 - token-erc-721/chaincode-java/build.gradle | 97 - .../config/checkstyle/checkstyle.xml | 174 - .../config/checkstyle/suppressions.xml | 13 - .../docker/docker-entrypoint.sh | 16 - .../gradle/wrapper/gradle-wrapper.jar | Bin 63721 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 - token-erc-721/chaincode-java/gradlew | 249 - token-erc-721/chaincode-java/gradlew.bat | 92 - token-erc-721/chaincode-java/settings.gradle | 5 - .../samples/erc721/ContractConstants.java | 24 - .../fabric/samples/erc721/ContractErrors.java | 13 - .../samples/erc721/ERC721TokenContract.java | 491 -- .../samples/erc721/models/Approval.java | 108 - .../fabric/samples/erc721/models/NFT.java | 122 - .../samples/erc721/models/Transfer.java | 91 - .../samples/erc721/utils/ContractUtility.java | 19 - .../erc721/ERC721TokenContractTest.java | 507 -- .../org.mockito.plugins.MockMaker | 1 - .../chaincode-javascript/.editorconfig | 16 - .../chaincode-javascript/.eslintignore | 5 - .../chaincode-javascript/.eslintrc.js | 39 - token-erc-721/chaincode-javascript/.gitignore | 78 - token-erc-721/chaincode-javascript/index.js | 10 - .../chaincode-javascript/lib/tokenERC721.js | 464 -- .../chaincode-javascript/npm-shrinkwrap.json | 4396 ----------------- .../chaincode-javascript/package.json | 51 - .../test/tokenERC721.test.js | 338 -- 166 files changed, 33126 deletions(-) delete mode 100644 asset-transfer-abac/README.md delete mode 100644 asset-transfer-abac/chaincode-go/go.mod delete mode 100644 asset-transfer-abac/chaincode-go/go.sum delete mode 100644 asset-transfer-abac/chaincode-go/smart-contract/abac.go delete mode 100644 asset-transfer-abac/chaincode-go/smartContract.go delete mode 100644 asset-transfer-events/README.md delete mode 100755 asset-transfer-events/application-gateway-go/app.go delete mode 100755 asset-transfer-events/application-gateway-go/connect.go delete mode 100644 asset-transfer-events/application-gateway-go/go.mod delete mode 100644 asset-transfer-events/application-gateway-go/go.sum delete mode 100644 asset-transfer-events/application-gateway-java/build.gradle delete mode 100644 asset-transfer-events/application-gateway-java/gradle/wrapper/gradle-wrapper.jar delete mode 100644 asset-transfer-events/application-gateway-java/gradle/wrapper/gradle-wrapper.properties delete mode 100755 asset-transfer-events/application-gateway-java/gradlew delete mode 100644 asset-transfer-events/application-gateway-java/gradlew.bat delete mode 100644 asset-transfer-events/application-gateway-java/settings.gradle delete mode 100644 asset-transfer-events/application-gateway-java/src/main/java/App.java delete mode 100644 asset-transfer-events/application-gateway-java/src/main/java/Connections.java delete mode 100644 asset-transfer-events/application-gateway-typescript/.gitignore delete mode 100644 asset-transfer-events/application-gateway-typescript/.npmrc delete mode 100644 asset-transfer-events/application-gateway-typescript/eslint.config.mjs delete mode 100755 asset-transfer-events/application-gateway-typescript/package.json delete mode 100755 asset-transfer-events/application-gateway-typescript/src/app.ts delete mode 100644 asset-transfer-events/application-gateway-typescript/src/connect.ts delete mode 100644 asset-transfer-events/application-gateway-typescript/tsconfig.json delete mode 100644 asset-transfer-events/chaincode-go/assetTransferEvents.go delete mode 100644 asset-transfer-events/chaincode-go/chaincode/smartcontract.go delete mode 100644 asset-transfer-events/chaincode-go/go.mod delete mode 100644 asset-transfer-events/chaincode-go/go.sum delete mode 100644 asset-transfer-events/chaincode-java/build.gradle delete mode 100644 asset-transfer-events/chaincode-java/config/checkstyle/checkstyle.xml delete mode 100644 asset-transfer-events/chaincode-java/config/checkstyle/suppressions.xml delete mode 100644 asset-transfer-events/chaincode-java/gradle/wrapper/gradle-wrapper.jar delete mode 100644 asset-transfer-events/chaincode-java/gradle/wrapper/gradle-wrapper.properties delete mode 100755 asset-transfer-events/chaincode-java/gradlew delete mode 100644 asset-transfer-events/chaincode-java/gradlew.bat delete mode 100644 asset-transfer-events/chaincode-java/settings.gradle delete mode 100644 asset-transfer-events/chaincode-java/src/main/java/org/hyperledger/fabric/samples/events/Asset.java delete mode 100644 asset-transfer-events/chaincode-java/src/main/java/org/hyperledger/fabric/samples/events/AssetTransfer.java delete mode 100644 asset-transfer-events/chaincode-javascript/.eslintignore delete mode 100644 asset-transfer-events/chaincode-javascript/.eslintrc.js delete mode 100644 asset-transfer-events/chaincode-javascript/.gitignore delete mode 100644 asset-transfer-events/chaincode-javascript/index.js delete mode 100644 asset-transfer-events/chaincode-javascript/lib/assetTransferEvents.js delete mode 100644 asset-transfer-events/chaincode-javascript/npm-shrinkwrap.json delete mode 100644 asset-transfer-events/chaincode-javascript/package.json delete mode 100644 asset-transfer-events/chaincode-javascript/test/assetTransferEvents.test.js delete mode 100644 auction-dutch/README.md delete mode 100644 auction-dutch/application-javascript/.eslintignore delete mode 100644 auction-dutch/application-javascript/.eslintrc.js delete mode 100644 auction-dutch/application-javascript/bid.js delete mode 100644 auction-dutch/application-javascript/closeAuction.js delete mode 100644 auction-dutch/application-javascript/createAuction.js delete mode 100644 auction-dutch/application-javascript/endAuction.js delete mode 100644 auction-dutch/application-javascript/endAuctionwithAuditor.js delete mode 100644 auction-dutch/application-javascript/enrollAdmin.js delete mode 100644 auction-dutch/application-javascript/package.json delete mode 100644 auction-dutch/application-javascript/queryAuction.js delete mode 100644 auction-dutch/application-javascript/queryBid.js delete mode 100644 auction-dutch/application-javascript/registerEnrollUser.js delete mode 100644 auction-dutch/application-javascript/revealBid.js delete mode 100644 auction-dutch/application-javascript/submitBid.js delete mode 100644 auction-dutch/chaincode-go-auditor/go.mod delete mode 100644 auction-dutch/chaincode-go-auditor/go.sum delete mode 100644 auction-dutch/chaincode-go-auditor/smart-contract/auction.go delete mode 100644 auction-dutch/chaincode-go-auditor/smart-contract/auctionQueries.go delete mode 100644 auction-dutch/chaincode-go-auditor/smart-contract/utils.go delete mode 100644 auction-dutch/chaincode-go-auditor/smartContract.go delete mode 100644 auction-dutch/chaincode-go/go.mod delete mode 100644 auction-dutch/chaincode-go/go.sum delete mode 100644 auction-dutch/chaincode-go/smart-contract/auction.go delete mode 100644 auction-dutch/chaincode-go/smart-contract/auctionQueries.go delete mode 100644 auction-dutch/chaincode-go/smart-contract/utils.go delete mode 100644 auction-dutch/chaincode-go/smartContract.go delete mode 100644 auction-simple/README.md delete mode 100644 auction-simple/application-javascript/.eslintignore delete mode 100644 auction-simple/application-javascript/.eslintrc.js delete mode 100644 auction-simple/application-javascript/bid.js delete mode 100644 auction-simple/application-javascript/closeAuction.js delete mode 100644 auction-simple/application-javascript/createAuction.js delete mode 100644 auction-simple/application-javascript/endAuction.js delete mode 100644 auction-simple/application-javascript/enrollAdmin.js delete mode 100644 auction-simple/application-javascript/package.json delete mode 100644 auction-simple/application-javascript/queryAuction.js delete mode 100644 auction-simple/application-javascript/queryBid.js delete mode 100644 auction-simple/application-javascript/registerEnrollUser.js delete mode 100644 auction-simple/application-javascript/revealBid.js delete mode 100644 auction-simple/application-javascript/submitBid.js delete mode 100644 auction-simple/chaincode-go/go.mod delete mode 100644 auction-simple/chaincode-go/go.sum delete mode 100644 auction-simple/chaincode-go/smart-contract/auction.go delete mode 100644 auction-simple/chaincode-go/smart-contract/auctionQueries.go delete mode 100644 auction-simple/chaincode-go/smart-contract/utils.go delete mode 100644 auction-simple/chaincode-go/smartContract.go delete mode 100644 token-erc-1155/README.md delete mode 100644 token-erc-1155/chaincode-go/chaincode/contract.go delete mode 100644 token-erc-1155/chaincode-go/erc1155.go delete mode 100644 token-erc-1155/chaincode-go/go.mod delete mode 100644 token-erc-1155/chaincode-go/go.sum delete mode 100644 token-erc-20/README.md delete mode 100644 token-erc-20/chaincode-go/chaincode/token_contract.go delete mode 100644 token-erc-20/chaincode-go/go.mod delete mode 100644 token-erc-20/chaincode-go/go.sum delete mode 100644 token-erc-20/chaincode-go/token_erc_20.go delete mode 100755 token-erc-20/chaincode-java/Dockerfile delete mode 100755 token-erc-20/chaincode-java/build.gradle delete mode 100755 token-erc-20/chaincode-java/config/checkstyle/checkstyle.xml delete mode 100755 token-erc-20/chaincode-java/config/checkstyle/suppressions.xml delete mode 100755 token-erc-20/chaincode-java/docker/docker-entrypoint.sh delete mode 100755 token-erc-20/chaincode-java/gradle/wrapper/gradle-wrapper.jar delete mode 100755 token-erc-20/chaincode-java/gradle/wrapper/gradle-wrapper.properties delete mode 100755 token-erc-20/chaincode-java/gradlew delete mode 100755 token-erc-20/chaincode-java/gradlew.bat delete mode 100755 token-erc-20/chaincode-java/settings.gradle delete mode 100644 token-erc-20/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc20/ContractConstants.java delete mode 100644 token-erc-20/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc20/ContractErrors.java delete mode 100644 token-erc-20/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc20/ERC20TokenContract.java delete mode 100644 token-erc-20/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc20/model/Approval.java delete mode 100644 token-erc-20/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc20/model/Transfer.java delete mode 100644 token-erc-20/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc20/utils/ContractUtility.java delete mode 100644 token-erc-20/chaincode-java/src/test/java/org/hyperledger/fabric/samples/erc20/TokenERC20ContractTest.java delete mode 100644 token-erc-20/chaincode-java/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker delete mode 100755 token-erc-20/chaincode-javascript/.editorconfig delete mode 100644 token-erc-20/chaincode-javascript/.eslintignore delete mode 100644 token-erc-20/chaincode-javascript/.eslintrc.js delete mode 100644 token-erc-20/chaincode-javascript/.gitignore delete mode 100644 token-erc-20/chaincode-javascript/index.js delete mode 100644 token-erc-20/chaincode-javascript/lib/tokenERC20.js delete mode 100644 token-erc-20/chaincode-javascript/npm-shrinkwrap.json delete mode 100644 token-erc-20/chaincode-javascript/package.json delete mode 100644 token-erc-20/chaincode-javascript/test/tokenERC20.test.js delete mode 100644 token-erc-721/README.md delete mode 100644 token-erc-721/chaincode-go/chaincode/erc721-contract.go delete mode 100644 token-erc-721/chaincode-go/chaincode/erc721-contract_test.go delete mode 100644 token-erc-721/chaincode-go/chaincode/erc721.go delete mode 100644 token-erc-721/chaincode-go/go.mod delete mode 100644 token-erc-721/chaincode-go/go.sum delete mode 100644 token-erc-721/chaincode-go/main.go delete mode 100755 token-erc-721/chaincode-java/Dockerfile delete mode 100755 token-erc-721/chaincode-java/build.gradle delete mode 100644 token-erc-721/chaincode-java/config/checkstyle/checkstyle.xml delete mode 100644 token-erc-721/chaincode-java/config/checkstyle/suppressions.xml delete mode 100755 token-erc-721/chaincode-java/docker/docker-entrypoint.sh delete mode 100644 token-erc-721/chaincode-java/gradle/wrapper/gradle-wrapper.jar delete mode 100644 token-erc-721/chaincode-java/gradle/wrapper/gradle-wrapper.properties delete mode 100755 token-erc-721/chaincode-java/gradlew delete mode 100755 token-erc-721/chaincode-java/gradlew.bat delete mode 100755 token-erc-721/chaincode-java/settings.gradle delete mode 100644 token-erc-721/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc721/ContractConstants.java delete mode 100644 token-erc-721/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc721/ContractErrors.java delete mode 100644 token-erc-721/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc721/ERC721TokenContract.java delete mode 100644 token-erc-721/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc721/models/Approval.java delete mode 100644 token-erc-721/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc721/models/NFT.java delete mode 100644 token-erc-721/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc721/models/Transfer.java delete mode 100644 token-erc-721/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc721/utils/ContractUtility.java delete mode 100644 token-erc-721/chaincode-java/src/test/java/org/hyperledger/fabric/samples/erc721/ERC721TokenContractTest.java delete mode 100644 token-erc-721/chaincode-java/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker delete mode 100755 token-erc-721/chaincode-javascript/.editorconfig delete mode 100644 token-erc-721/chaincode-javascript/.eslintignore delete mode 100644 token-erc-721/chaincode-javascript/.eslintrc.js delete mode 100644 token-erc-721/chaincode-javascript/.gitignore delete mode 100644 token-erc-721/chaincode-javascript/index.js delete mode 100644 token-erc-721/chaincode-javascript/lib/tokenERC721.js delete mode 100644 token-erc-721/chaincode-javascript/npm-shrinkwrap.json delete mode 100644 token-erc-721/chaincode-javascript/package.json delete mode 100644 token-erc-721/chaincode-javascript/test/tokenERC721.test.js diff --git a/asset-transfer-abac/README.md b/asset-transfer-abac/README.md deleted file mode 100644 index 09cb106c..00000000 --- a/asset-transfer-abac/README.md +++ /dev/null @@ -1,173 +0,0 @@ -# Attribute based access control - -The `asset-transfer-abac` sample demonstrates the use of Attribute-based access control within the context of a simple asset transfer scenario. The sample also uses authorization based on individual client identities to allow the users that interact with the network to own assets on the blockchain ledger. - -Attribute-Based Access Control (ABAC) refers to the ability to restrict access to certain functionality within a smart contract based on the attributes within a users certificate. For example, you may want certain functions within a smart contract to be used only by application administrators. ABAC allows organizations to provide elevated access to certain users without requiring those users be administrators of the network. For more information, see [Attribute-based access control](https://hyperledger-fabric-ca.readthedocs.io/en/latest/users-guide.html#attribute-based-access-control) in the Fabric CA users guide. - -The `asset-transfer-abac` smart contract allows you to create assets that can be updated or transferred by the asset owner. However, the ability to create or remove assets from the ledger is restricted to identities with the `abac.creator=true` attribute. The identity that creates the asset is assigned as the asset owner. Only the owner can transfer the asset to a new owner or update the asset properties. In the course of the tutorial, we will use the Fabric CA client to create identities with the attribute required to create a new asset. We will then transfer the asset to another identity and demonstrate how the `GetID()` function can be used to enforce asset ownership. We will then use the owner identity to delete the asset. Both Attribute based access control and the `GetID()` function are provided by the [Client Identity Chaincode Library](https://github.com/hyperledger/fabric-chaincode-go/blob/master/pkg/cid/README.md). - -## Start the network and deploy the smart contract - -We can use the Fabric test network to deploy and interact with the `asset-transfer-abac` smart contract. Run the following command to change into the test network directory and bring down any running nodes: -``` -cd fabric-samples/test-network -./network.sh down -``` - -Run the following command to deploy the test network using Certificate Authorities: -``` -./network.sh up createChannel -ca -``` - -You can then use the test network script to deploy the `asset-transfer-abac` smart contract to a channel on the network: -``` -./network.sh deployCC -ccn abac -ccp ../asset-transfer-abac/chaincode-go/ -ccl go -``` - -## Register identities with attributes - -We can use the one of the test network Certificate Authorities to register and enroll identities with the attribute of `abac.creator=true`. First, we need to set the following environment variables in order to use the Fabric CA client. -``` -export PATH=${PWD}/../bin:${PWD}:$PATH -export FABRIC_CFG_PATH=$PWD/../config/ -``` - -We will create the identities using the Org1 CA. Set the Fabric CA client home to the MSP of the Org1 CA admin: -``` -export FABRIC_CA_CLIENT_HOME=${PWD}/organizations/peerOrganizations/org1.example.com/ -``` - -There are two ways to generate certificates with attributes added. We will use both methods and create two identities in the process. The first method is to specify that the attribute be added to the certificate by default when the identity is registered. The following command will register an identity named creator1 with the attribute of `abac.creator=true`. - -``` -fabric-ca-client register --id.name creator1 --id.secret creator1pw --id.type client --id.affiliation org1 --id.attrs 'abac.creator=true:ecert' --tls.certfiles "${PWD}/organizations/fabric-ca/org1/tls-cert.pem" -``` - -The `ecert` suffix adds the attribute to the certificate automatically when the identity is enrolled. As a result, the following enroll command will contain the attribute that was provided in the registration command. - -``` -fabric-ca-client enroll -u https://creator1:creator1pw@localhost:7054 --caname ca-org1 -M "${PWD}/organizations/peerOrganizations/org1.example.com/users/creator1@org1.example.com/msp" --tls.certfiles "${PWD}/organizations/fabric-ca/org1/tls-cert.pem" -``` - -Now that we have enrolled the identity, run the command below to copy the Node OU configuration file into the creator1 MSP folder. -``` -cp "${PWD}/organizations/peerOrganizations/org1.example.com/msp/config.yaml" "${PWD}/organizations/peerOrganizations/org1.example.com/users/creator1@org1.example.com/msp/config.yaml" -``` - -The second method is to request that the attribute be added upon enrollment. The following command will register an identity named creator2 with the same `abac.creator` attribute. -``` -fabric-ca-client register --id.name creator2 --id.secret creator2pw --id.type client --id.affiliation org1 --id.attrs 'abac.creator=true:' --tls.certfiles "${PWD}/organizations/fabric-ca/org1/tls-cert.pem" -``` - -The following enroll command will add the attribute to the certificate: - -``` -fabric-ca-client enroll -u https://creator2:creator2pw@localhost:7054 --caname ca-org1 --enrollment.attrs "abac.creator" -M "${PWD}/organizations/peerOrganizations/org1.example.com/users/creator2@org1.example.com/msp" --tls.certfiles "${PWD}/organizations/fabric-ca/org1/tls-cert.pem" -``` - -Run the command below to copy the Node OU configuration file into the creator2 MSP folder. -``` -cp "${PWD}/organizations/peerOrganizations/org1.example.com/msp/config.yaml" "${PWD}/organizations/peerOrganizations/org1.example.com/users/creator2@org1.example.com/msp/config.yaml" -``` - -## Create an asset - -You can use either identity with the `abac.creator=true` attribute to create an asset using the `asset-transfer-abac` smart contract. We will set the following environment variables to use the first identity that was generated, creator1: - -``` -export CORE_PEER_TLS_ENABLED=true -export CORE_PEER_LOCALMSPID=Org1MSP -export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/creator1@org1.example.com/msp -export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt -export CORE_PEER_ADDRESS=localhost:7051 -export TARGET_TLS_OPTIONS=(-o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" --peerAddresses localhost:7051 --tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt" --peerAddresses localhost:9051 --tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt") -``` - -Run the following command to create Asset1: -``` -peer chaincode invoke "${TARGET_TLS_OPTIONS[@]}" -C mychannel -n abac -c '{"function":"CreateAsset","Args":["Asset1","blue","20","100"]}' -``` - -You can use the command below to query the asset on the ledger: -``` -peer chaincode query -C mychannel -n abac -c '{"function":"ReadAsset","Args":["Asset1"]}' -``` -The result will list the creator1 identity as the asset owner. The `GetID()` API reads the name and issuer from the certificate of the identity that submitted the transaction and assigns that identity as the asset owner: -``` -{"ID":"Asset1","color":"blue","size":20,"owner":"x509::CN=creator1,OU=client+OU=org1,O=Hyperledger,ST=North Carolina,C=US::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US","appraisedValue":100} -``` - -## Transfer the asset - -As the owner of Asset1, the creator1 identity has the ability to transfer the asset to another owner. In order to transfer the asset, the owner needs to provide the name and issuer of the new owner to the `TransferAsset` function. The `asset-transfer-abac` smart contract has a `GetSubmittingClientIdentity` function that allows users to retrieve their certificate information and provide it to the asset owner out of band (we omit this step). Issue the command below to transfer Asset1 to the user1 identity from Org1 that was created when the test network was deployed: -``` -export RECIPIENT="x509::CN=user1,OU=client,O=Hyperledger,ST=North Carolina,C=US::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US" -peer chaincode invoke "${TARGET_TLS_OPTIONS[@]}" -C mychannel -n abac -c '{"function":"TransferAsset","Args":["Asset1","'"$RECIPIENT"'"]}' -``` -Query the ledger to verify that the asset has a new owner: -``` -peer chaincode query -C mychannel -n abac -c '{"function":"ReadAsset","Args":["Asset1"]}' -``` -We can see that Asset1 with is now owned by User1: -``` -{"ID":"Asset1","color":"blue","size":20,"owner":"x509::CN=user1,OU=client,O=Hyperledger,ST=North Carolina,C=US::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US","appraisedValue":100} -``` - -## Update the asset - -Now that the asset has been transferred, the new owner can update the asset properties. The smart contract uses the `GetID()` API to ensure that the update is being submitted by the asset owner. To demonstrate the difference between identity and attribute based access control, lets try to update the asset using the creator1 identity first: -``` -peer chaincode invoke "${TARGET_TLS_OPTIONS[@]}" -C mychannel -n abac -c '{"function":"UpdateAsset","Args":["Asset1","green","20","100"]}' -``` - -Even though creator1 can create new assets, the smart contract detects that the transaction was not submitted by the identity that owns the asset, user1. The command returns the following error: -``` -Error: endorsement failure during invoke. response: status:500 message:"submitting client not authorized to update asset, does not own asset" -``` - -Run the following command to operate as the asset owner by setting the MSP path to User1: -``` -export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/User1@org1.example.com/msp -``` - -We can now update the asset. Run the following command to change the asset color from blue to green. All other aspects of the asset will remain unchanged. -``` -peer chaincode invoke "${TARGET_TLS_OPTIONS[@]}" -C mychannel -n abac -c '{"function":"UpdateAsset","Args":["Asset1","green","20","100"]}' -``` -Run the query command again to verify that the asset has changed color: -``` -peer chaincode query -C mychannel -n abac -c '{"function":"ReadAsset","Args":["Asset1"]}' -``` -The result will display that Asset1 is now green: -``` -{"ID":"Asset1","color":"green","size":20,"owner":"x509::CN=user1,OU=client,O=Hyperledger,ST=North Carolina,C=US::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US","appraisedValue":100} -``` - -## Delete the asset - -The owner also has the ability to delete the asset. Run the following command to remove Asset1 from the ledger: -``` -peer chaincode invoke "${TARGET_TLS_OPTIONS[@]}" -C mychannel -n abac -c '{"function":"DeleteAsset","Args":["Asset1"]}' -``` - -If you query the ledger once more, you will see that Asset1 no longer exists: -``` -peer chaincode query -C mychannel -n abac -c '{"function":"ReadAsset","Args":["Asset1"]}' -``` - -While we are operating as User1, we can demonstrate attribute based access control by trying to create an asset using an identity without the `abac.creator=true` attribute. Run the following command to try to create Asset1 as User1: -``` -peer chaincode invoke "${TARGET_TLS_OPTIONS[@]}" -C mychannel -n abac -c '{"function":"CreateAsset","Args":["Asset2","red","20","100"]}' -``` - -The smart contract will return the following error: -``` -Error: endorsement failure during invoke. response: status:500 message:"submitting client not authorized to create asset, does not have abac.creator role" -``` - -## Clean up - -When you are finished, you can run the following command to bring down the test network: -``` -./network.sh down -``` diff --git a/asset-transfer-abac/chaincode-go/go.mod b/asset-transfer-abac/chaincode-go/go.mod deleted file mode 100644 index 7d79a675..00000000 --- a/asset-transfer-abac/chaincode-go/go.mod +++ /dev/null @@ -1,32 +0,0 @@ -module github.com/hyperledger/fabric-samples/asset-transfer-abac/chaincode-go - -go 1.21 - -require github.com/hyperledger/fabric-contract-api-go/v2 v2.0.0 - -require ( - github.com/go-openapi/jsonpointer v0.21.0 // indirect - github.com/go-openapi/jsonreference v0.21.0 // indirect - github.com/go-openapi/spec v0.21.0 // indirect - github.com/go-openapi/swag v0.23.0 // indirect - github.com/gobuffalo/envy v1.10.2 // indirect - github.com/gobuffalo/packd v1.0.2 // indirect - github.com/gobuffalo/packr v1.30.1 // indirect - github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0-20240618210511-f7903324a8af // indirect - github.com/hyperledger/fabric-protos-go-apiv2 v0.3.3 // indirect - github.com/joho/godotenv v1.5.1 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/mailru/easyjson v0.7.7 // indirect - github.com/rogpeppe/go-internal v1.12.0 // indirect - github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect - github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect - github.com/xeipuuv/gojsonschema v1.2.0 // indirect - golang.org/x/mod v0.17.0 // indirect - golang.org/x/net v0.24.0 // indirect - golang.org/x/sys v0.19.0 // indirect - golang.org/x/text v0.14.0 // indirect - google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect - google.golang.org/grpc v1.64.0 // indirect - google.golang.org/protobuf v1.34.2 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) diff --git a/asset-transfer-abac/chaincode-go/go.sum b/asset-transfer-abac/chaincode-go/go.sum deleted file mode 100644 index 7c5e414c..00000000 --- a/asset-transfer-abac/chaincode-go/go.sum +++ /dev/null @@ -1,132 +0,0 @@ -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= -github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= -github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= -github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= -github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= -github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= -github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= -github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= -github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= -github.com/gobuffalo/envy v1.10.2 h1:EIi03p9c3yeuRCFPOKcSfajzkLb3hrRjEpHGI8I2Wo4= -github.com/gobuffalo/envy v1.10.2/go.mod h1:qGAGwdvDsaEtPhfBzb3o0SfDea8ByGn9j8bKmVft9z8= -github.com/gobuffalo/logger v1.0.0/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs= -github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q= -github.com/gobuffalo/packd v1.0.2 h1:Yg523YqnOxGIWCp69W12yYBKsoChwI7mtu6ceM9Bwfw= -github.com/gobuffalo/packd v1.0.2/go.mod h1:sUc61tDqGMXON80zpKGp92lDb86Km28jfvX7IAyxFT8= -github.com/gobuffalo/packr v1.30.1 h1:hu1fuVR3fXEZR7rXNW3h8rqSML8EVAf6KNm0NKO/wKg= -github.com/gobuffalo/packr v1.30.1/go.mod h1:ljMyFO2EcrnzsHsN99cvbq055Y9OhRrIaviy289eRuk= -github.com/gobuffalo/packr/v2 v2.5.1/go.mod h1:8f9c96ITobJlPzI44jj+4tHnEKNt0xXWSVlXRN9X1Iw= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0-20240618210511-f7903324a8af h1:WT4NjX7Uk03GSeH++jF3a0wp4FhybTM86zDPCETvmSk= -github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0-20240618210511-f7903324a8af/go.mod h1:f/ER25FaBepxJugwpLhbD2hLAoZaZEVqkBjOcHjw72Y= -github.com/hyperledger/fabric-contract-api-go/v2 v2.0.0 h1:IDiCGVOBlRd6zpL0Y+f6V7IpBqa4/Z5JAK9SF7a5ea8= -github.com/hyperledger/fabric-contract-api-go/v2 v2.0.0/go.mod h1:pdqhe7ALf4lmXgQdprCyNWYdnCPxgj02Vhf8JF5w8po= -github.com/hyperledger/fabric-protos-go-apiv2 v0.3.3 h1:Xpd6fzG/KjAOHJsq7EQXY2l+qi/y8muxBaY7R6QWABk= -github.com/hyperledger/fabric-protos-go-apiv2 v0.3.3/go.mod h1:2pq0ui6ZWA0cC8J+eCErgnMDCS1kPOEYVY+06ZAK0qE= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= -github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= -github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= -github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= -golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= -google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/asset-transfer-abac/chaincode-go/smart-contract/abac.go b/asset-transfer-abac/chaincode-go/smart-contract/abac.go deleted file mode 100644 index 30816c64..00000000 --- a/asset-transfer-abac/chaincode-go/smart-contract/abac.go +++ /dev/null @@ -1,214 +0,0 @@ -package abac - -import ( - "encoding/base64" - "encoding/json" - "fmt" - - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" -) - -// SmartContract provides functions for managing an Asset -type SmartContract struct { - contractapi.Contract -} - -// Asset describes basic details of what makes up a simple asset -type Asset struct { - ID string `json:"ID"` - Color string `json:"color"` - Size int `json:"size"` - Owner string `json:"owner"` - AppraisedValue int `json:"appraisedValue"` -} - -// CreateAsset issues a new asset to the world state with given details. -func (s *SmartContract) CreateAsset(ctx contractapi.TransactionContextInterface, id string, color string, size int, appraisedValue int) error { - - // Demonstrate the use of Attribute-Based Access Control (ABAC) by checking - // to see if the caller has the "abac.creator" attribute with a value of true; - // if not, return an error. - - err := ctx.GetClientIdentity().AssertAttributeValue("abac.creator", "true") - if err != nil { - return fmt.Errorf("submitting client not authorized to create asset, does not have abac.creator role") - } - - exists, err := s.AssetExists(ctx, id) - if err != nil { - return err - } - if exists { - return fmt.Errorf("the asset %s already exists", id) - } - - // Get ID of submitting client identity - clientID, err := s.GetSubmittingClientIdentity(ctx) - if err != nil { - return err - } - - asset := Asset{ - ID: id, - Color: color, - Size: size, - Owner: clientID, - AppraisedValue: appraisedValue, - } - assetJSON, err := json.Marshal(asset) - if err != nil { - return err - } - - return ctx.GetStub().PutState(id, assetJSON) -} - -// UpdateAsset updates an existing asset in the world state with provided parameters. -func (s *SmartContract) UpdateAsset(ctx contractapi.TransactionContextInterface, id string, newColor string, newSize int, newValue int) error { - - asset, err := s.ReadAsset(ctx, id) - if err != nil { - return err - } - - clientID, err := s.GetSubmittingClientIdentity(ctx) - if err != nil { - return err - } - - if clientID != asset.Owner { - return fmt.Errorf("submitting client not authorized to update asset, does not own asset") - } - - asset.Color = newColor - asset.Size = newSize - asset.AppraisedValue = newValue - - assetJSON, err := json.Marshal(asset) - if err != nil { - return err - } - - return ctx.GetStub().PutState(id, assetJSON) -} - -// DeleteAsset deletes a given asset from the world state. -func (s *SmartContract) DeleteAsset(ctx contractapi.TransactionContextInterface, id string) error { - - asset, err := s.ReadAsset(ctx, id) - if err != nil { - return err - } - - clientID, err := s.GetSubmittingClientIdentity(ctx) - if err != nil { - return err - } - - if clientID != asset.Owner { - return fmt.Errorf("submitting client not authorized to update asset, does not own asset") - } - - return ctx.GetStub().DelState(id) -} - -// TransferAsset updates the owner field of asset with given id in world state. -func (s *SmartContract) TransferAsset(ctx contractapi.TransactionContextInterface, id string, newOwner string) error { - - asset, err := s.ReadAsset(ctx, id) - if err != nil { - return err - } - - clientID, err := s.GetSubmittingClientIdentity(ctx) - if err != nil { - return err - } - - if clientID != asset.Owner { - return fmt.Errorf("submitting client not authorized to update asset, does not own asset") - } - - asset.Owner = newOwner - assetJSON, err := json.Marshal(asset) - if err != nil { - return err - } - - return ctx.GetStub().PutState(id, assetJSON) -} - -// ReadAsset returns the asset stored in the world state with given id. -func (s *SmartContract) ReadAsset(ctx contractapi.TransactionContextInterface, id string) (*Asset, error) { - - assetJSON, err := ctx.GetStub().GetState(id) - if err != nil { - return nil, fmt.Errorf("failed to read from world state: %v", err) - } - if assetJSON == nil { - return nil, fmt.Errorf("the asset %s does not exist", id) - } - - var asset Asset - err = json.Unmarshal(assetJSON, &asset) - if err != nil { - return nil, err - } - - return &asset, nil -} - -// GetAllAssets returns all assets found in world state -func (s *SmartContract) GetAllAssets(ctx contractapi.TransactionContextInterface) ([]*Asset, error) { - // range query with empty string for startKey and endKey does an - // open-ended query of all assets in the chaincode namespace. - resultsIterator, err := ctx.GetStub().GetStateByRange("", "") - if err != nil { - return nil, err - } - defer resultsIterator.Close() - - var assets []*Asset - for resultsIterator.HasNext() { - queryResponse, err := resultsIterator.Next() - if err != nil { - return nil, err - } - - var asset Asset - err = json.Unmarshal(queryResponse.Value, &asset) - if err != nil { - return nil, err - } - assets = append(assets, &asset) - } - - return assets, nil -} - -// AssetExists returns true when asset with given ID exists in world state -func (s *SmartContract) AssetExists(ctx contractapi.TransactionContextInterface, id string) (bool, error) { - - assetJSON, err := ctx.GetStub().GetState(id) - if err != nil { - return false, fmt.Errorf("failed to read from world state: %v", err) - } - - return assetJSON != nil, nil -} - -// GetSubmittingClientIdentity returns the name and issuer of the identity that -// invokes the smart contract. This function base64 decodes the identity string -// before returning the value to the client or smart contract. -func (s *SmartContract) GetSubmittingClientIdentity(ctx contractapi.TransactionContextInterface) (string, error) { - - b64ID, err := ctx.GetClientIdentity().GetID() - if err != nil { - return "", fmt.Errorf("Failed to read clientID: %v", err) - } - decodeID, err := base64.StdEncoding.DecodeString(b64ID) - if err != nil { - return "", fmt.Errorf("failed to base64 decode clientID: %v", err) - } - return string(decodeID), nil -} diff --git a/asset-transfer-abac/chaincode-go/smartContract.go b/asset-transfer-abac/chaincode-go/smartContract.go deleted file mode 100644 index cef4262b..00000000 --- a/asset-transfer-abac/chaincode-go/smartContract.go +++ /dev/null @@ -1,23 +0,0 @@ -/* -SPDX-License-Identifier: Apache-2.0 -*/ - -package main - -import ( - "log" - - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" - abac "github.com/hyperledger/fabric-samples/asset-transfer-abac/chaincode-go/smart-contract" -) - -func main() { - abacSmartContract, err := contractapi.NewChaincode(&abac.SmartContract{}) - if err != nil { - log.Panicf("Error creating abac chaincode: %v", err) - } - - if err := abacSmartContract.Start(); err != nil { - log.Panicf("Error starting abac chaincode: %v", err) - } -} diff --git a/asset-transfer-events/README.md b/asset-transfer-events/README.md deleted file mode 100644 index edfd1148..00000000 --- a/asset-transfer-events/README.md +++ /dev/null @@ -1,84 +0,0 @@ -# Asset transfer events sample - -The asset transfer events sample demonstrates: - -- Emitting chaincode events from smart contract transaction functions. -- Receiving chaincode events in a client application. -- Replaying previous chaincode events in a client application. - -Events are published when a block is committed to the ledger. - -For more information about event services on per-channel basis, visit the -[Channel-based event service](https://hyperledger-fabric.readthedocs.io/en/latest/peer_event_services.html) -page in the Fabric documentation. - - -## About the sample - -This sample includes smart contract and application code in multiple languages. In a use-case similar to basic asset transfer (see [asset-transfer-basic](../asset-transfer-basic) folder) this sample shows sending and receiving of events during create / update / delete of an asset, and during transfer of an asset to a new owner. - -### Application - -Follow the execution flow in the client application code, and corresponding output on running the application. Pay attention to the sequence of: - -- Transaction invocations (console output like "**--> Submit transaction**"). -- Events received by the application (console output like "**<-- Chaincode event received**"). - -Notice that events will be received by the listener after the application code submits the transaction and it is committed to the ledger, but during other application activity unrelated to the event. - -### Smart Contract - -The smart contract (in folder `chaincode-xyz`) implements the following functions to support the application: - -- CreateAsset -- ReadAsset -- UpdateAsset -- DeleteAsset -- TransferAsset - -Note that the asset transfer implemented by the smart contract is a simplified scenario, without ownership validation, meant only to demonstrate the use of sending and receiving events. - -## Running the sample - -Like other samples, the Fabric test network is used to deploy and run this sample. Follow these steps in order: - -1. Create the test network and a channel (from the `test-network` folder). - ``` - ./network.sh up createChannel -c mychannel -ca - ``` - -1. Deploy one of the smart contract implementations (from the `test-network` folder). - ``` - # To deploy the Go chaincode implementation - ./network.sh deployCC -ccn events -ccp ../asset-transfer-events/chaincode-go/ -ccl go -ccep "OR('Org1MSP.peer','Org2MSP.peer')" - - # To deploy the JavaScript chaincode implementation - ./network.sh deployCC -ccn events -ccp ../asset-transfer-events/chaincode-javascript/ -ccl javascript -ccep "OR('Org1MSP.peer','Org2MSP.peer')" - - # To deploy the Java chaincode implementation - ./network.sh deployCC -ccn events -ccp ../asset-transfer-events/chaincode-java/ -ccl java -ccep "OR('Org1MSP.peer','Org2MSP.peer')" - ``` - -1. Run the application (from the `asset-transfer-events` folder). - ``` - # To run the Go sample application - cd application-gateway-go - go run . - - # To run the TypeScript sample application - cd application-gateway-typescript - npm install - npm start - - # To run the Java sample application - cd application-gateway-java - ./gradlew run - ``` - -## Clean up - -When you are finished, you can bring down the test network (from the `test-network` folder). The command will remove all the nodes of the test network, and delete any ledger data that you created. - -``` -./network.sh down -``` \ No newline at end of file diff --git a/asset-transfer-events/application-gateway-go/app.go b/asset-transfer-events/application-gateway-go/app.go deleted file mode 100755 index 4046556c..00000000 --- a/asset-transfer-events/application-gateway-go/app.go +++ /dev/null @@ -1,170 +0,0 @@ -/* -Copyright 2022 IBM All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package main - -import ( - "bytes" - "context" - "encoding/json" - "errors" - "fmt" - "time" - - "github.com/hyperledger/fabric-gateway/pkg/client" -) - -const ( - channelName = "mychannel" - chaincodeName = "events" -) - -var now = time.Now() -var assetID = fmt.Sprintf("asset%d", now.Unix()*1e3+int64(now.Nanosecond())/1e6) - -func main() { - clientConnection := newGrpcConnection() - defer clientConnection.Close() - - id := newIdentity() - sign := newSign() - - gateway, err := client.Connect( - id, - client.WithSign(sign), - client.WithClientConnection(clientConnection), - client.WithEvaluateTimeout(5*time.Second), - client.WithEndorseTimeout(15*time.Second), - client.WithSubmitTimeout(5*time.Second), - client.WithCommitStatusTimeout(1*time.Minute), - ) - if err != nil { - panic(err) - } - defer gateway.Close() - - network := gateway.GetNetwork(channelName) - contract := network.GetContract(chaincodeName) - - // Context used for event listening - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - // Listen for events emitted by subsequent transactions - startChaincodeEventListening(ctx, network) - - firstBlockNumber := createAsset(contract) - updateAsset(contract) - transferAsset(contract) - deleteAsset(contract) - - // Replay events from the block containing the first transaction - replayChaincodeEvents(ctx, network, firstBlockNumber) -} - -func startChaincodeEventListening(ctx context.Context, network *client.Network) { - fmt.Println("\n*** Start chaincode event listening") - - events, err := network.ChaincodeEvents(ctx, chaincodeName) - if err != nil { - panic(fmt.Errorf("failed to start chaincode event listening: %w", err)) - } - - go func() { - for event := range events { - asset := formatJSON(event.Payload) - fmt.Printf("\n<-- Chaincode event received: %s - %s\n", event.EventName, asset) - } - }() -} - -func formatJSON(data []byte) string { - var result bytes.Buffer - if err := json.Indent(&result, data, "", " "); err != nil { - panic(fmt.Errorf("failed to parse JSON: %w", err)) - } - return result.String() -} - -func createAsset(contract *client.Contract) uint64 { - fmt.Printf("\n--> Submit transaction: CreateAsset, %s owned by Sam with appraised value 100\n", assetID) - - _, commit, err := contract.SubmitAsync("CreateAsset", client.WithArguments(assetID, "blue", "10", "Sam", "100")) - if err != nil { - panic(fmt.Errorf("failed to submit transaction: %w", err)) - } - - status, err := commit.Status() - if err != nil { - panic(fmt.Errorf("failed to get transaction commit status: %w", err)) - } - - if !status.Successful { - panic(fmt.Errorf("failed to commit transaction with status code %v", status.Code)) - } - - fmt.Println("\n*** CreateAsset committed successfully") - - return status.BlockNumber -} - -func updateAsset(contract *client.Contract) { - fmt.Printf("\n--> Submit transaction: UpdateAsset, %s update appraised value to 200\n", assetID) - - _, err := contract.SubmitTransaction("UpdateAsset", assetID, "blue", "10", "Sam", "200") - if err != nil { - panic(fmt.Errorf("failed to submit transaction: %w", err)) - } - - fmt.Println("\n*** UpdateAsset committed successfully") -} - -func transferAsset(contract *client.Contract) { - fmt.Printf("\n--> Submit transaction: TransferAsset, %s to Mary\n", assetID) - - _, err := contract.SubmitTransaction("TransferAsset", assetID, "Mary") - if err != nil { - panic(fmt.Errorf("failed to submit transaction: %w", err)) - } - - fmt.Println("\n*** TransferAsset committed successfully") -} - -func deleteAsset(contract *client.Contract) { - fmt.Printf("\n--> Submit transaction: DeleteAsset, %s\n", assetID) - - _, err := contract.SubmitTransaction("DeleteAsset", assetID) - if err != nil { - panic(fmt.Errorf("failed to submit transaction: %w", err)) - } - - fmt.Println("\n*** DeleteAsset committed successfully") -} - -func replayChaincodeEvents(ctx context.Context, network *client.Network, startBlock uint64) { - fmt.Println("\n*** Start chaincode event replay") - - events, err := network.ChaincodeEvents(ctx, chaincodeName, client.WithStartBlock(startBlock)) - if err != nil { - panic(fmt.Errorf("failed to start chaincode event listening: %w", err)) - } - - for { - select { - case <-time.After(10 * time.Second): - panic(errors.New("timeout waiting for event replay")) - - case event := <-events: - asset := formatJSON(event.Payload) - fmt.Printf("\n<-- Chaincode event replayed: %s - %s\n", event.EventName, asset) - - if event.EventName == "DeleteAsset" { - // Reached the last submitted transaction so return to stop listening for events - return - } - } - } -} diff --git a/asset-transfer-events/application-gateway-go/connect.go b/asset-transfer-events/application-gateway-go/connect.go deleted file mode 100755 index 7b21d8b1..00000000 --- a/asset-transfer-events/application-gateway-go/connect.go +++ /dev/null @@ -1,114 +0,0 @@ -/* -Copyright 2022 IBM All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package main - -import ( - "crypto/x509" - "fmt" - "os" - "path" - - "github.com/hyperledger/fabric-gateway/pkg/identity" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials" -) - -const ( - mspID = "Org1MSP" - cryptoPath = "../../test-network/organizations/peerOrganizations/org1.example.com" - certPath = cryptoPath + "/users/User1@org1.example.com/msp/signcerts" - keyPath = cryptoPath + "/users/User1@org1.example.com/msp/keystore" - tlsCertPath = cryptoPath + "/peers/peer0.org1.example.com/tls/ca.crt" - peerEndpoint = "dns:///localhost:7051" - gatewayPeer = "peer0.org1.example.com" -) - -// newGrpcConnection creates a gRPC connection to the Gateway server. -func newGrpcConnection() *grpc.ClientConn { - certificatePEM, err := os.ReadFile(tlsCertPath) - if err != nil { - panic(fmt.Errorf("failed to read TLS certifcate file: %w", err)) - } - - certificate, err := identity.CertificateFromPEM(certificatePEM) - if err != nil { - panic(err) - } - - certPool := x509.NewCertPool() - certPool.AddCert(certificate) - transportCredentials := credentials.NewClientTLSFromCert(certPool, gatewayPeer) - - connection, err := grpc.NewClient(peerEndpoint, grpc.WithTransportCredentials(transportCredentials)) - if err != nil { - panic(fmt.Errorf("failed to create gRPC connection: %w", err)) - } - - return connection -} - -// newIdentity creates a client identity for this Gateway connection using an X.509 certificate. -func newIdentity() *identity.X509Identity { - certificatePEM, err := readFirstFile(certPath) - if err != nil { - panic(fmt.Errorf("failed to read certificate file: %w", err)) - } - - certificate, err := identity.CertificateFromPEM(certificatePEM) - if err != nil { - panic(err) - } - - id, err := identity.NewX509Identity(mspID, certificate) - if err != nil { - panic(err) - } - - return id -} - -func loadCertificate(filename string) (*x509.Certificate, error) { - certificatePEM, err := os.ReadFile(filename) - if err != nil { - return nil, fmt.Errorf("failed to read certificate file: %w", err) - } - return identity.CertificateFromPEM(certificatePEM) -} - -// newSign creates a function that generates a digital signature from a message digest using a private key. -func newSign() identity.Sign { - privateKeyPEM, err := readFirstFile(keyPath) - if err != nil { - panic(fmt.Errorf("failed to read private key file: %w", err)) - } - - privateKey, err := identity.PrivateKeyFromPEM(privateKeyPEM) - if err != nil { - panic(err) - } - - sign, err := identity.NewPrivateKeySign(privateKey) - if err != nil { - panic(err) - } - - return sign -} - -func readFirstFile(dirPath string) ([]byte, error) { - dir, err := os.Open(dirPath) - if err != nil { - return nil, err - } - - fileNames, err := dir.Readdirnames(1) - if err != nil { - return nil, err - } - - return os.ReadFile(path.Join(dirPath, fileNames[0])) -} diff --git a/asset-transfer-events/application-gateway-go/go.mod b/asset-transfer-events/application-gateway-go/go.mod deleted file mode 100644 index 6d15b9ea..00000000 --- a/asset-transfer-events/application-gateway-go/go.mod +++ /dev/null @@ -1,19 +0,0 @@ -module assetTransfer - -go 1.21 - -require ( - github.com/hyperledger/fabric-gateway v1.5.0 - google.golang.org/grpc v1.63.2 -) - -require ( - github.com/hyperledger/fabric-protos-go-apiv2 v0.3.3 // indirect - github.com/miekg/pkcs11 v1.1.1 // indirect - golang.org/x/crypto v0.22.0 // indirect - golang.org/x/net v0.24.0 // indirect - golang.org/x/sys v0.19.0 // indirect - golang.org/x/text v0.14.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda // indirect - google.golang.org/protobuf v1.33.0 // indirect -) diff --git a/asset-transfer-events/application-gateway-go/go.sum b/asset-transfer-events/application-gateway-go/go.sum deleted file mode 100644 index cb50be2a..00000000 --- a/asset-transfer-events/application-gateway-go/go.sum +++ /dev/null @@ -1,32 +0,0 @@ -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/hyperledger/fabric-gateway v1.5.0 h1:JChlqtJNm2479Q8YWJ6k8wwzOiu2IRrV3K8ErsQmdTU= -github.com/hyperledger/fabric-gateway v1.5.0/go.mod h1:v13OkXAp7pKi4kh6P6epn27SyivRbljr8Gkfy8JlbtM= -github.com/hyperledger/fabric-protos-go-apiv2 v0.3.3 h1:Xpd6fzG/KjAOHJsq7EQXY2l+qi/y8muxBaY7R6QWABk= -github.com/hyperledger/fabric-protos-go-apiv2 v0.3.3/go.mod h1:2pq0ui6ZWA0cC8J+eCErgnMDCS1kPOEYVY+06ZAK0qE= -github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU= -github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo= -go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= -golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= -golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= -golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= -golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= -golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda h1:LI5DOvAxUPMv/50agcLLoo+AdWc1irS9Rzz4vPuD1V4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= -google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM= -google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/asset-transfer-events/application-gateway-java/build.gradle b/asset-transfer-events/application-gateway-java/build.gradle deleted file mode 100644 index 73665368..00000000 --- a/asset-transfer-events/application-gateway-java/build.gradle +++ /dev/null @@ -1,26 +0,0 @@ -plugins { - // Apply the application plugin to add support for building a CLI application. - id 'application' -} - -repositories { - mavenCentral() -} - -dependencies { - implementation 'org.hyperledger.fabric:fabric-gateway:1.4.0' - compileOnly 'io.grpc:grpc-api:1.59.0' - runtimeOnly 'io.grpc:grpc-netty-shaded:1.59.0' - implementation 'com.google.code.gson:gson:2.10.1' -} - -java { - toolchain { - languageVersion = JavaLanguageVersion.of(11) - } -} - -application { - // Define the main class for the application. - mainClass = 'App' -} diff --git a/asset-transfer-events/application-gateway-java/gradle/wrapper/gradle-wrapper.jar b/asset-transfer-events/application-gateway-java/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 7f93135c49b765f8051ef9d0a6055ff8e46073d8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 63721 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鯊%1Et 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⁢ zv5o9#E7!G0XmdzfsS{efPNi`1b44~SZ4Z8fuX!I}#8g+(wxzQwUT#Xb2(tbY1+EUhGKoT@KEU9Ktl>_0 z%bjDJg;#*gtJZv!-Zs`?^}v5eKmnbjqlvnSzE@_SP|LG_PJ6CYU+6zY6>92%E+ z=j@TZf-iW4(%U{lnYxQA;7Q!b;^brF8n0D>)`q5>|WDDXLrqYU_tKN2>=#@~OE7grMnNh?UOz-O~6 z6%rHy{#h9K0AT+lDC7q4{hw^|q6*Ry;;L%Q@)Ga}$60_q%D)rv(CtS$CQbpq9|y1e zRSrN4;$Jyl{m5bZw`$8TGvb}(LpY{-cQ)fcyJv7l3S52TLXVDsphtv&aPuDk1OzCA z4A^QtC(!11`IsNx_HnSy?>EKpHJWT^wmS~hc^p^zIIh@9f6U@I2 zC=Mve{j2^)mS#U$e{@Q?SO6%LDsXz@SY+=cK_QMmXBIU)j!$ajc-zLx3V60EXJ!qC zi<%2x8Q24YN+&8U@CIlN zrZkcT9yh%LrlGS9`G)KdP(@9Eo-AQz@8GEFWcb7U=a0H^ZVbLmz{+&M7W(nXJ4sN8 zJLR7eeK(K8`2-}j(T7JsO`L!+CvbueT%izanm-^A1Dn{`1Nw`9P?cq;7no+XfC`K(GO9?O^5zNIt4M+M8LM0=7Gz8UA@Z0N+lg+cX)NfazRu z5D)~HA^(u%w^cz+@2@_#S|u>GpB+j4KzQ^&Wcl9f z&hG#bCA(Yk0D&t&aJE^xME^&E-&xGHhXn%}psEIj641H+Nl-}boj;)Zt*t(4wZ5DN z@GXF$bL=&pBq-#vkTkh>7hl%K5|3 z{`Vn9b$iR-SoGENp}bn4;fR3>9sA%X2@1L3aE9yTra;Wb#_`xWwLSLdfu+PAu+o3| zGVnpzPr=ch{uuoHjtw7+_!L_2;knQ!DuDl0R`|%jr+}jFzXtrHIKc323?JO{l&;VF z*L1+}JU7%QJOg|5|Tc|D8fN zJORAg=_vsy{ak|o);@)Yh8Lkcg@$FG3k@ep36BRa^>~UmnRPziS>Z=`Jb2x*Q#`%A zU*i3&Vg?TluO@X0O;r2Jl6LKLUOVhSqg1*qOt^|8*c7 zo(298@+r$k_wQNGHv{|$tW(T8L+4_`FQ{kEW5Jgg{yf7ey4ss_(SNKfz(N9lx&a;< je(UuV8hP?p&}TPdm1I$XmG#(RzlD&B2izSj9sl%y5~4qc diff --git a/asset-transfer-events/application-gateway-java/gradle/wrapper/gradle-wrapper.properties b/asset-transfer-events/application-gateway-java/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index a80b22ce..00000000 --- a/asset-transfer-events/application-gateway-java/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,7 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip -networkTimeout=10000 -validateDistributionUrl=true -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/asset-transfer-events/application-gateway-java/gradlew b/asset-transfer-events/application-gateway-java/gradlew deleted file mode 100755 index 0adc8e1a..00000000 --- a/asset-transfer-events/application-gateway-java/gradlew +++ /dev/null @@ -1,249 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -# This is normally unused -# shellcheck disable=SC2034 -APP_BASE_NAME=${0##*/} -# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - if ! command -v java >/dev/null 2>&1 - then - die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/asset-transfer-events/application-gateway-java/gradlew.bat b/asset-transfer-events/application-gateway-java/gradlew.bat deleted file mode 100644 index 6689b85b..00000000 --- a/asset-transfer-events/application-gateway-java/gradlew.bat +++ /dev/null @@ -1,92 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/asset-transfer-events/application-gateway-java/settings.gradle b/asset-transfer-events/application-gateway-java/settings.gradle deleted file mode 100644 index acea186a..00000000 --- a/asset-transfer-events/application-gateway-java/settings.gradle +++ /dev/null @@ -1,10 +0,0 @@ -/* - * This file was generated by the Gradle 'init' task. - * - * The settings file is used to specify which projects to include in your build. - * - * Detailed information about configuring a multi-project build in Gradle can be found - * in the user manual at https://docs.gradle.org/6.5/userguide/multi_project_builds.html - */ - -rootProject.name = 'asset-transfer-events' diff --git a/asset-transfer-events/application-gateway-java/src/main/java/App.java b/asset-transfer-events/application-gateway-java/src/main/java/App.java deleted file mode 100644 index 7b0cfff5..00000000 --- a/asset-transfer-events/application-gateway-java/src/main/java/App.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonParser; -import io.grpc.Status; -import org.hyperledger.fabric.client.ChaincodeEvent; -import org.hyperledger.fabric.client.CloseableIterator; -import org.hyperledger.fabric.client.CommitException; -import org.hyperledger.fabric.client.CommitStatusException; -import org.hyperledger.fabric.client.Contract; -import org.hyperledger.fabric.client.EndorseException; -import org.hyperledger.fabric.client.Gateway; -import org.hyperledger.fabric.client.GatewayRuntimeException; -import org.hyperledger.fabric.client.Network; -import org.hyperledger.fabric.client.SubmitException; - -import java.nio.charset.StandardCharsets; -import java.time.Instant; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; - -public final class App implements AutoCloseable { - private static final String channelName = "mychannel"; - private static final String chaincodeName = "events"; - - private final Network network; - private final Contract contract; - private final String assetId = "asset" + Instant.now().toEpochMilli(); - private final Gson gson = new GsonBuilder().setPrettyPrinting().create(); - private final ExecutorService executor = Executors.newCachedThreadPool(); - - public static void main(final String[] args) throws Exception { - var grpcChannel = Connections.newGrpcConnection(); - var builder = Gateway.newInstance() - .identity(Connections.newIdentity()) - .signer(Connections.newSigner()) - .connection(grpcChannel) - .evaluateOptions(options -> options.withDeadlineAfter(5, TimeUnit.SECONDS)) - .endorseOptions(options -> options.withDeadlineAfter(15, TimeUnit.SECONDS)) - .submitOptions(options -> options.withDeadlineAfter(5, TimeUnit.SECONDS)) - .commitStatusOptions(options -> options.withDeadlineAfter(1, TimeUnit.MINUTES)); - - try (var gateway = builder.connect(); var app = new App(gateway)) { - app.run(); - } finally { - grpcChannel.shutdownNow().awaitTermination(5, TimeUnit.SECONDS); - } - } - - public App(final Gateway gateway) { - network = gateway.getNetwork(channelName); - contract = network.getContract(chaincodeName); - } - - public void run() throws EndorseException, SubmitException, CommitStatusException, CommitException { - // Listen for events emitted by subsequent transactions, stopping when the try-with-resources block exits - try (var eventSession = startChaincodeEventListening()) { - var firstBlockNumber = createAsset(); - updateAsset(); - transferAsset(); - deleteAsset(); - - // Replay events from the block containing the first transaction - replayChaincodeEvents(firstBlockNumber); - } - } - - private CloseableIterator startChaincodeEventListening() { - System.out.println("\n*** Start chaincode event listening"); - - var eventIter = network.getChaincodeEvents(chaincodeName); - executor.execute(() -> readEvents(eventIter)); - - return eventIter; - } - - private void readEvents(final CloseableIterator eventIter) { - try { - eventIter.forEachRemaining(event -> { - var payload = prettyJson(event.getPayload()); - System.out.println("\n<-- Chaincode event received: " + event.getEventName() + " - " + payload); - }); - } catch (GatewayRuntimeException e) { - if (e.getStatus().getCode() != Status.Code.CANCELLED) { - throw e; - } - } - } - - private String prettyJson(final byte[] json) { - return prettyJson(new String(json, StandardCharsets.UTF_8)); - } - - private String prettyJson(final String json) { - var parsedJson = JsonParser.parseString(json); - return gson.toJson(parsedJson); - } - - private long createAsset() throws EndorseException, SubmitException, CommitStatusException { - System.out.println("\n--> Submit transaction: CreateAsset, " + assetId + " owned by Sam with appraised value 100"); - - var commit = contract.newProposal("CreateAsset") - .addArguments(assetId, "blue", "10", "Sam", "100") - .build() - .endorse() - .submitAsync(); - - var status = commit.getStatus(); - if (!status.isSuccessful()) { - throw new RuntimeException("failed to commit transaction with status code " + status.getCode()); - } - - System.out.println("\n*** CreateAsset committed successfully"); - - return status.getBlockNumber(); - } - - private void updateAsset() throws EndorseException, SubmitException, CommitStatusException, CommitException { - System.out.println("\n--> Submit transaction: UpdateAsset, " + assetId + " update appraised value to 200"); - - contract.submitTransaction("UpdateAsset", assetId, "blue", "10", "Sam", "200"); - - System.out.println("\n*** UpdateAsset committed successfully"); - } - - private void transferAsset() throws EndorseException, SubmitException, CommitStatusException, CommitException { - System.out.println("\n--> Submit transaction: TransferAsset, " + assetId + " to Mary"); - - contract.submitTransaction("TransferAsset", assetId, "Mary"); - - System.out.println("\n*** TransferAsset committed successfully"); - } - - private void deleteAsset() throws EndorseException, SubmitException, CommitStatusException, CommitException { - System.out.println("\n--> Submit transaction: DeleteAsset, " + assetId); - - contract.submitTransaction("DeleteAsset", assetId); - - System.out.println("\n*** DeleteAsset committed successfully"); - } - - private void replayChaincodeEvents(final long startBlock) { - System.out.println("\n*** Start chaincode event replay"); - - var request = network.newChaincodeEventsRequest(chaincodeName) - .startBlock(startBlock) - .build(); - - try (var eventIter = request.getEvents()) { - while (eventIter.hasNext()) { - var event = eventIter.next(); - var payload = prettyJson(event.getPayload()); - System.out.println("\n<-- Chaincode event replayed: " + event.getEventName() + " - " + payload); - - if (event.getEventName().equals("DeleteAsset")) { - // Reached the last submitted transaction so break to close the iterator and stop listening for events - break; - } - } - } - } - - @Override - public void close() throws Exception { - executor.shutdownNow(); - } -} diff --git a/asset-transfer-events/application-gateway-java/src/main/java/Connections.java b/asset-transfer-events/application-gateway-java/src/main/java/Connections.java deleted file mode 100644 index 6902fc03..00000000 --- a/asset-transfer-events/application-gateway-java/src/main/java/Connections.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -import io.grpc.Grpc; -import io.grpc.ManagedChannel; -import io.grpc.TlsChannelCredentials; -import org.hyperledger.fabric.client.identity.Identities; -import org.hyperledger.fabric.client.identity.Identity; -import org.hyperledger.fabric.client.identity.Signer; -import org.hyperledger.fabric.client.identity.Signers; -import org.hyperledger.fabric.client.identity.X509Identity; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.security.InvalidKeyException; -import java.security.cert.CertificateException; - -public final class Connections { - // Path to crypto materials. - private static final Path cryptoPath = Paths.get("..", "..", "test-network", "organizations", "peerOrganizations", "org1.example.com"); - // Path to user certificate. - private static final Path certDirPath = cryptoPath.resolve(Paths.get("users", "User1@org1.example.com", "msp", "signcerts")); - // Path to user private key directory. - private static final Path keyDirPath = cryptoPath.resolve(Paths.get("users", "User1@org1.example.com", "msp", "keystore")); - // Path to peer tls certificate. - private static final Path tlsCertPath = cryptoPath.resolve(Paths.get("peers", "peer0.org1.example.com", "tls", "ca.crt")); - - // Gateway peer end point. - private static final String peerEndpoint = "localhost:7051"; - private static final String overrideAuth = "peer0.org1.example.com"; - - private static final String mspID = "Org1MSP"; - - private Connections() { - // Private constructor to prevent instantiation - } - - public static ManagedChannel newGrpcConnection() throws IOException { - var credentials = TlsChannelCredentials.newBuilder() - .trustManager(tlsCertPath.toFile()) - .build(); - return Grpc.newChannelBuilder(peerEndpoint, credentials) - .overrideAuthority(overrideAuth) - .build(); - } - - public static Identity newIdentity() throws IOException, CertificateException { - try (var certReader = Files.newBufferedReader(getFirstFilePath(certDirPath))) { - var certificate = Identities.readX509Certificate(certReader); - return new X509Identity(mspID, certificate); - } - } - - public static Signer newSigner() throws IOException, InvalidKeyException { - try (var keyReader = Files.newBufferedReader(getFirstFilePath(keyDirPath))) { - var privateKey = Identities.readPrivateKey(keyReader); - return Signers.newPrivateKeySigner(privateKey); - } - } - - private static Path getFirstFilePath(Path dirPath) throws IOException { - try (var keyFiles = Files.list(dirPath)) { - return keyFiles.findFirst().orElseThrow(); - } - }} diff --git a/asset-transfer-events/application-gateway-typescript/.gitignore b/asset-transfer-events/application-gateway-typescript/.gitignore deleted file mode 100644 index 99e5af9f..00000000 --- a/asset-transfer-events/application-gateway-typescript/.gitignore +++ /dev/null @@ -1,14 +0,0 @@ -# -# SPDX-License-Identifier: Apache-2.0 -# - - -# Coverage directory used by tools like istanbul -coverage - -# Dependency directories -node_modules/ -jspm_packages/ - -# Compiled TypeScript files -dist diff --git a/asset-transfer-events/application-gateway-typescript/.npmrc b/asset-transfer-events/application-gateway-typescript/.npmrc deleted file mode 100644 index b6f27f13..00000000 --- a/asset-transfer-events/application-gateway-typescript/.npmrc +++ /dev/null @@ -1 +0,0 @@ -engine-strict=true diff --git a/asset-transfer-events/application-gateway-typescript/eslint.config.mjs b/asset-transfer-events/application-gateway-typescript/eslint.config.mjs deleted file mode 100644 index 9ef6b243..00000000 --- a/asset-transfer-events/application-gateway-typescript/eslint.config.mjs +++ /dev/null @@ -1,13 +0,0 @@ -import js from '@eslint/js'; -import tseslint from 'typescript-eslint'; - -export default tseslint.config(js.configs.recommended, ...tseslint.configs.strictTypeChecked, { - languageOptions: { - ecmaVersion: 2023, - sourceType: 'module', - parserOptions: { - project: 'tsconfig.json', - tsconfigRootDir: import.meta.dirname, - }, - }, -}); diff --git a/asset-transfer-events/application-gateway-typescript/package.json b/asset-transfer-events/application-gateway-typescript/package.json deleted file mode 100755 index 82248261..00000000 --- a/asset-transfer-events/application-gateway-typescript/package.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "name": "asset-transfer-events", - "version": "1.0.0", - "description": "Asset Transfer Events Application implemented in typeScript using fabric-gateway", - "main": "dist/index.js", - "typings": "dist/index.d.ts", - "engines": { - "node": ">=18" - }, - "scripts": { - "build": "tsc", - "build:watch": "tsc -w", - "lint": "eslint src", - "prepare": "npm run build", - "pretest": "npm run lint", - "start": "node dist/app.js" - }, - "engineStrict": true, - "author": "Hyperledger", - "license": "Apache-2.0", - "dependencies": { - "@grpc/grpc-js": "^1.10", - "@hyperledger/fabric-gateway": "^1.5" - }, - "devDependencies": { - "@eslint/js": "^9.3.0", - "@tsconfig/node18": "^18.2.2", - "@types/node": "^18.18.6", - "eslint": "^8.57.0", - "typescript": "~5.4", - "typescript-eslint": "^7.13.0" - } -} diff --git a/asset-transfer-events/application-gateway-typescript/src/app.ts b/asset-transfer-events/application-gateway-typescript/src/app.ts deleted file mode 100755 index 24ef3339..00000000 --- a/asset-transfer-events/application-gateway-typescript/src/app.ts +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as grpc from '@grpc/grpc-js'; -import { ChaincodeEvent, CloseableAsyncIterable, connect, Contract, GatewayError, Network } from '@hyperledger/fabric-gateway'; -import { TextDecoder } from 'util'; -import { newGrpcConnection, newIdentity, newSigner } from './connect'; - -const channelName = 'mychannel'; -const chaincodeName = 'events'; - -const utf8Decoder = new TextDecoder(); -const now = Date.now(); -const assetId = `asset${String(now)}`; - - -async function main(): Promise { - const client = await newGrpcConnection(); - const gateway = connect({ - client, - identity: await newIdentity(), - signer: await newSigner(), - evaluateOptions: () => { - return { deadline: Date.now() + 5000 }; // 5 seconds - }, - endorseOptions: () => { - return { deadline: Date.now() + 15000 }; // 15 seconds - }, - submitOptions: () => { - return { deadline: Date.now() + 5000 }; // 5 seconds - }, - commitStatusOptions: () => { - return { deadline: Date.now() + 60000 }; // 1 minute - }, - }); - - let events: CloseableAsyncIterable | undefined; - - try { - const network = gateway.getNetwork(channelName); - const contract = network.getContract(chaincodeName); - - // Listen for events emitted by subsequent transactions - events = await startEventListening(network); - - const firstBlockNumber = await createAsset(contract); - await updateAsset(contract); - await transferAsset(contract); - await deleteAssetByID(contract); - - // Replay events from the block containing the first transaction - await replayChaincodeEvents(network,firstBlockNumber); - } finally { - events?.close(); - gateway.close(); - client.close(); - } -} - -main().catch((error: unknown) => { - console.error('******** FAILED to run the application:', error); - process.exitCode = 1; -}); - -async function startEventListening(network: Network): Promise> { - console.log('\n*** Start chaincode event listening'); - - const events = await network.getChaincodeEvents(chaincodeName); - - void readEvents(events); // Don't await - run asynchronously - return events; -} - -async function readEvents(events: CloseableAsyncIterable): Promise { - try { - for await (const event of events) { - const payload = parseJson(event.payload); - console.log(`\n<-- Chaincode event received: ${event.eventName} -`, payload); - } - } catch (error: unknown) { - // Ignore the read error when events.close() is called explicitly - if (!(error instanceof GatewayError) || error.code !== grpc.status.CANCELLED.valueOf()) { - throw error; - } - } -} - -function parseJson(jsonBytes: Uint8Array): unknown { - const json = utf8Decoder.decode(jsonBytes); - return JSON.parse(json); -} - -async function createAsset(contract: Contract): Promise { - console.log(`\n--> Submit Transaction: CreateAsset, ${assetId} owned by Sam with appraised value 100`); - - const result = await contract.submitAsync('CreateAsset', { - arguments: [ assetId, 'blue', '10', 'Sam', '100' ], - }); - - const status = await result.getStatus(); - if (!status.successful) { - throw new Error(`failed to commit transaction ${status.transactionId} with status code ${String(status.code)}`); - } - - console.log('\n*** CreateAsset committed successfully'); - - return status.blockNumber; -} - -async function updateAsset(contract: Contract): Promise { - console.log(`\n--> Submit transaction: UpdateAsset, ${assetId} update appraised value to 200`); - - await contract.submitTransaction('UpdateAsset', assetId, 'blue', '10', 'Sam', '200'); - - console.log('\n*** UpdateAsset committed successfully'); -} - -async function transferAsset(contract: Contract): Promise { - console.log(`\n--> Submit transaction: TransferAsset, ${assetId} to Mary`); - - await contract.submitTransaction('TransferAsset', assetId, 'Mary'); - - console.log('\n*** TransferAsset committed successfully'); -} - -async function deleteAssetByID(contract: Contract): Promise{ - console.log(`\n--> Submit transaction: DeleteAsset, ${assetId}`); - - await contract.submitTransaction('DeleteAsset', assetId); - - console.log('\n*** DeleteAsset committed successfully'); -} - -async function replayChaincodeEvents(network: Network, startBlock: bigint): Promise { - console.log('\n*** Start chaincode event replay'); - - const events = await network.getChaincodeEvents(chaincodeName, { - startBlock, - }); - - try { - for await (const event of events) { - const payload = parseJson(event.payload); - console.log(`\n<-- Chaincode event replayed: ${event.eventName} -`, payload); - - if (event.eventName === 'DeleteAsset') { - // Reached the last submitted transaction so break to stop listening for events - break; - } - } - } finally { - events.close(); - } -} diff --git a/asset-transfer-events/application-gateway-typescript/src/connect.ts b/asset-transfer-events/application-gateway-typescript/src/connect.ts deleted file mode 100644 index c72f766a..00000000 --- a/asset-transfer-events/application-gateway-typescript/src/connect.ts +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as grpc from '@grpc/grpc-js'; -import { Identity, Signer, signers } from '@hyperledger/fabric-gateway'; -import * as crypto from 'crypto'; -import { promises as fs } from 'fs'; -import * as path from 'path'; - -const mspId = 'Org1MSP'; - -// Path to crypto materials. -const cryptoPath = path.resolve(__dirname, '..', '..', '..', 'test-network', 'organizations', 'peerOrganizations', 'org1.example.com'); - -// Path to user private key directory. -const keyDirectoryPath = path.resolve(cryptoPath, 'users', 'User1@org1.example.com', 'msp', 'keystore'); - -// Path to user certificate. -const certDirectoryPath = path.resolve(cryptoPath, 'users', 'User1@org1.example.com', 'msp', 'signcerts'); - -// Path to peer tls certificate. -const tlsCertPath = path.resolve(cryptoPath, 'peers', 'peer0.org1.example.com', 'tls', 'ca.crt'); - -// Gateway peer endpoint. -const peerEndpoint = 'localhost:7051'; - -export async function newGrpcConnection(): Promise { - const tlsRootCert = await fs.readFile(tlsCertPath); - const tlsCredentials = grpc.credentials.createSsl(tlsRootCert); - return new grpc.Client(peerEndpoint, tlsCredentials, { - 'grpc.ssl_target_name_override': 'peer0.org1.example.com', - }); -} - -export async function newIdentity(): Promise { - const certPath = await getFirstDirFileName(certDirectoryPath); - const credentials = await fs.readFile(certPath); - return { mspId, credentials }; -} - -export async function newSigner(): Promise { - const keyPath = await getFirstDirFileName(keyDirectoryPath); - const privateKeyPem = await fs.readFile(keyPath); - const privateKey = crypto.createPrivateKey(privateKeyPem); - return signers.newPrivateKeySigner(privateKey); -} - -async function getFirstDirFileName(dirPath: string): Promise { - const files = await fs.readdir(dirPath); - const file = files[0]; - if (!file) { - throw new Error(`No files in directory: ${dirPath}`); - } - return path.join(dirPath, file); -} diff --git a/asset-transfer-events/application-gateway-typescript/tsconfig.json b/asset-transfer-events/application-gateway-typescript/tsconfig.json deleted file mode 100644 index 4c20df24..00000000 --- a/asset-transfer-events/application-gateway-typescript/tsconfig.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "extends": "@tsconfig/node18/tsconfig.json", - "compilerOptions": { - "outDir": "dist", - "declaration": true, - "declarationMap": true, - "sourceMap": true, - "noUnusedLocals": true, - "noImplicitReturns": true, - "noUncheckedIndexedAccess": true, - "forceConsistentCasingInFileNames": true - }, - "include": ["./src/**/*"], - "exclude": ["./src/**/*.spec.ts"] -} diff --git a/asset-transfer-events/chaincode-go/assetTransferEvents.go b/asset-transfer-events/chaincode-go/assetTransferEvents.go deleted file mode 100644 index 4aede5c1..00000000 --- a/asset-transfer-events/chaincode-go/assetTransferEvents.go +++ /dev/null @@ -1,23 +0,0 @@ -/* -SPDX-License-Identifier: Apache-2.0 -*/ - -package main - -import ( - "log" - - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" - "github.com/hyperledger/fabric-samples/asset-transfer-events/chaincode-go/chaincode" -) - -func main() { - assetChaincode, err := contractapi.NewChaincode(&chaincode.SmartContract{}) - if err != nil { - log.Panicf("Error creating asset-transfer-events chaincode: %v", err) - } - - if err := assetChaincode.Start(); err != nil { - log.Panicf("Error starting asset-transfer-events chaincode: %v", err) - } -} diff --git a/asset-transfer-events/chaincode-go/chaincode/smartcontract.go b/asset-transfer-events/chaincode-go/chaincode/smartcontract.go deleted file mode 100644 index e9420cfa..00000000 --- a/asset-transfer-events/chaincode-go/chaincode/smartcontract.go +++ /dev/null @@ -1,134 +0,0 @@ -package chaincode - -import ( - "encoding/json" - "fmt" - - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" -) - -// SmartContract provides functions for managing an Asset -type SmartContract struct { - contractapi.Contract -} - -// Asset describes basic details of what makes up a simple asset -// Insert struct field in alphabetic order => to achieve determinism across languages -// golang keeps the order when marshal to json but doesn't order automatically -type Asset struct { - AppraisedValue int `json:"AppraisedValue"` - Color string `json:"Color"` - ID string `json:"ID"` - Owner string `json:"Owner"` - Size int `json:"Size"` -} - -// CreateAsset issues a new asset to the world state with given details. -func (s *SmartContract) CreateAsset(ctx contractapi.TransactionContextInterface, id string, color string, size int, owner string, appraisedValue int) error { - existing, err := s.readState(ctx, id) - if err == nil && existing != nil { - return fmt.Errorf("the asset %s already exists", id) - } - - asset := Asset{ - ID: id, - Color: color, - Size: size, - Owner: owner, - AppraisedValue: appraisedValue, - } - assetJSON, err := json.Marshal(asset) - if err != nil { - return err - } - - ctx.GetStub().SetEvent("CreateAsset", assetJSON) - return ctx.GetStub().PutState(id, assetJSON) -} - -func (s *SmartContract) readState(ctx contractapi.TransactionContextInterface, id string) ([]byte, error) { - assetJSON, err := ctx.GetStub().GetState(id) - if err != nil { - return nil, fmt.Errorf("failed to read from world state: %w", err) - } - if assetJSON == nil { - return nil, fmt.Errorf("the asset %s does not exist", id) - } - - return assetJSON, nil -} - -// ReadAsset returns the asset stored in the world state with given id. -func (s *SmartContract) ReadAsset(ctx contractapi.TransactionContextInterface, id string) (*Asset, error) { - assetJSON, err := s.readState(ctx, id) - if err != nil { - return nil, err - } - - var asset Asset - err = json.Unmarshal(assetJSON, &asset) - if err != nil { - return nil, err - } - - return &asset, nil -} - -// UpdateAsset updates an existing asset in the world state with provided parameters. -func (s *SmartContract) UpdateAsset(ctx contractapi.TransactionContextInterface, id string, color string, size int, owner string, appraisedValue int) error { - _, err := s.readState(ctx, id) - if err != nil { - return err - } - - // overwriting original asset with new asset - asset := Asset{ - ID: id, - Color: color, - Size: size, - Owner: owner, - AppraisedValue: appraisedValue, - } - assetJSON, err := json.Marshal(asset) - if err != nil { - return err - } - - ctx.GetStub().SetEvent("UpdateAsset", assetJSON) - return ctx.GetStub().PutState(id, assetJSON) -} - -// DeleteAsset deletes an given asset from the world state. -func (s *SmartContract) DeleteAsset(ctx contractapi.TransactionContextInterface, id string) error { - assetJSON, err := s.readState(ctx, id) - if err != nil { - return err - } - - ctx.GetStub().SetEvent("DeleteAsset", assetJSON) - return ctx.GetStub().DelState(id) -} - -// TransferAsset updates the owner field of asset with given id in world state, and returns the old owner. -func (s *SmartContract) TransferAsset(ctx contractapi.TransactionContextInterface, id string, newOwner string) (string, error) { - asset, err := s.ReadAsset(ctx, id) - if err != nil { - return "", err - } - - oldOwner := asset.Owner - asset.Owner = newOwner - - assetJSON, err := json.Marshal(asset) - if err != nil { - return "", err - } - - ctx.GetStub().SetEvent("TransferAsset", assetJSON) - err = ctx.GetStub().PutState(id, assetJSON) - if err != nil { - return "", err - } - - return oldOwner, nil -} diff --git a/asset-transfer-events/chaincode-go/go.mod b/asset-transfer-events/chaincode-go/go.mod deleted file mode 100644 index 3b0fadac..00000000 --- a/asset-transfer-events/chaincode-go/go.mod +++ /dev/null @@ -1,32 +0,0 @@ -module github.com/hyperledger/fabric-samples/asset-transfer-events/chaincode-go - -go 1.21 - -require github.com/hyperledger/fabric-contract-api-go/v2 v2.0.0 - -require ( - github.com/go-openapi/jsonpointer v0.21.0 // indirect - github.com/go-openapi/jsonreference v0.21.0 // indirect - github.com/go-openapi/spec v0.21.0 // indirect - github.com/go-openapi/swag v0.23.0 // indirect - github.com/gobuffalo/envy v1.10.2 // indirect - github.com/gobuffalo/packd v1.0.2 // indirect - github.com/gobuffalo/packr v1.30.1 // indirect - github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0-20240618210511-f7903324a8af // indirect - github.com/hyperledger/fabric-protos-go-apiv2 v0.3.3 // indirect - github.com/joho/godotenv v1.5.1 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/mailru/easyjson v0.7.7 // indirect - github.com/rogpeppe/go-internal v1.12.0 // indirect - github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect - github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect - github.com/xeipuuv/gojsonschema v1.2.0 // indirect - golang.org/x/mod v0.17.0 // indirect - golang.org/x/net v0.24.0 // indirect - golang.org/x/sys v0.19.0 // indirect - golang.org/x/text v0.14.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 // indirect - google.golang.org/grpc v1.64.0 // indirect - google.golang.org/protobuf v1.34.2 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) diff --git a/asset-transfer-events/chaincode-go/go.sum b/asset-transfer-events/chaincode-go/go.sum deleted file mode 100644 index a70936b0..00000000 --- a/asset-transfer-events/chaincode-go/go.sum +++ /dev/null @@ -1,132 +0,0 @@ -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= -github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= -github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= -github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= -github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= -github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= -github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= -github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= -github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= -github.com/gobuffalo/envy v1.10.2 h1:EIi03p9c3yeuRCFPOKcSfajzkLb3hrRjEpHGI8I2Wo4= -github.com/gobuffalo/envy v1.10.2/go.mod h1:qGAGwdvDsaEtPhfBzb3o0SfDea8ByGn9j8bKmVft9z8= -github.com/gobuffalo/logger v1.0.0/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs= -github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q= -github.com/gobuffalo/packd v1.0.2 h1:Yg523YqnOxGIWCp69W12yYBKsoChwI7mtu6ceM9Bwfw= -github.com/gobuffalo/packd v1.0.2/go.mod h1:sUc61tDqGMXON80zpKGp92lDb86Km28jfvX7IAyxFT8= -github.com/gobuffalo/packr v1.30.1 h1:hu1fuVR3fXEZR7rXNW3h8rqSML8EVAf6KNm0NKO/wKg= -github.com/gobuffalo/packr v1.30.1/go.mod h1:ljMyFO2EcrnzsHsN99cvbq055Y9OhRrIaviy289eRuk= -github.com/gobuffalo/packr/v2 v2.5.1/go.mod h1:8f9c96ITobJlPzI44jj+4tHnEKNt0xXWSVlXRN9X1Iw= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0-20240618210511-f7903324a8af h1:WT4NjX7Uk03GSeH++jF3a0wp4FhybTM86zDPCETvmSk= -github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0-20240618210511-f7903324a8af/go.mod h1:f/ER25FaBepxJugwpLhbD2hLAoZaZEVqkBjOcHjw72Y= -github.com/hyperledger/fabric-contract-api-go/v2 v2.0.0 h1:IDiCGVOBlRd6zpL0Y+f6V7IpBqa4/Z5JAK9SF7a5ea8= -github.com/hyperledger/fabric-contract-api-go/v2 v2.0.0/go.mod h1:pdqhe7ALf4lmXgQdprCyNWYdnCPxgj02Vhf8JF5w8po= -github.com/hyperledger/fabric-protos-go-apiv2 v0.3.3 h1:Xpd6fzG/KjAOHJsq7EQXY2l+qi/y8muxBaY7R6QWABk= -github.com/hyperledger/fabric-protos-go-apiv2 v0.3.3/go.mod h1:2pq0ui6ZWA0cC8J+eCErgnMDCS1kPOEYVY+06ZAK0qE= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= -github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= -github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= -github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= -golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 h1:Zy9XzmMEflZ/MAaA7vNcoebnRAld7FsPW1EeBB7V0m8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= -google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= -google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/asset-transfer-events/chaincode-java/build.gradle b/asset-transfer-events/chaincode-java/build.gradle deleted file mode 100644 index 202333bd..00000000 --- a/asset-transfer-events/chaincode-java/build.gradle +++ /dev/null @@ -1,69 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ - -plugins { - id 'com.github.johnrengelman.shadow' version '8.1.1' - id 'application' - id 'checkstyle' - id 'jacoco' -} - -group 'org.hyperledger.fabric.samples' -version '1.0-SNAPSHOT' - -dependencies { - implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.+' - implementation 'org.json:json:+' - testImplementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.+' -} - -repositories { - mavenCentral() - maven { - url 'https://jitpack.io' - } -} - -java { - toolchain { - languageVersion = JavaLanguageVersion.of(11) - } -} - -application { - mainClassName = 'org.hyperledger.fabric.contract.ContractRouter' -} - - -checkstyle { - toolVersion '8.21' - configFile file("config/checkstyle/checkstyle.xml") -} - -checkstyleMain { - source ='src/main/java' -} - -checkstyleTest { - source ='src/test/java' -} - -jacocoTestReport { - dependsOn test -} - -mainClassName = 'org.hyperledger.fabric.contract.ContractRouter' - -shadowJar { - archiveBaseName = 'chaincode' - archiveVersion = '' - archiveClassifier = '' - mergeServiceFiles() - - manifest { - attributes 'Main-Class': 'org.hyperledger.fabric.contract.ContractRouter' - } -} - -installDist.dependsOn check diff --git a/asset-transfer-events/chaincode-java/config/checkstyle/checkstyle.xml b/asset-transfer-events/chaincode-java/config/checkstyle/checkstyle.xml deleted file mode 100644 index acd5df44..00000000 --- a/asset-transfer-events/chaincode-java/config/checkstyle/checkstyle.xml +++ /dev/null @@ -1,171 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/asset-transfer-events/chaincode-java/config/checkstyle/suppressions.xml b/asset-transfer-events/chaincode-java/config/checkstyle/suppressions.xml deleted file mode 100644 index 33dda041..00000000 --- a/asset-transfer-events/chaincode-java/config/checkstyle/suppressions.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - diff --git a/asset-transfer-events/chaincode-java/gradle/wrapper/gradle-wrapper.jar b/asset-transfer-events/chaincode-java/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 7f93135c49b765f8051ef9d0a6055ff8e46073d8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 63721 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鯊%1Et zwk~hMkhq;MOw^Q5`7oC{CUUyTw9x>^%*FHx^qJw(LB+E0WBX@{Ghw;)6aA-KyYg8p z7XDveQOpEr;B4je@2~usI5BlFadedX^ma{b{ypd|RNYqo#~d*mj&y`^iojR}s%~vF z(H!u`yx68D1Tj(3(m;Q+Ma}s2n#;O~bcB1`lYk%Irx60&-nWIUBr2x&@}@76+*zJ5 ze&4?q8?m%L9c6h=J$WBzbiTf1Z-0Eb5$IZs>lvm$>1n_Mezp*qw_pr8<8$6f)5f<@ zyV#tzMCs51nTv_5ca`x`yfE5YA^*%O_H?;tWYdM_kHPubA%vy47i=9>Bq) zRQ&0UwLQHeswmB1yP)+BiR;S+Vc-5TX84KUA;8VY9}yEj0eESSO`7HQ4lO z4(CyA8y1G7_C;6kd4U3K-aNOK!sHE}KL_-^EDl(vB42P$2Km7$WGqNy=%fqB+ zSLdrlcbEH=T@W8V4(TgoXZ*G1_aq$K^@ek=TVhoKRjw;HyI&coln|uRr5mMOy2GXP zwr*F^Y|!Sjr2YQXX(Fp^*`Wk905K%$bd03R4(igl0&7IIm*#f`A!DCarW9$h$z`kYk9MjjqN&5-DsH@8xh63!fTNPxWsFQhNv z#|3RjnP$Thdb#Ys7M+v|>AHm0BVTw)EH}>x@_f4zca&3tXJhTZ8pO}aN?(dHo)44Z z_5j+YP=jMlFqwvf3lq!57-SAuRV2_gJ*wsR_!Y4Z(trO}0wmB9%f#jNDHPdQGHFR; zZXzS-$`;7DQ5vF~oSgP3bNV$6Z(rwo6W(U07b1n3UHqml>{=6&-4PALATsH@Bh^W? z)ob%oAPaiw{?9HfMzpGb)@Kys^J$CN{uf*HX?)z=g`J(uK1YO^8~s1(ZIbG%Et(|q z$D@_QqltVZu9Py4R0Ld8!U|#`5~^M=b>fnHthzKBRr=i+w@0Vr^l|W;=zFT#PJ?*a zbC}G#It}rQP^Ait^W&aa6B;+0gNvz4cWUMzpv(1gvfw-X4xJ2Sv;mt;zb2Tsn|kSS zo*U9N?I{=-;a-OybL4r;PolCfiaL=y@o9{%`>+&FI#D^uy#>)R@b^1ue&AKKwuI*` zx%+6r48EIX6nF4o;>)zhV_8(IEX})NGU6Vs(yslrx{5fII}o3SMHW7wGtK9oIO4OM&@@ECtXSICLcPXoS|{;=_yj>hh*%hP27yZwOmj4&Lh z*Nd@OMkd!aKReoqNOkp5cW*lC)&C$P?+H3*%8)6HcpBg&IhGP^77XPZpc%WKYLX$T zsSQ$|ntaVVOoRat$6lvZO(G-QM5s#N4j*|N_;8cc2v_k4n6zx9c1L4JL*83F-C1Cn zaJhd;>rHXB%%ZN=3_o3&Qd2YOxrK~&?1=UuN9QhL$~OY-Qyg&})#ez*8NpQW_*a&kD&ANjedxT0Ar z<6r{eaVz3`d~+N~vkMaV8{F?RBVemN(jD@S8qO~L{rUw#=2a$V(7rLE+kGUZ<%pdr z?$DP|Vg#gZ9S}w((O2NbxzQ^zTot=89!0^~hE{|c9q1hVzv0?YC5s42Yx($;hAp*E zyoGuRyphQY{Q2ee0Xx`1&lv(l-SeC$NEyS~8iil3_aNlnqF_G|;zt#F%1;J)jnPT& z@iU0S;wHJ2$f!juqEzPZeZkjcQ+Pa@eERSLKsWf=`{R@yv7AuRh&ALRTAy z8=g&nxsSJCe!QLchJ=}6|LshnXIK)SNd zRkJNiqHwKK{SO;N5m5wdL&qK`v|d?5<4!(FAsDxR>Ky#0#t$8XCMptvNo?|SY?d8b z`*8dVBlXTUanlh6n)!EHf2&PDG8sXNAt6~u-_1EjPI1|<=33T8 zEnA00E!`4Ave0d&VVh0e>)Dc}=FfAFxpsC1u9ATfQ`-Cu;mhc8Z>2;uyXtqpLb7(P zd2F9<3cXS} znMg?{&8_YFTGRQZEPU-XPq55%51}RJpw@LO_|)CFAt62-_!u_Uq$csc+7|3+TV_!h z+2a7Yh^5AA{q^m|=KSJL+w-EWDBc&I_I1vOr^}P8i?cKMhGy$CP0XKrQzCheG$}G# zuglf8*PAFO8%xop7KSwI8||liTaQ9NCAFarr~psQt)g*pC@9bORZ>m`_GA`_K@~&% zijH0z;T$fd;-Liw8%EKZas>BH8nYTqsK7F;>>@YsE=Rqo?_8}UO-S#|6~CAW0Oz1} z3F(1=+#wrBJh4H)9jTQ_$~@#9|Bc1Pd3rAIA_&vOpvvbgDJOM(yNPhJJq2%PCcMaI zrbe~toYzvkZYQ{ea(Wiyu#4WB#RRN%bMe=SOk!CbJZv^m?Flo5p{W8|0i3`hI3Np# zvCZqY%o258CI=SGb+A3yJe~JH^i{uU`#U#fvSC~rWTq+K`E%J@ zasU07&pB6A4w3b?d?q}2=0rA#SA7D`X+zg@&zm^iA*HVi z009#PUH<%lk4z~p^l0S{lCJk1Uxi=F4e_DwlfHA`X`rv(|JqWKAA5nH+u4Da+E_p+ zVmH@lg^n4ixs~*@gm_dgQ&eDmE1mnw5wBz9Yg?QdZwF|an67Xd*x!He)Gc8&2!urh z4_uXzbYz-aX)X1>&iUjGp;P1u8&7TID0bTH-jCL&Xk8b&;;6p2op_=y^m@Nq*0{#o!!A;wNAFG@0%Z9rHo zcJs?Th>Ny6+hI`+1XoU*ED$Yf@9f91m9Y=#N(HJP^Y@ZEYR6I?oM{>&Wq4|v0IB(p zqX#Z<_3X(&{H+{3Tr|sFy}~=bv+l=P;|sBz$wk-n^R`G3p0(p>p=5ahpaD7>r|>pm zv;V`_IR@tvZreIuv2EM7ZQHhO+qUgw#kOs%*ekY^n|=1#x9&c;Ro&I~{rG-#_3ZB1 z?|9}IFdbP}^DneP*T-JaoYHt~r@EfvnPE5EKUwIxjPbsr$% zfWW83pgWST7*B(o=kmo)74$8UU)v0{@4DI+ci&%=#90}!CZz|rnH+Mz=HN~97G3~@ z;v5(9_2%eca(9iu@J@aqaMS6*$TMw!S>H(b z4(*B!|H|8&EuB%mITr~O?vVEf%(Gr)6E=>H~1VR z&1YOXluJSG1!?TnT)_*YmJ*o_Q@om~(GdrhI{$Fsx_zrkupc#y{DK1WOUR>tk>ZE) ziOLoBkhZZ?0Uf}cm>GsA>Rd6V8@JF)J*EQlQ<=JD@m<)hyElXR0`pTku*3MU`HJn| zIf7$)RlK^pW-$87U;431;Ye4Ie+l~_B3*bH1>*yKzn23cH0u(i5pXV! z4K?{3oF7ZavmmtTq((wtml)m6i)8X6ot_mrE-QJCW}Yn!(3~aUHYG=^fA<^~`e3yc z-NWTb{gR;DOUcK#zPbN^D*e=2eR^_!(!RKkiwMW@@yYtEoOp4XjOGgzi`;=8 zi3`Ccw1%L*y(FDj=C7Ro-V?q)-%p?Ob2ZElu`eZ99n14-ZkEV#y5C+{Pq87Gu3&>g zFy~Wk7^6v*)4pF3@F@rE__k3ikx(hzN3@e*^0=KNA6|jC^B5nf(XaoQaZN?Xi}Rn3 z$8&m*KmWvPaUQ(V<#J+S&zO|8P-#!f%7G+n_%sXp9=J%Z4&9OkWXeuZN}ssgQ#Tcj z8p6ErJQJWZ+fXLCco=RN8D{W%+*kko*2-LEb))xcHwNl~Xmir>kmAxW?eW50Osw3# zki8Fl$#fvw*7rqd?%E?}ZX4`c5-R&w!Y0#EBbelVXSng+kUfeUiqofPehl}$ormli zg%r)}?%=?_pHb9`Cq9Z|B`L8b>(!+8HSX?`5+5mm81AFXfnAt1*R3F z%b2RPIacKAddx%JfQ8l{3U|vK@W7KB$CdLqn@wP^?azRks@x8z59#$Q*7q!KilY-P zHUbs(IFYRGG1{~@RF;Lqyho$~7^hNC`NL3kn^Td%A7dRgr_&`2k=t+}D-o9&C!y^? z6MsQ=tc3g0xkK(O%DzR9nbNB(r@L;1zQrs8mzx&4dz}?3KNYozOW5;=w18U6$G4U2 z#2^qRLT*Mo4bV1Oeo1PKQ2WQS2Y-hv&S|C7`xh6=Pj7MNLC5K-zokZ67S)C;(F0Dd zloDK2_o1$Fmza>EMj3X9je7e%Q`$39Dk~GoOj89-6q9|_WJlSl!!+*{R=tGp z8u|MuSwm^t7K^nUe+^0G3dkGZr3@(X+TL5eah)K^Tn zXEtHmR9UIaEYgD5Nhh(s*fcG_lh-mfy5iUF3xxpRZ0q3nZ=1qAtUa?(LnT9I&~uxX z`pV?+=|-Gl(kz?w!zIieXT}o}7@`QO>;u$Z!QB${a08_bW0_o@&9cjJUXzVyNGCm8 zm=W+$H!;_Kzp6WQqxUI;JlPY&`V}9C$8HZ^m?NvI*JT@~BM=()T()Ii#+*$y@lTZBkmMMda>7s#O(1YZR+zTG@&}!EXFG{ zEWPSDI5bFi;NT>Yj*FjH((=oe%t%xYmE~AGaOc4#9K_XsVpl<4SP@E!TgC0qpe1oi zNpxU2b0(lEMcoibQ-G^cxO?ySVW26HoBNa;n0}CWL*{k)oBu1>F18X061$SP{Gu67 z-v-Fa=Fl^u3lnGY^o5v)Bux}bNZ~ z5pL+7F_Esoun8^5>z8NFoIdb$sNS&xT8_|`GTe8zSXQzs4r^g0kZjg(b0bJvz`g<70u9Z3fQILX1Lj@;@+##bP|FAOl)U^9U>0rx zGi)M1(Hce)LAvQO-pW!MN$;#ZMX?VE(22lTlJrk#pB0FJNqVwC+*%${Gt#r_tH9I_ z;+#)#8cWAl?d@R+O+}@1A^hAR1s3UcW{G+>;X4utD2d9X(jF555}!TVN-hByV6t+A zdFR^aE@GNNgSxxixS2p=on4(+*+f<8xrwAObC)D5)4!z7)}mTpb7&ofF3u&9&wPS< zB62WHLGMhmrmOAgmJ+|c>qEWTD#jd~lHNgT0?t-p{T=~#EMcB| z=AoDKOL+qXCfk~F)-Rv**V}}gWFl>liXOl7Uec_8v)(S#av99PX1sQIVZ9eNLkhq$ zt|qu0b?GW_uo}TbU8!jYn8iJeIP)r@;!Ze_7mj{AUV$GEz6bDSDO=D!&C9!M@*S2! zfGyA|EPlXGMjkH6x7OMF?gKL7{GvGfED=Jte^p=91FpCu)#{whAMw`vSLa`K#atdN zThnL+7!ZNmP{rc=Z>%$meH;Qi1=m1E3Lq2D_O1-X5C;!I0L>zur@tPAC9*7Jeh)`;eec}1`nkRP(%iv-`N zZ@ip-g|7l6Hz%j%gcAM}6-nrC8oA$BkOTz^?dakvX?`^=ZkYh%vUE z9+&)K1UTK=ahYiaNn&G5nHUY5niLGus@p5E2@RwZufRvF{@$hW{;{3QhjvEHMvduO z#Wf-@oYU4ht?#uP{N3utVzV49mEc9>*TV_W2TVC`6+oI)zAjy$KJrr=*q##&kobiQ z1vNbya&OVjK`2pdRrM?LuK6BgrLN7H_3m z!qpNKg~87XgCwb#I=Q&0rI*l$wM!qTkXrx1ko5q-f;=R2fImRMwt5Qs{P*p^z@9ex z`2#v(qE&F%MXlHpdO#QEZyZftn4f05ab^f2vjxuFaat2}jke{j?5GrF=WYBR?gS(^ z9SBiNi}anzBDBRc+QqizTTQuJrzm^bNA~A{j%ugXP7McZqJ}65l10({wk++$=e8O{ zxWjG!Qp#5OmI#XRQQM?n6?1ztl6^D40hDJr?4$Wc&O_{*OfMfxe)V0=e{|N?J#fgE>j9jAajze$iN!*yeF%jJU#G1c@@rm zolGW!j?W6Q8pP=lkctNFdfgUMg92wlM4E$aks1??M$~WQfzzzXtS)wKrr2sJeCN4X zY(X^H_c^PzfcO8Bq(Q*p4c_v@F$Y8cHLrH$`pJ2}=#*8%JYdqsqnGqEdBQMpl!Ot04tUGSXTQdsX&GDtjbWD=prcCT9(+ z&UM%lW%Q3yrl1yiYs;LxzIy>2G}EPY6|sBhL&X&RAQrSAV4Tlh2nITR?{6xO9ujGu zr*)^E`>o!c=gT*_@6S&>0POxcXYNQd&HMw6<|#{eSute2C3{&h?Ah|cw56-AP^f8l zT^kvZY$YiH8j)sk7_=;gx)vx-PW`hbSBXJGCTkpt;ap(}G2GY=2bbjABU5)ty%G#x zAi07{Bjhv}>OD#5zh#$0w;-vvC@^}F! z#X$@)zIs1L^E;2xDAwEjaXhTBw2<{&JkF*`;c3<1U@A4MaLPe{M5DGGkL}#{cHL%* zYMG+-Fm0#qzPL#V)TvQVI|?_M>=zVJr9>(6ib*#z8q@mYKXDP`k&A4A};xMK0h=yrMp~JW{L?mE~ph&1Y1a#4%SO)@{ zK2juwynUOC)U*hVlJU17%llUxAJFuKZh3K0gU`aP)pc~bE~mM!i1mi!~LTf>1Wp< zuG+ahp^gH8g8-M$u{HUWh0m^9Rg@cQ{&DAO{PTMudV6c?ka7+AO& z746QylZ&Oj`1aqfu?l&zGtJnpEQOt;OAFq19MXTcI~`ZcoZmyMrIKDFRIDi`FH)w; z8+*8tdevMDv*VtQi|e}CnB_JWs>fhLOH-+Os2Lh!&)Oh2utl{*AwR)QVLS49iTp{6 z;|172Jl!Ml17unF+pd+Ff@jIE-{Oxv)5|pOm@CkHW?{l}b@1>Pe!l}VccX#xp@xgJ zyE<&ep$=*vT=}7vtvif0B?9xw_3Gej7mN*dOHdQPtW5kA5_zGD zpA4tV2*0E^OUimSsV#?Tg#oiQ>%4D@1F5@AHwT8Kgen$bSMHD3sXCkq8^(uo7CWk`mT zuslYq`6Yz;L%wJh$3l1%SZv#QnG3=NZ=BK4yzk#HAPbqXa92;3K5?0kn4TQ`%E%X} z&>Lbt!!QclYKd6+J7Nl@xv!uD%)*bY-;p`y^ZCC<%LEHUi$l5biu!sT3TGGSTPA21 zT8@B&a0lJHVn1I$I3I1I{W9fJAYc+8 zVj8>HvD}&O`TqU2AAb={?eT;0hyL(R{|h23=4fDSZKC32;wWxsVj`P z3J3{M$PwdH!ro*Cn!D&=jnFR>BNGR<<|I8CI@+@658Dy(lhqbhXfPTVecY@L8%`3Q z1Fux2w?2C3th60jI~%OC9BtpNF$QPqcG+Pz96qZJ71_`0o0w_q7|h&O>`6U+^BA&5 zXd5Zp1Xkw~>M%RixTm&OqpNl8Q+ue=92Op_>T~_9UON?ZM2c0aGm=^A4ejrXj3dV9 zhh_bCt-b9`uOX#cFLj!vhZ#lS8Tc47OH>*)y#{O9?AT~KR9LntM|#l#Dlm^8{nZdk zjMl#>ZM%#^nK2TPzLcKxqx24P7R1FPlBy7LSBrRvx>fE$9AJ;7{PQm~^LBX^k#6Zq zw*Z(zJC|`!6_)EFR}8|n8&&Rbj8y028~P~sFXBFRt+tmqH-S3<%N;C&WGH!f3{7cm zy_fCAb9@HqaXa1Y5vFbxWf%#zg6SI$C+Uz5=CTO}e|2fjWkZ;Dx|84Ow~bkI=LW+U zuq;KSv9VMboRvs9)}2PAO|b(JCEC_A0wq{uEj|3x@}*=bOd zwr{TgeCGG>HT<@Zeq8y}vTpwDg#UBvD)BEs@1KP$^3$sh&_joQPn{hjBXmLPJ{tC) z*HS`*2+VtJO{|e$mM^|qv1R*8i(m1`%)}g=SU#T#0KlTM2RSvYUc1fP+va|4;5}Bfz98UvDCpq7}+SMV&;nX zQw~N6qOX{P55{#LQkrZk(e5YGzr|(B;Q;ju;2a`q+S9bsEH@i1{_Y0;hWYn1-79jl z5c&bytD*k)GqrVcHn6t-7kinadiD>B{Tl`ZY@`g|b~pvHh5!gKP4({rp?D0aFd_cN zhHRo4dd5^S6ViN(>(28qZT6E>??aRhc($kP`>@<+lIKS5HdhjVU;>f7<4))E*5|g{ z&d1}D|vpuV^eRj5j|xx9nwaCxXFG?Qbjn~_WSy=N}P0W>MP zG-F%70lX5Xr$a)2i6?i|iMyM|;Jtf*hO?=Jxj12oz&>P=1#h~lf%#fc73M2_(SUM- zf&qnjS80|_Y0lDgl&I?*eMumUklLe_=Td!9G@eR*tcPOgIShJipp3{A10u(4eT~DY zHezEj8V+7m!knn7)W!-5QI3=IvC^as5+TW1@Ern@yX| z7Nn~xVx&fGSr+L%4iohtS3w^{-H1A_5=r&x8}R!YZvp<2T^YFvj8G_vm}5q;^UOJf ztl=X3iL;;^^a#`t{Ae-%5Oq{?M#s6Npj+L(n-*LMI-yMR{)qki!~{5z{&`-iL}lgW zxo+tnvICK=lImjV$Z|O_cYj_PlEYCzu-XBz&XC-JVxUh9;6*z4fuBG+H{voCC;`~GYV|hj%j_&I zDZCj>Q_0RCwFauYoVMiUSB+*Mx`tg)bWmM^SwMA+?lBg12QUF_x2b)b?qb88K-YUd z0dO}3k#QirBV<5%jL$#wlf!60dizu;tsp(7XLdI=eQs?P`tOZYMjVq&jE)qK*6B^$ zBe>VvH5TO>s>izhwJJ$<`a8fakTL!yM^Zfr2hV9`f}}VVUXK39p@G|xYRz{fTI+Yq z20d=)iwjuG9RB$%$^&8#(c0_j0t_C~^|n+c`Apu|x7~;#cS-s=X1|C*YxX3ailhg_|0`g!E&GZJEr?bh#Tpb8siR=JxWKc{#w7g zWznLwi;zLFmM1g8V5-P#RsM@iX>TK$xsWuujcsVR^7TQ@!+vCD<>Bk9tdCo7Mzgq5 zv8d>dK9x8C@Qoh01u@3h0X_`SZluTb@5o;{4{{eF!-4405x8X7hewZWpz z2qEi4UTiXTvsa(0X7kQH{3VMF>W|6;6iTrrYD2fMggFA&-CBEfSqPlQDxqsa>{e2M z(R5PJ7uOooFc|9GU0ELA%m4&4Ja#cQpNw8i8ACAoK6?-px+oBl_yKmenZut#Xumjz zk8p^OV2KY&?5MUwGrBOo?ki`Sxo#?-Q4gw*Sh0k`@ zFTaYK2;}%Zk-68`#5DXU$2#=%YL#S&MTN8bF+!J2VT6x^XBci6O)Q#JfW{YMz) zOBM>t2rSj)n#0a3cjvu}r|k3od6W(SN}V-cL?bi*Iz-8uOcCcsX0L>ZXjLqk zZu2uHq5B|Kt>e+=pPKu=1P@1r9WLgYFq_TNV1p9pu0erHGd!+bBp!qGi+~4A(RsYN@CyXNrC&hxGmW)u5m35OmWwX`I+0yByglO`}HC4nGE^_HUs^&A(uaM zKPj^=qI{&ayOq#z=p&pnx@@k&I1JI>cttJcu@Ihljt?6p^6{|ds`0MoQwp+I{3l6` zB<9S((RpLG^>=Kic`1LnhpW2=Gu!x`m~=y;A`Qk!-w`IN;S8S930#vBVMv2vCKi}u z6<-VPrU0AnE&vzwV(CFC0gnZYcpa-l5T0ZS$P6(?9AM;`Aj~XDvt;Jua=jIgF=Fm? zdp=M$>`phx%+Gu};;-&7T|B1AcC#L4@mW5SV_^1BRbo6;2PWe$r+npRV`yc;T1mo& z+~_?7rA+(Um&o@Tddl zL_hxvWk~a)yY}%j`Y+200D%9$bWHy&;(yj{jpi?Rtz{J66ANw)UyPOm;t6FzY3$hx zcn)Ir79nhFvNa7^a{SHN7XH*|Vlsx`CddPnA&Qvh8aNhEA;mPVv;Ah=k<*u!Zq^7 z<=xs*iQTQOMMcg|(NA_auh@x`3#_LFt=)}%SQppP{E>mu_LgquAWvh<>L7tf9+~rO znwUDS52u)OtY<~!d$;m9+87aO+&`#2ICl@Y>&F{jI=H(K+@3M1$rr=*H^dye#~TyD z!){#Pyfn+|ugUu}G;a~!&&0aqQ59U@UT3|_JuBlYUpT$2+11;}JBJ`{+lQN9T@QFY z5+`t;6(TS0F?OlBTE!@7D`8#URDNqx2t6`GZ{ZgXeS@v%-eJzZOHz18aS|svxII$a zZeFjrJ*$IwX$f-Rzr_G>xbu@euGl)B7pC&S+CmDJBg$BoV~jxSO#>y z33`bupN#LDoW0feZe0%q8un0rYN|eRAnwDHQ6e_)xBTbtoZtTA=Fvk){q}9Os~6mQ zKB80VI_&6iSq`LnK7*kfHZoeX6?WE}8yjuDn=2#JG$+;-TOA1%^=DnXx%w{b=w}tS zQbU3XxtOI8E(!%`64r2`zog;5<0b4i)xBmGP^jiDZ2%HNSxIf3@wKs~uk4%3Mxz;~ zts_S~E4>W+YwI<-*-$U8*^HKDEa8oLbmqGg?3vewnaNg%Mm)W=)lcC_J+1ov^u*N3 zXJ?!BrH-+wGYziJq2Y#vyry6Z>NPgkEk+Ke`^DvNRdb>Q2Nlr#v%O@<5hbflI6EKE z9dWc0-ORk^T}jP!nkJ1imyjdVX@GrjOs%cpgA8-c&FH&$(4od#x6Y&=LiJZPINVyW z0snY$8JW@>tc2}DlrD3StQmA0Twck~@>8dSix9CyQOALcREdxoM$Sw*l!}bXKq9&r zysMWR@%OY24@e`?+#xV2bk{T^C_xSo8v2ZI=lBI*l{RciPwuE>L5@uhz@{!l)rtVlWC>)6(G)1~n=Q|S!{E9~6*fdpa*n z!()-8EpTdj=zr_Lswi;#{TxbtH$8*G=UM`I+icz7sr_SdnHXrv=?iEOF1UL+*6O;% zPw>t^kbW9X@oEXx<97%lBm-9?O_7L!DeD)Me#rwE54t~UBu9VZ zl_I1tBB~>jm@bw0Aljz8! zXBB6ATG6iByKIxs!qr%pz%wgqbg(l{65DP4#v(vqhhL{0b#0C8mq`bnqZ1OwFV z7mlZZJFMACm>h9v^2J9+^_zc1=JjL#qM5ZHaThH&n zXPTsR8(+)cj&>Un{6v*z?@VTLr{TmZ@-fY%*o2G}*G}#!bmqpoo*Ay@U!JI^Q@7gj;Kg-HIrLj4}#ec4~D2~X6vo;ghep-@&yOivYP zC19L0D`jjKy1Yi-SGPAn94(768Tcf$urAf{)1)9W58P`6MA{YG%O?|07!g9(b`8PXG1B1Sh0?HQmeJtP0M$O$hI z{5G`&9XzYhh|y@qsF1GnHN|~^ru~HVf#)lOTSrv=S@DyR$UKQk zjdEPFDz{uHM&UM;=mG!xKvp;xAGHOBo~>_=WFTmh$chpC7c`~7?36h)7$fF~Ii}8q zF|YXxH-Z?d+Q+27Rs3X9S&K3N+)OBxMHn1u(vlrUC6ckBY@@jl+mgr#KQUKo#VeFm zFwNYgv0<%~Wn}KeLeD9e1$S>jhOq&(e*I@L<=I5b(?G(zpqI*WBqf|Zge0&aoDUsC zngMRA_Kt0>La+Erl=Uv_J^p(z=!?XHpenzn$%EA`JIq#yYF?JLDMYiPfM(&Csr#f{ zdd+LJL1by?xz|D8+(fgzRs~(N1k9DSyK@LJygwaYX8dZl0W!I&c^K?7)z{2is;OkE zd$VK-(uH#AUaZrp=1z;O*n=b?QJkxu`Xsw&7yrX0?(CX=I-C#T;yi8a<{E~?vr3W> zQrpPqOW2M+AnZ&p{hqmHZU-;Q(7?- zP8L|Q0RM~sB0w1w53f&Kd*y}ofx@c z5Y6B8qGel+uT1JMot$nT1!Tim6{>oZzJXdyA+4euOLME?5Fd_85Uk%#E*ln%y{u8Q z$|?|R@Hpb~yTVK-Yr_S#%NUy7EBfYGAg>b({J|5b+j-PBpPy$Ns`PaJin4JdRfOaS zE|<HjH%NuJgsd2wOlv>~y=np%=2)$M9LS|>P)zJ+Fei5vYo_N~B0XCn+GM76 z)Xz3tg*FRVFgIl9zpESgdpWAavvVViGlU8|UFY{{gVJskg*I!ZjWyk~OW-Td4(mZ6 zB&SQreAAMqwp}rjy`HsG({l2&q5Y52<@AULVAu~rWI$UbFuZs>Sc*x+XI<+ez%$U)|a^unjpiW0l0 zj1!K0(b6$8LOjzRqQ~K&dfbMIE=TF}XFAi)$+h}5SD3lo z%%Qd>p9se=VtQG{kQ;N`sI)G^u|DN#7{aoEd zkksYP%_X$Rq08);-s6o>CGJ<}v`qs%eYf+J%DQ^2k68C%nvikRsN?$ap--f+vCS`K z#&~)f7!N^;sdUXu54gl3L=LN>FB^tuK=y2e#|hWiWUls__n@L|>xH{%8lIJTd5`w? zSwZbnS;W~DawT4OwSJVdAylbY+u5S+ZH{4hAi2&}Iv~W(UvHg(1GTZRPz`@{SOqzy z(8g&Dz=$PfRV=6FgxN~zo+G8OoPI&d-thcGVR*_^(R8COTM@bq?fDwY{}WhsQS1AK zF6R1t8!RdFmfocpJ6?9Yv~;WYi~XPgs(|>{5})j!AR!voO7y9&cMPo#80A(`za@t>cx<0;qxM@S*m(jYP)dMXr*?q0E`oL;12}VAep179uEr8c<=D zr5?A*C{eJ`z9Ee;E$8)MECqatHkbHH z&Y+ho0B$31MIB-xm&;xyaFCtg<{m~M-QDbY)fQ>Q*Xibb~8ytxZQ?QMf9!%cV zU0_X1@b4d+Pg#R!`OJ~DOrQz3@cpiGy~XSKjZQQ|^4J1puvwKeScrH8o{bscBsowomu z^f12kTvje`yEI3eEXDHJ6L+O{Jv$HVj%IKb|J{IvD*l6IG8WUgDJ*UGz z3!C%>?=dlfSJ>4U88)V+`U-!9r^@AxJBx8R;)J4Fn@`~k>8>v0M9xp90OJElWP&R5 zM#v*vtT}*Gm1^)Bv!s72T3PB0yVIjJW)H7a)ilkAvoaH?)jjb`MP>2z{%Y?}83 zUIwBKn`-MSg)=?R)1Q0z3b>dHE^)D8LFs}6ASG1|daDly_^lOSy&zIIhm*HXm1?VS=_iacG);_I9c zUQH1>i#*?oPIwBMJkzi_*>HoUe}_4o>2(SHWzqQ=;TyhAHS;Enr7!#8;sdlty&(>d zl%5cjri8`2X^Ds`jnw7>A`X|bl=U8n+3LKLy(1dAu8`g@9=5iw$R0qk)w8Vh_Dt^U zIglK}sn^)W7aB(Q>HvrX=rxB z+*L)3DiqpQ_%~|m=44LcD4-bxO3OO*LPjsh%p(k?&jvLp0py57oMH|*IMa(<|{m1(0S|x)?R-mqJ=I;_YUZA>J z62v*eSK;5w!h8J+6Z2~oyGdZ68waWfy09?4fU&m7%u~zi?YPHPgK6LDwphgaYu%0j zurtw)AYOpYKgHBrkX189mlJ`q)w-f|6>IER{5Lk97%P~a-JyCRFjejW@L>n4vt6#hq;!|m;hNE||LK3nw1{bJOy+eBJjK=QqNjI;Q6;Rp5 z&035pZDUZ#%Oa;&_7x0T<7!RW`#YBOj}F380Bq?MjjEhrvlCATPdkCTTl+2efTX$k zH&0zR1n^`C3ef~^sXzJK-)52(T}uTG%OF8yDhT76L~|^+hZ2hiSM*QA9*D5odI1>& z9kV9jC~twA5MwyOx(lsGD_ggYmztXPD`2=_V|ks_FOx!_J8!zM zTzh^cc+=VNZ&(OdN=y4Juw)@8-85lwf_#VMN!Ed(eQiRiLB2^2e`4dp286h@v@`O%_b)Y~A; zv}r6U?zs&@uD_+(_4bwoy7*uozNvp?bXFoB8?l8yG0qsm1JYzIvB_OH4_2G*IIOwT zVl%HX1562vLVcxM_RG*~w_`FbIc!(T=3>r528#%mwwMK}uEhJ()3MEby zQQjzqjWkwfI~;Fuj(Lj=Ug0y`>~C7`w&wzjK(rPw+Hpd~EvQ-ufQOiB4OMpyUKJhw zqEt~jle9d7S~LI~$6Z->J~QJ{Vdn3!c}g9}*KG^Kzr^(7VI5Gk(mHLL{itj_hG?&K4Ws0+T4gLfi3eu$N=`s36geNC?c zm!~}vG6lx9Uf^5M;bWntF<-{p^bruy~f?sk9 zcETAPQZLoJ8JzMMg<-=ju4keY@SY%Wo?u9Gx=j&dfa6LIAB|IrbORLV1-H==Z1zCM zeZcOYpm5>U2fU7V*h;%n`8 zN95QhfD994={1*<2vKLCNF)feKOGk`R#K~G=;rfq}|)s20&MCa65 zUM?xF5!&e0lF%|U!#rD@I{~OsS_?=;s_MQ_b_s=PuWdC)q|UQ&ea)DMRh5>fpQjXe z%9#*x=7{iRCtBKT#H>#v%>77|{4_slZ)XCY{s3j_r{tdpvb#|r|sbS^dU1x70$eJMU!h{Y7Kd{dl}9&vxQl6Jt1a` zHQZrWyY0?!vqf@u-fxU_@+}u(%Wm>0I#KP48tiAPYY!TdW(o|KtVI|EUB9V`CBBNaBLVih7+yMVF|GSoIQD0Jfb{ z!OXq;(>Z?O`1gap(L~bUcp>Lc@Jl-})^=6P%<~~9ywY=$iu8pJ0m*hOPzr~q`23eX zgbs;VOxxENe0UMVeN*>uCn9Gk!4siN-e>x)pIKAbQz!G)TcqIJ0`JBBaX>1-4_XO_-HCS^vr2vjv#7KltDZdyQ{tlWh4$Gm zB>|O1cBDC)yG(sbnc*@w6e%e}r*|IhpXckx&;sQCwGdKH+3oSG-2)Bf#x`@<4ETAr z0My%7RFh6ZLiZ_;X6Mu1YmXx7C$lSZ^}1h;j`EZd6@%JNUe=btBE z%s=Xmo1Ps?8G`}9+6>iaB8bgjUdXT?=trMu|4yLX^m0Dg{m7rpKNJey|EwHI+nN1e zL^>qN%5Fg)dGs4DO~uwIdXImN)QJ*Jhpj7$fq_^`{3fwpztL@WBB}OwQ#Epo-mqMO zsM$UgpFiG&d#)lzEQ{3Q;)&zTw;SzGOah-Dpm{!q7<8*)Ti_;xvV2TYXa}=faXZy? z3y?~GY@kl)>G&EvEijk9y1S`*=zBJSB1iet>0;x1Ai)*`^{pj0JMs)KAM=@UyOGtO z3y0BouW$N&TnwU6!%zS%nIrnANvZF&vB1~P5_d`x-giHuG zPJ;>XkVoghm#kZXRf>qxxEix;2;D1CC~NrbO6NBX!`&_$iXwP~P*c($EVV|669kDO zKoTLZNF4Cskh!Jz5ga9uZ`3o%7Pv`d^;a=cXI|>y;zC3rYPFLQkF*nv(r>SQvD*## z(Vo%^9g`%XwS0t#94zPq;mYGLKu4LU3;txF26?V~A0xZbU4Lmy`)>SoQX^m7fd^*E z+%{R4eN!rIk~K)M&UEzxp9dbY;_I^c} zOc{wlIrN_P(PPqi51k_$>Lt|X6A^|CGYgKAmoI#Li?;Wq%q~q*L7ehZkUrMxW67Jl zhsb~+U?33QS>eqyN{(odAkbopo=Q$Az?L+NZW>j;#~@wCDX?=L5SI|OxI~7!Pli;e zELMFcZtJY3!|=Gr2L4>z8yQ-{To>(f80*#;6`4IAiqUw`=Pg$%C?#1 z_g@hIGerILSU>=P>z{gM|DS91A4cT@PEIB^hSop!uhMo#2G;+tQSpDO_6nOnPWSLU zS;a9m^DFMXR4?*X=}d7l;nXuHk&0|m`NQn%d?8|Ab3A9l9Jh5s120ibWBdB z$5YwsK3;wvp!Kn@)Qae{ef`0#NwlRpQ}k^r>yos_Ne1;xyKLO?4)t_G4eK~wkUS2A&@_;)K0-03XGBzU+5f+uMDxC z(s8!8!RvdC#@`~fx$r)TKdLD6fWEVdEYtV#{ncT-ZMX~eI#UeQ-+H(Z43vVn%Yj9X zLdu9>o%wnWdvzA-#d6Z~vzj-}V3FQ5;axDIZ;i(95IIU=GQ4WuU{tl-{gk!5{l4_d zvvb&uE{%!iFwpymz{wh?bKr1*qzeZb5f6e6m_ozRF&zux2mlK=v_(_s^R6b5lu?_W4W3#<$zeG~Pd)^!4tzhs}-Sx$FJP>)ZGF(hVTH|C3(U zs0PO&*h_ zNA-&qZpTP$$LtIgfiCn07}XDbK#HIXdmv8zdz4TY;ifNIH-0jy(gMSByG2EF~Th#eb_TueZC` zE?3I>UTMpKQ})=C;6p!?G)M6w^u*A57bD?2X`m3X^6;&4%i_m(uGJ3Z5h`nwxM<)H z$I5m?wN>O~8`BGnZ=y^p6;0+%_0K}Dcg|K;+fEi|qoBqvHj(M&aHGqNF48~XqhtU? z^ogwBzRlOfpAJ+Rw7IED8lRbTdBdyEK$gPUpUG}j-M42xDj_&qEAQEtbs>D#dRd7Y z<&TpSZ(quQDHiCFn&0xsrz~4`4tz!CdL8m~HxZM_agu@IrBpyeL1Ft}V$HX_ZqDPm z-f89)pjuEzGdq-PRu`b1m+qBGY{zr_>{6Ss>F|xHZlJj9dt5HD$u`1*WZe)qEIuDSR)%z+|n zatVlhQ?$w#XRS7xUrFE;Y8vMGhQS5*T{ZnY=q1P?w5g$OKJ#M&e??tAmPWHMj3xhS ziGxapy?kn@$~2%ZY;M8Bc@%$pkl%Rvj!?o%agBvpQ-Q61n9kznC4ttrRNQ4%GFR5u zyv%Yo9~yxQJWJSfj z?#HY$y=O~F|2pZs22pu|_&Ajd+D(Mt!nPUG{|1nlvP`=R#kKH zO*s$r_%ss5h1YO7k0bHJ2CXN)Yd6CHn~W!R=SqkWe=&nAZu(Q1G!xgcUilM@YVei@2@a`8he z9@pM`)VB*=e7-MWgLlXlc)t;fF&-AwM{E-EX}pViFn0I0CNw2bNEnN2dj!^4(^zS3 zobUm1uQnpqk_4q{pl*n06=TfK_C>UgurKFjRXsK_LEn};=79`TB12tv6KzwSu*-C8 z;=~ohDLZylHQ|Mpx-?yql>|e=vI1Z!epyUpAcDCp4T|*RV&X`Q$0ogNwy6mFALo^@ z9=&(9txO8V@E!@6^(W0{*~CT>+-MA~vnJULBxCTUW>X5>r7*eXYUT0B6+w@lzw%n> z_VjJ<2qf|(d6jYq2(x$(ZDf!yVkfnbvNmb5c|hhZ^2TV_LBz`9w!e_V*W_(MiA7|= z&EeIIkw*+$Xd!)j8<@_<}A5;~A_>3JT*kX^@}cDoLd>Qj<`Se^wdUa(j0dp+Tl8EptwBm{9OGsdFEq zM`!pjf(Lm(`$e3FLOjqA5LnN5o!}z{ zNf}rJuZh@yUtq&ErjHeGzX4(!luV!jB&;FAP|!R_QHYw#^Z1LwTePAKJ6X&IDNO#; z)#I@Xnnzyij~C@UH~X51JCgQeF0&hTXnuoElz#m{heZRexWc0k4<>0+ClX7%0 zEBqCCld1tD9Zwkr4{?Nor19#E5-YKfB8d?qgR82-Ow2^AuNevly2*tHA|sK!ybYkX zm-sLQH72P&{vEAW6+z~O5d0qd=xW~rua~5a?ymYFSD@8&gV)E5@RNNBAj^C99+Z5Z zR@Pq55mbCQbz+Mn$d_CMW<-+?TU960agEk1J<>d>0K=pF19yN))a~4>m^G&tc*xR+yMD*S=yip-q=H zIlredHpsJV8H(32@Zxc@bX6a21dUV95Th--8pE6C&3F>pk=yv$yd6@Haw;$v4+Fcb zRwn{Qo@0`7aPa2LQOP}j9v>sjOo5Kqvn|`FLizX zB+@-u4Lw|jsvz{p^>n8Vo8H2peIqJJnMN}A)q6%$Tmig7eu^}K2 zrh$X?T|ZMsoh{6pdw1G$_T<`Ds-G=jc;qcGdK4{?dN2-XxjDNbb(7pk|3JUVCU4y; z)?LXR>f+AAu)JEiti_Zy#z5{RgsC}R(@jl%9YZ>zu~hKQ*AxbvhC378-I@{~#%Y`Z zy=a=9YpewPIC+gkEUUwtUL7|RU7=!^Aa}Mk^6uxOgRGA#JXjWLsjFUnix|Mau{hDT z7mn*z1m5g`vP(#tjT0Zy4eAY(br&!RiiXE=ZI!{sE1#^#%x^Z7t1U)b<;%Y}Q9=5v z;wpDCEZ@OE36TWT=|gxigT@VaW9BvHS05;_P(#s z8zI4XFQys}q)<`tkX$WnSarn{3e!s}4(J!=Yf>+Y>cP3f;vr63f2{|S^`_pWc)^5_!R z*(x-fuBxL51@xe!lnDBKi}Br$c$BMZ3%f2Sa6kLabiBS{pq*yj;q|k(86x`PiC{p6 z_bxCW{>Q2BA8~Ggz&0jkrcU+-$ANBsOop*ms>34K9lNYil@}jC;?cYP(m^P}nR6FV zk(M%48Z&%2Rx$A&FhOEirEhY0(dn;-k(qkTU)sFQ`+-ih+s@A8g?r8Pw+}2;35WYf zi}VO`jS`p(tc)$X$a>-#WXoW!phhatC*$}|rk>|wUU71eUJG^$c6_jwX?iSHM@6__ zvV|6%U*$sSXJu9SX?2%M^kK|}a2QJ8AhF{fuXrHZxXsI~O zGKX45!K7p*MCPEQ=gp?eu&#AW*pR{lhQR##P_*{c_DjMGL|3T3-bSJ(o$|M{ytU}> zAV>wq*uE*qFo9KvnA^@juy{x<-u*#2NvkV={Ly}ysKYB-k`K3@K#^S1Bb$8Y#0L0# z`6IkSG&|Z$ODy|VLS+y5pFJx&8tvPmMd8c9FhCyiU8~k6FwkakUd^(_ml8`rnl>JS zZV){9G*)xBqPz^LDqRwyS6w86#D^~xP4($150M)SOZRe9sn=>V#aG0Iy(_^YcPpIz8QYM-#s+n% z@Jd?xQq?Xk6=<3xSY7XYP$$yd&Spu{A#uafiIfy8gRC`o0nk{ezEDjb=q_qRAlR1d zFq^*9Gn)yTG4b}R{!+3hWQ+u3GT~8nwl2S1lpw`s0X_qpxv)g+JIkVKl${sYf_nV~B>Em>M;RlqGb5WVil(89 zs=ld@|#;dq1*vQGz=7--Br-|l) zZ%Xh@v8>B7P?~}?Cg$q9_={59l%m~O&*a6TKsCMAzG&vD>k2WDzJ6!tc!V)+oxF;h zJH;apM=wO?r_+*#;ulohuP=E>^zon}a$NnlcQ{1$SO*i=jnGVcQa^>QOILc)e6;eNTI>os=eaJ{*^DE+~jc zS}TYeOykDmJ=6O%>m`i*>&pO_S;qMySJIyP=}4E&J%#1zju$RpVAkZbEl+p%?ZP^C z*$$2b4t%a(e+%>a>d_f_<JjxI#J1x;=hPd1zFPx=6T$;;X1TD*2(edZ3f46zaAoW>L53vS_J*N8TMB|n+;LD| zC=GkQPpyDY#Am4l49chDv*gojhRj_?63&&8#doW`INATAo(qY#{q}%nf@eTIXmtU< zdB<7YWfyCmBs|c)cK>1)v&M#!yNj#4d$~pVfDWQc_ke1?fw{T1Nce_b`v|Vp5ig(H zJvRD^+ps46^hLX;=e2!2e;w9y1D@!D$c@Jc&%%%IL=+xzw55&2?darw=9g~>P z9>?Kdc$r?6c$m%x2S$sdpPl>GQZ{rC9mPS63*qjCVa?OIBj!fW zm|g?>CVfGXNjOfcyqImXR_(tXS(F{FcoNzKvG5R$IgGaxC@)i(e+$ME}vPVIhd|mx2IIE+f zM?9opQHIVgBWu)^A|RzXw!^??S!x)SZOwZaJkGjc<_}2l^eSBm!eAJG9T>EC6I_sy z?bxzDIAn&K5*mX)$RQzDA?s)-no-XF(g*yl4%+GBf`##bDXJ==AQk*xmnatI;SsLp zP9XTHq5mmS=iWu~9ES>b%Q=1aMa|ya^vj$@qz9S!ih{T8_PD%Sf_QrNKwgrXw9ldm zHRVR98*{C?_XNpJn{abA!oix_mowRMu^2lV-LPi;0+?-F(>^5#OHX-fPED zCu^l7u3E%STI}c4{J2!)9SUlGP_@!d?5W^QJXOI-Ea`hFMKjR7TluLvzC-ozCPn1`Tpy z!vlv@_Z58ILX6>nDjTp-1LlFMx~-%GA`aJvG$?8*Ihn;mH37eK**rmOEwqegf-Ccx zrIX4;{c~RK>XuTXxYo5kMiWMy)!IC{*DHG@E$hx?RwP@+wuad(P1{@%tRkyJRqD)3 zMHHHZ4boqDn>-=DgR5VlhQTpfVy182Gk;A_S8A1-;U1RR>+$62>(MUx@Nox$vTjHq z%QR=j!6Gdyb5wu7y(YUktwMuW5<@jl?m4cv4BODiT5o8qVdC0MBqGr@-YBIwnpZAY znX9(_uQjP}JJ=!~Ve9#5I~rUnN|P_3D$LqZcvBnywYhjlMSFHm`;u9GPla{5QD7(7*6Tb3Svr8;(nuAd81q$*uq6HC_&~je*Ca7hP4sJp0av{M8480wF zxASi7Qv+~@2U%Nu1Ud;s-G4CTVWIPyx!sg&8ZG0Wq zG_}i3C(6_1>q3w!EH7$Kwq8uBp2F2N7}l65mk1p*9v0&+;th=_E-W)E;w}P(j⁢ zv5o9#E7!G0XmdzfsS{efPNi`1b44~SZ4Z8fuX!I}#8g+(wxzQwUT#Xb2(tbY1+EUhGKoT@KEU9Ktl>_0 z%bjDJg;#*gtJZv!-Zs`?^}v5eKmnbjqlvnSzE@_SP|LG_PJ6CYU+6zY6>92%E+ z=j@TZf-iW4(%U{lnYxQA;7Q!b;^brF8n0D>)`q5>|WDDXLrqYU_tKN2>=#@~OE7grMnNh?UOz-O~6 z6%rHy{#h9K0AT+lDC7q4{hw^|q6*Ry;;L%Q@)Ga}$60_q%D)rv(CtS$CQbpq9|y1e zRSrN4;$Jyl{m5bZw`$8TGvb}(LpY{-cQ)fcyJv7l3S52TLXVDsphtv&aPuDk1OzCA z4A^QtC(!11`IsNx_HnSy?>EKpHJWT^wmS~hc^p^zIIh@9f6U@I2 zC=Mve{j2^)mS#U$e{@Q?SO6%LDsXz@SY+=cK_QMmXBIU)j!$ajc-zLx3V60EXJ!qC zi<%2x8Q24YN+&8U@CIlN zrZkcT9yh%LrlGS9`G)KdP(@9Eo-AQz@8GEFWcb7U=a0H^ZVbLmz{+&M7W(nXJ4sN8 zJLR7eeK(K8`2-}j(T7JsO`L!+CvbueT%izanm-^A1Dn{`1Nw`9P?cq;7no+XfC`K(GO9?O^5zNIt4M+M8LM0=7Gz8UA@Z0N+lg+cX)NfazRu z5D)~HA^(u%w^cz+@2@_#S|u>GpB+j4KzQ^&Wcl9f z&hG#bCA(Yk0D&t&aJE^xME^&E-&xGHhXn%}psEIj641H+Nl-}boj;)Zt*t(4wZ5DN z@GXF$bL=&pBq-#vkTkh>7hl%K5|3 z{`Vn9b$iR-SoGENp}bn4;fR3>9sA%X2@1L3aE9yTra;Wb#_`xWwLSLdfu+PAu+o3| zGVnpzPr=ch{uuoHjtw7+_!L_2;knQ!DuDl0R`|%jr+}jFzXtrHIKc323?JO{l&;VF z*L1+}JU7%QJOg|5|Tc|D8fN zJORAg=_vsy{ak|o);@)Yh8Lkcg@$FG3k@ep36BRa^>~UmnRPziS>Z=`Jb2x*Q#`%A zU*i3&Vg?TluO@X0O;r2Jl6LKLUOVhSqg1*qOt^|8*c7 zo(298@+r$k_wQNGHv{|$tW(T8L+4_`FQ{kEW5Jgg{yf7ey4ss_(SNKfz(N9lx&a;< je(UuV8hP?p&}TPdm1I$XmG#(RzlD&B2izSj9sl%y5~4qc diff --git a/asset-transfer-events/chaincode-java/gradle/wrapper/gradle-wrapper.properties b/asset-transfer-events/chaincode-java/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index a80b22ce..00000000 --- a/asset-transfer-events/chaincode-java/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,7 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip -networkTimeout=10000 -validateDistributionUrl=true -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/asset-transfer-events/chaincode-java/gradlew b/asset-transfer-events/chaincode-java/gradlew deleted file mode 100755 index 0adc8e1a..00000000 --- a/asset-transfer-events/chaincode-java/gradlew +++ /dev/null @@ -1,249 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -# This is normally unused -# shellcheck disable=SC2034 -APP_BASE_NAME=${0##*/} -# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - if ! command -v java >/dev/null 2>&1 - then - die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/asset-transfer-events/chaincode-java/gradlew.bat b/asset-transfer-events/chaincode-java/gradlew.bat deleted file mode 100644 index 6689b85b..00000000 --- a/asset-transfer-events/chaincode-java/gradlew.bat +++ /dev/null @@ -1,92 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/asset-transfer-events/chaincode-java/settings.gradle b/asset-transfer-events/chaincode-java/settings.gradle deleted file mode 100644 index 7112a47d..00000000 --- a/asset-transfer-events/chaincode-java/settings.gradle +++ /dev/null @@ -1,5 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ - -rootProject.name = 'events' diff --git a/asset-transfer-events/chaincode-java/src/main/java/org/hyperledger/fabric/samples/events/Asset.java b/asset-transfer-events/chaincode-java/src/main/java/org/hyperledger/fabric/samples/events/Asset.java deleted file mode 100644 index f9bdc18e..00000000 --- a/asset-transfer-events/chaincode-java/src/main/java/org/hyperledger/fabric/samples/events/Asset.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ - -package org.hyperledger.fabric.samples.events; - -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; - -import static java.nio.charset.StandardCharsets.UTF_8; - -import org.hyperledger.fabric.contract.annotation.DataType; -import org.hyperledger.fabric.contract.annotation.Property; - - -import org.json.JSONObject; - -@DataType() -public final class Asset { - - @Property() - private final String assetID; - - @Property() - private String color; - - @Property() - private int size; - - @Property() - private String owner; - - @Property() - private int appraisedValue; - - public Asset(final String assetID, final String color, - final int size, final String owner, final int value) { - - this.assetID = assetID; - this.color = color; - this.size = size; - this.owner = owner; - this.appraisedValue = value; - } - - public String getAssetID() { - return assetID; - } - - public String getColor() { - return color; - } - - public int getSize() { - return size; - } - - public String getOwner() { - return owner; - } - - public int getAppraisedValue() { - return appraisedValue; - } - - public void setOwner(final String newowner) { - this.owner = newowner; - } - - public void setAppraisedValue(final int value) { - this.appraisedValue = value; - } - - public void setColor(final String c) { - this.color = c; - } - - public void setSize(final int s) { - this.size = s; - } - - // Serialize asset without private properties - public byte[] serialize() { - return serialize(null).getBytes(UTF_8); - } - - public String serialize(final String privateProps) { - Map tMap = new HashMap(); - tMap.put("ID", assetID); - tMap.put("Color", color); - tMap.put("Owner", owner); - tMap.put("Size", Integer.toString(size)); - tMap.put("AppraisedValue", Integer.toString(appraisedValue)); - if (privateProps != null && privateProps.length() > 0) { - tMap.put("asset_properties", new JSONObject(privateProps)); - } - return new JSONObject(tMap).toString(); - } - - public static Asset deserialize(final byte[] assetJSON) { - return deserialize(new String(assetJSON, UTF_8)); - } - - public static Asset deserialize(final String assetJSON) { - - JSONObject json = new JSONObject(assetJSON); - Map tMap = json.toMap(); - final String id = (String) tMap.get("ID"); - - final String color = (String) tMap.get("Color"); - final String owner = (String) tMap.get("Owner"); - int size = 0; - int appraisedValue = 0; - if (tMap.containsKey("Size")) { - size = Integer.parseInt((String) tMap.get("Size")); - } - if (tMap.containsKey("AppraisedValue")) { - appraisedValue = Integer.parseInt((String) tMap.get("AppraisedValue")); - } - return new Asset(id, color, size, owner, appraisedValue); - - } - - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - - if ((obj == null) || (getClass() != obj.getClass())) { - return false; - } - - Asset other = (Asset) obj; - - return Objects.deepEquals( - new String[]{getAssetID(), getColor(), getOwner()}, - new String[]{other.getAssetID(), other.getColor(), other.getOwner()}) - && - Objects.deepEquals( - new int[]{getSize(), getAppraisedValue()}, - new int[]{other.getSize(), other.getAppraisedValue()}); - } - - @Override - public int hashCode() { - return Objects.hash(getAssetID(), getColor(), getSize(), getOwner(), getAppraisedValue()); - } - - @Override - public String toString() { - return this.getClass().getSimpleName() + "@" + Integer.toHexString(hashCode()) - + " [assetID=" + assetID + ", appraisedValue=" + appraisedValue + ", color=" - + color + ", size=" + size + ", owner=" + owner + "]"; - } - -} diff --git a/asset-transfer-events/chaincode-java/src/main/java/org/hyperledger/fabric/samples/events/AssetTransfer.java b/asset-transfer-events/chaincode-java/src/main/java/org/hyperledger/fabric/samples/events/AssetTransfer.java deleted file mode 100644 index a892693a..00000000 --- a/asset-transfer-events/chaincode-java/src/main/java/org/hyperledger/fabric/samples/events/AssetTransfer.java +++ /dev/null @@ -1,299 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ - -package org.hyperledger.fabric.samples.events; - -import static java.nio.charset.StandardCharsets.UTF_8; - -import org.hyperledger.fabric.contract.Context; -import org.hyperledger.fabric.contract.ContractInterface; -import org.hyperledger.fabric.contract.annotation.Contact; -import org.hyperledger.fabric.contract.annotation.Contract; -import org.hyperledger.fabric.contract.annotation.Default; -import org.hyperledger.fabric.contract.annotation.Info; -import org.hyperledger.fabric.contract.annotation.License; -import org.hyperledger.fabric.contract.annotation.Transaction; -import org.hyperledger.fabric.shim.ChaincodeException; -import org.hyperledger.fabric.shim.ChaincodeStub; - -import java.util.Map; - -/** - * Main Chaincode class. - * - * @see org.hyperledger.fabric.shim.Chaincode - *

- * Each chaincode transaction function must take, Context as first parameter. - * Unless specified otherwise via annotation (@Contract or @Transaction), the contract name - * is the class name (without package) - * and the transaction name is the method name. - */ -@Contract( - name = "asset-transfer-events-java", - info = @Info( - title = "Asset Transfer Events", - description = "The hyperlegendary asset transfer events sample", - version = "0.0.1-SNAPSHOT", - license = @License( - name = "Apache 2.0 License", - url = "http://www.apache.org/licenses/LICENSE-2.0.html"), - contact = @Contact( - email = "a.transfer@example.com", - name = "Fabric Development Team", - url = "https://hyperledger.example.com"))) -@Default -public final class AssetTransfer implements ContractInterface { - - static final String IMPLICIT_COLLECTION_NAME_PREFIX = "_implicit_org_"; - static final String PRIVATE_PROPS_KEY = "asset_properties"; - - /** - * Retrieves the asset details with the specified ID - * - * @param ctx the transaction context - * @param assetID the ID of the asset - * @return the asset found on the ledger. Returns error if asset is not found - */ - @Transaction(intent = Transaction.TYPE.EVALUATE) - public String ReadAsset(final Context ctx, final String assetID) { - System.out.printf("ReadAsset: ID %s\n", assetID); - - Asset asset = getState(ctx, assetID); - String privData = readPrivateData(ctx, assetID); - return asset.serialize(privData); - } - - /** - * Creates a new asset on the ledger. Saves the passed private data (asset properties) from transient map input. - * - * @param ctx the transaction context - * Transient map with asset_properties key with asset json as value - * @param assetID - * @param color - * @param size - * @param owner - * @param appraisedValue - * @return the created asset - */ - @Transaction(intent = Transaction.TYPE.SUBMIT) - public Asset CreateAsset(final Context ctx, final String assetID, final String color, final int size, final String owner, final int appraisedValue) { - ChaincodeStub stub = ctx.getStub(); - // input validations - String errorMessage = null; - if (assetID == null || assetID.equals("")) { - errorMessage = String.format("Empty input: assetID"); - } - if (owner == null || owner.equals("")) { - errorMessage = String.format("Empty input: owner"); - } - - if (errorMessage != null) { - System.err.println(errorMessage); - throw new ChaincodeException(errorMessage, AssetTransferErrors.INCOMPLETE_INPUT.toString()); - } - // Check if asset already exists - byte[] assetJSON = ctx.getStub().getState(assetID); - if (assetJSON != null && assetJSON.length > 0) { - errorMessage = String.format("Asset %s already exists", assetID); - System.err.println(errorMessage); - throw new ChaincodeException(errorMessage, AssetTransferErrors.ASSET_ALREADY_EXISTS.toString()); - } - - Asset asset = new Asset(assetID, color, size, owner, appraisedValue); - - savePrivateData(ctx, assetID); - assetJSON = asset.serialize(); - System.out.printf("CreateAsset Put: ID %s Data %s\n", assetID, new String(assetJSON)); - - stub.putState(assetID, assetJSON); - // add Event data to the transaction data. Event will be published after the block containing - // this transaction is committed - stub.setEvent("CreateAsset", assetJSON); - return asset; - } - - - /** - * TransferAsset transfers the asset to the new owner - * Save any private data, if provided in transient map - * - * @param ctx the transaction context - * @param assetID asset to delete - * @param newOwner new owner for the asset - * @return none - */ - @Transaction(intent = Transaction.TYPE.SUBMIT) - public void TransferAsset(final Context ctx, final String assetID, final String newOwner) { - ChaincodeStub stub = ctx.getStub(); - String errorMessage = null; - - if (assetID == null || assetID.equals("")) { - errorMessage = "Empty input: assetID"; - } - if (newOwner == null || newOwner.equals("")) { - errorMessage = "Empty input: newOwner"; - } - if (errorMessage != null) { - System.err.println(errorMessage); - throw new ChaincodeException(errorMessage, AssetTransferErrors.INCOMPLETE_INPUT.toString()); - } - System.out.printf("TransferAsset: verify asset %s exists\n", assetID); - Asset thisAsset = getState(ctx, assetID); - // Transfer asset to new owner - thisAsset.setOwner(newOwner); - - System.out.printf(" Transfer Asset: ID %s to owner %s\n", assetID, newOwner); - savePrivateData(ctx, assetID); // save private data if any - byte[] assetJSON = thisAsset.serialize(); - - stub.putState(assetID, assetJSON); - stub.setEvent("TransferAsset", assetJSON); //publish Event - } - - /** - * Update existing asset on the ledger with provided parameters. - * Saves the passed private data (asset properties) from transient map input. - * - * @param ctx the transaction context - * Transient map with asset_properties key with asset json as value - * @param assetID - * @param color - * @param size - * @param owner - * @param appraisedValue - * @return the created asset - */ - @Transaction(intent = Transaction.TYPE.SUBMIT) - public Asset UpdateAsset(final Context ctx, final String assetID, final String color, final int size, final String owner, final int appraisedValue) { - ChaincodeStub stub = ctx.getStub(); - // input validations - String errorMessage = null; - if (assetID == null || assetID.equals("")) { - errorMessage = String.format("Empty input: assetID"); - } - - if (errorMessage != null) { - System.err.println(errorMessage); - throw new ChaincodeException(errorMessage, AssetTransferErrors.INCOMPLETE_INPUT.toString()); - } - // reads from the Statedb. Check if asset already exists - Asset asset = getState(ctx, assetID); - - if (owner != null) { - asset.setOwner(owner); - } - if (color != null) { - asset.setColor(color); - } - if (size > 0) { - asset.setSize(size); - } - if (appraisedValue > 0) { - asset.setAppraisedValue(appraisedValue); - } - - savePrivateData(ctx, assetID); - byte[] assetJSON = asset.serialize(); - System.out.printf("UpdateAsset Put: ID %s Data %s\n", assetID, new String(assetJSON)); - stub.putState(assetID, assetJSON); - stub.setEvent("UpdateAsset", assetJSON); //publish Event - return asset; - } - - /** - * Deletes a asset & related details from the ledger. - * - * @param ctx the transaction context - * @param assetID asset to delete - */ - @Transaction(intent = Transaction.TYPE.SUBMIT) - public void DeleteAsset(final Context ctx, final String assetID) { - ChaincodeStub stub = ctx.getStub(); - System.out.printf("DeleteAsset: verify asset %s exists\n", assetID); - Asset asset = getState(ctx, assetID); - - System.out.printf(" DeleteAsset: ID %s\n", assetID); - // delete private details of asset - removePrivateData(ctx, assetID); - stub.delState(assetID); // delete the key from Statedb - stub.setEvent("DeleteAsset", asset.serialize()); // publish Event - } - - private Asset getState(final Context ctx, final String assetID) { - byte[] assetJSON = ctx.getStub().getState(assetID); - if (assetJSON == null || assetJSON.length == 0) { - String errorMessage = String.format("Asset %s does not exist", assetID); - System.err.println(errorMessage); - throw new ChaincodeException(errorMessage, AssetTransferErrors.ASSET_NOT_FOUND.toString()); - } - - try { - Asset asset = Asset.deserialize(assetJSON); - return asset; - } catch (Exception e) { - throw new ChaincodeException("Deserialize error: " + e.getMessage(), AssetTransferErrors.DATA_ERROR.toString()); - } - } - - private String readPrivateData(final Context ctx, final String assetKey) { - String peerMSPID = ctx.getStub().getMspId(); - String clientMSPID = ctx.getClientIdentity().getMSPID(); - String implicitCollectionName = getCollectionName(ctx); - String privData = null; - // only if ClientOrgMatchesPeerOrg - if (peerMSPID.equals(clientMSPID)) { - System.out.printf(" ReadPrivateData from collection %s, ID %s\n", implicitCollectionName, assetKey); - byte[] propJSON = ctx.getStub().getPrivateData(implicitCollectionName, assetKey); - - if (propJSON != null && propJSON.length > 0) { - privData = new String(propJSON, UTF_8); - } - } - return privData; - } - - private void savePrivateData(final Context ctx, final String assetKey) { - String peerMSPID = ctx.getStub().getMspId(); - String clientMSPID = ctx.getClientIdentity().getMSPID(); - String implicitCollectionName = getCollectionName(ctx); - - if (peerMSPID.equals(clientMSPID)) { - Map transientMap = ctx.getStub().getTransient(); - if (transientMap != null && transientMap.containsKey(PRIVATE_PROPS_KEY)) { - byte[] transientAssetJSON = transientMap.get(PRIVATE_PROPS_KEY); - - System.out.printf("Asset's PrivateData Put in collection %s, ID %s\n", implicitCollectionName, assetKey); - ctx.getStub().putPrivateData(implicitCollectionName, assetKey, transientAssetJSON); - } - } - } - - private void removePrivateData(final Context ctx, final String assetKey) { - String peerMSPID = ctx.getStub().getMspId(); - String clientMSPID = ctx.getClientIdentity().getMSPID(); - String implicitCollectionName = getCollectionName(ctx); - - if (peerMSPID.equals(clientMSPID)) { - System.out.printf("PrivateData Delete from collection %s, ID %s\n", implicitCollectionName, assetKey); - ctx.getStub().delPrivateData(implicitCollectionName, assetKey); - } - } - - // Return the implicit collection name, to use for private property persistance - private String getCollectionName(final Context ctx) { - // Get the MSP ID of submitting client identity - String clientMSPID = ctx.getClientIdentity().getMSPID(); - String collectionName = IMPLICIT_COLLECTION_NAME_PREFIX + clientMSPID; - return collectionName; - } - - private enum AssetTransferErrors { - INCOMPLETE_INPUT, - INVALID_ACCESS, - ASSET_NOT_FOUND, - ASSET_ALREADY_EXISTS, - DATA_ERROR - } - -} diff --git a/asset-transfer-events/chaincode-javascript/.eslintignore b/asset-transfer-events/chaincode-javascript/.eslintignore deleted file mode 100644 index 15958470..00000000 --- a/asset-transfer-events/chaincode-javascript/.eslintignore +++ /dev/null @@ -1,5 +0,0 @@ -# -# SPDX-License-Identifier: Apache-2.0 -# - -coverage diff --git a/asset-transfer-events/chaincode-javascript/.eslintrc.js b/asset-transfer-events/chaincode-javascript/.eslintrc.js deleted file mode 100644 index cb00fa96..00000000 --- a/asset-transfer-events/chaincode-javascript/.eslintrc.js +++ /dev/null @@ -1,39 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ -'use strict'; - -module.exports = { - env: { - node: true, - mocha: true, - es6: true - }, - parserOptions: { - ecmaVersion: 8, - sourceType: 'script' - }, - extends: 'eslint:recommended', - rules: { - indent: ['error', 'tab'], - 'linebreak-style': ['error', 'unix'], - quotes: ['error', 'single'], - semi: ['error', 'always'], - 'no-unused-vars': ['error', { args: 'none' }], - 'no-console': 'off', - curly: 'error', - eqeqeq: 'error', - 'no-throw-literal': 'error', - strict: 'error', - 'no-var': 'error', - 'dot-notation': 'error', - 'no-trailing-spaces': 'error', - 'no-use-before-define': 'error', - 'no-useless-call': 'error', - 'no-with': 'error', - 'operator-linebreak': 'error', - yoda: 'error', - 'quote-props': ['error', 'as-needed'], - 'no-constant-condition': ['error', { checkLoops: false }] - } -}; diff --git a/asset-transfer-events/chaincode-javascript/.gitignore b/asset-transfer-events/chaincode-javascript/.gitignore deleted file mode 100644 index eeace290..00000000 --- a/asset-transfer-events/chaincode-javascript/.gitignore +++ /dev/null @@ -1,15 +0,0 @@ -# -# SPDX-License-Identifier: Apache-2.0 -# - -# Coverage directory used by tools like istanbul -coverage - -# Report cache used by istanbul -.nyc_output - -# Dependency directories -node_modules/ -jspm_packages/ - -package-lock.json diff --git a/asset-transfer-events/chaincode-javascript/index.js b/asset-transfer-events/chaincode-javascript/index.js deleted file mode 100644 index 3244cedf..00000000 --- a/asset-transfer-events/chaincode-javascript/index.js +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const assetTransferEvents = require('./lib/assetTransferEvents'); - -module.exports.AssetTransferEvents = assetTransferEvents; -module.exports.contracts = [assetTransferEvents]; diff --git a/asset-transfer-events/chaincode-javascript/lib/assetTransferEvents.js b/asset-transfer-events/chaincode-javascript/lib/assetTransferEvents.js deleted file mode 100644 index 27c5acbd..00000000 --- a/asset-transfer-events/chaincode-javascript/lib/assetTransferEvents.js +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const { Contract } = require('fabric-contract-api'); - -async function savePrivateData(ctx, assetKey) { - const clientOrg = ctx.clientIdentity.getMSPID(); - const peerOrg = ctx.stub.getMspID(); - const collection = '_implicit_org_' + peerOrg; - - if (clientOrg === peerOrg) { - const transientMap = ctx.stub.getTransient(); - if (transientMap) { - const properties = transientMap.get('asset_properties'); - if (properties) { - await ctx.stub.putPrivateData(collection, assetKey, properties); - } - } - } -} - -async function removePrivateData(ctx, assetKey) { - const clientOrg = ctx.clientIdentity.getMSPID(); - const peerOrg = ctx.stub.getMspID(); - const collection = '_implicit_org_' + peerOrg; - - if (clientOrg === peerOrg) { - const propertiesBuffer = await ctx.stub.getPrivateData(collection, assetKey); - if (propertiesBuffer && propertiesBuffer.length > 0) { - await ctx.stub.deletePrivateData(collection, assetKey); - } - } -} - -async function addPrivateData(ctx, assetKey, asset) { - const clientOrg = ctx.clientIdentity.getMSPID(); - const peerOrg = ctx.stub.getMspID(); - const collection = '_implicit_org_' + peerOrg; - - if (clientOrg === peerOrg) { - const propertiesBuffer = await ctx.stub.getPrivateData(collection, assetKey); - if (propertiesBuffer && propertiesBuffer.length > 0) { - const properties = JSON.parse(propertiesBuffer.toString()); - asset.asset_properties = properties; - } - } -} - -async function readState(ctx, id) { - const assetBuffer = await ctx.stub.getState(id); // get the asset from chaincode state - if (!assetBuffer || assetBuffer.length === 0) { - throw new Error(`The asset ${id} does not exist`); - } - const assetString = assetBuffer.toString(); - const asset = JSON.parse(assetString); - - return asset; -} - -class AssetTransferEvents extends Contract { - - // CreateAsset issues a new asset to the world state with given details. - async CreateAsset(ctx, id, color, size, owner, appraisedValue) { - const asset = { - ID: id, - Color: color, - Size: size, - Owner: owner, - AppraisedValue: appraisedValue, - }; - await savePrivateData(ctx, id); - const assetBuffer = Buffer.from(JSON.stringify(asset)); - - ctx.stub.setEvent('CreateAsset', assetBuffer); - return ctx.stub.putState(id, assetBuffer); - } - - // TransferAsset updates the owner field of an asset with the given id in - // the world state. - async TransferAsset(ctx, id, newOwner) { - const asset = await readState(ctx, id); - asset.Owner = newOwner; - const assetBuffer = Buffer.from(JSON.stringify(asset)); - await savePrivateData(ctx, id); - - ctx.stub.setEvent('TransferAsset', assetBuffer); - return ctx.stub.putState(id, assetBuffer); - } - - // ReadAsset returns the asset stored in the world state with given id. - async ReadAsset(ctx, id) { - const asset = await readState(ctx, id); - await addPrivateData(ctx, asset.ID, asset); - - return JSON.stringify(asset); - } - - // UpdateAsset updates an existing asset in the world state with provided parameters. - async UpdateAsset(ctx, id, color, size, owner, appraisedValue) { - const asset = await readState(ctx, id); - asset.Color = color; - asset.Size = size; - asset.Owner = owner; - asset.AppraisedValue = appraisedValue; - const assetBuffer = Buffer.from(JSON.stringify(asset)); - await savePrivateData(ctx, id); - - ctx.stub.setEvent('UpdateAsset', assetBuffer); - return ctx.stub.putState(id, assetBuffer); - } - - // DeleteAsset deletes an given asset from the world state. - async DeleteAsset(ctx, id) { - const asset = await readState(ctx, id); - const assetBuffer = Buffer.from(JSON.stringify(asset)); - await removePrivateData(ctx, id); - - ctx.stub.setEvent('DeleteAsset', assetBuffer); - return ctx.stub.deleteState(id); - } -} - -module.exports = AssetTransferEvents; diff --git a/asset-transfer-events/chaincode-javascript/npm-shrinkwrap.json b/asset-transfer-events/chaincode-javascript/npm-shrinkwrap.json deleted file mode 100644 index 8f9fc8e5..00000000 --- a/asset-transfer-events/chaincode-javascript/npm-shrinkwrap.json +++ /dev/null @@ -1,3982 +0,0 @@ -{ - "name": "asset-transfer-events", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "asset-transfer-events", - "version": "1.0.0", - "license": "Apache-2.0", - "dependencies": { - "fabric-contract-api": "~2.5", - "fabric-shim": "~2.5" - }, - "devDependencies": { - "chai": "^4.4.1", - "eslint": "^8.57.0", - "mocha": "^10.4.0", - "nyc": "^15.1.0", - "sinon": "^18.0.0", - "sinon-chai": "^3.7.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", - "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.24.7", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.7.tgz", - "integrity": "sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.7.tgz", - "integrity": "sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.7", - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helpers": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/template": "^7.24.7", - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, - "node_modules/@babel/generator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.7.tgz", - "integrity": "sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.24.7", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.7.tgz", - "integrity": "sha512-ctSdRHBi20qWOfy27RUb4Fhp07KSJ3sXcuSvTrXrc4aG8NSYDo1ici3Vhg9bg69y5bj0Mr1lh0aeEgTvc12rMg==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.24.7", - "@babel/helper-validator-option": "^7.24.7", - "browserslist": "^4.22.2", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", - "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", - "dev": true, - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz", - "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==", - "dev": true, - "dependencies": { - "@babel/template": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz", - "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==", - "dev": true, - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", - "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", - "dev": true, - "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.7.tgz", - "integrity": "sha512-1fuJEwIrp+97rM4RWdO+qrRsZlAeL1lQJoPqtCYWv0NL115XM93hIH4CSRln2w52SqvmY5hqdtauB6QFCDiZNQ==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-module-imports": "^7.24.7", - "@babel/helper-simple-access": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", - "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", - "dev": true, - "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", - "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz", - "integrity": "sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", - "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.7.tgz", - "integrity": "sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.7.tgz", - "integrity": "sha512-NlmJJtvcw72yRJRcnCmGvSi+3jDEg8qFu3z0AFoymmzLx5ERVWyzd9kVXr7Th9/8yIJi2Zc6av4Tqz3wFs8QWg==", - "dev": true, - "dependencies": { - "@babel/template": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", - "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.24.7", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/parser": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.7.tgz", - "integrity": "sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/template": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz", - "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.7.tgz", - "integrity": "sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.7", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-hoist-variables": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/types": "^7.24.7", - "debug": "^4.3.1", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse/node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/types": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz", - "integrity": "sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@colors/colors": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", - "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/@dabh/diagnostics": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", - "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", - "dependencies": { - "colorspace": "1.1.x", - "enabled": "2.0.x", - "kuler": "^2.0.0" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.1.tgz", - "integrity": "sha512-Zm2NGpWELsQAD1xsJzGQpYfvICSsFkEpU0jxBjfdC6uNEWXcHnfs9hScFWtXVDVl+rBQJGrl4g1vcKIejpH9dA==", - "dev": true, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/js": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", - "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@fidm/asn1": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@fidm/asn1/-/asn1-1.0.4.tgz", - "integrity": "sha512-esd1jyNvRb2HVaQGq2Gg8Z0kbQPXzV9Tq5Z14KNIov6KfFD6PTaRIO8UpcsYiTNzOqJpmyzWgVTrUwFV3UF4TQ==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@fidm/x509": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@fidm/x509/-/x509-1.2.1.tgz", - "integrity": "sha512-nwc2iesjyc9hkuzcrMCBXQRn653XuAUKorfWM8PZyJawiy1QzLj4vahwzaI25+pfpwOLvMzbJ0uKpWLDNmo16w==", - "dependencies": { - "@fidm/asn1": "^1.0.4", - "tweetnacl": "^1.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@grpc/grpc-js": { - "version": "1.10.9", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.10.9.tgz", - "integrity": "sha512-5tcgUctCG0qoNyfChZifz2tJqbRbXVO9J7X6duFcOjY3HUNCxg5D0ZCK7EP9vIcZ0zRpLU9bWkyCqVCLZ46IbQ==", - "dependencies": { - "@grpc/proto-loader": "^0.7.13", - "@js-sdsl/ordered-map": "^4.4.2" - }, - "engines": { - "node": ">=12.10.0" - } - }, - "node_modules/@grpc/proto-loader": { - "version": "0.7.13", - "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.13.tgz", - "integrity": "sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw==", - "dependencies": { - "lodash.camelcase": "^4.3.0", - "long": "^5.0.0", - "protobufjs": "^7.2.5", - "yargs": "^17.7.2" - }, - "bin": { - "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", - "deprecated": "Use @eslint/config-array instead", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "deprecated": "Use @eslint/object-schema instead", - "dev": true - }, - "node_modules/@hyperledger/fabric-protos": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@hyperledger/fabric-protos/-/fabric-protos-0.2.1.tgz", - "integrity": "sha512-qjm0vIQIfCall804tWDeA8p/mUfu14sl5Sj+PbOn2yDKJq+7ThoIhNsLAqf+BCxUfqsoqQq6AojhqQeTFyOOqg==", - "dependencies": { - "@grpc/grpc-js": "^1.9.0", - "google-protobuf": "^3.21.0" - }, - "engines": { - "node": ">=14.15.0" - } - }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@js-sdsl/ordered-map": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz", - "integrity": "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/js-sdsl" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@protobufjs/aspromise": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" - }, - "node_modules/@protobufjs/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" - }, - "node_modules/@protobufjs/codegen": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" - }, - "node_modules/@protobufjs/eventemitter": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" - }, - "node_modules/@protobufjs/fetch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", - "dependencies": { - "@protobufjs/aspromise": "^1.1.1", - "@protobufjs/inquire": "^1.1.0" - } - }, - "node_modules/@protobufjs/float": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" - }, - "node_modules/@protobufjs/inquire": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" - }, - "node_modules/@protobufjs/path": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" - }, - "node_modules/@protobufjs/pool": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" - }, - "node_modules/@protobufjs/utf8": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" - }, - "node_modules/@sinonjs/commons": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", - "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", - "dev": true, - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/fake-timers": { - "version": "11.2.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-11.2.2.tgz", - "integrity": "sha512-G2piCSxQ7oWOxwGSAyFHfPIsyeJGXYtc6mFbnFA+kRXkiEnTl8c/8jul2S329iFBnDI9HGoeWWAZvuvOkZccgw==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^3.0.0" - } - }, - "node_modules/@sinonjs/samsam": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.0.tgz", - "integrity": "sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^2.0.0", - "lodash.get": "^4.4.2", - "type-detect": "^4.0.8" - } - }, - "node_modules/@sinonjs/samsam/node_modules/@sinonjs/commons": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", - "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", - "dev": true, - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/text-encoding": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz", - "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", - "dev": true - }, - "node_modules/@types/node": { - "version": "16.18.98", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.98.tgz", - "integrity": "sha512-fpiC20NvLpTLAzo3oVBKIqBGR6Fx/8oAK/SSf7G+fydnXMY1x4x9RZ6sBXhqKlCU21g2QapUsbLlhv3+a7wS+Q==" - }, - "node_modules/@types/triple-beam": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", - "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==" - }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true - }, - "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/append-transform": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", - "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", - "dev": true, - "dependencies": { - "default-require-extensions": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/archy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", - "dev": true - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/async": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", - "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true - }, - "node_modules/browserslist": { - "version": "4.23.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.1.tgz", - "integrity": "sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "caniuse-lite": "^1.0.30001629", - "electron-to-chromium": "^1.4.796", - "node-releases": "^2.0.14", - "update-browserslist-db": "^1.0.16" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/caching-transform": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", - "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", - "dev": true, - "dependencies": { - "hasha": "^5.0.0", - "make-dir": "^3.0.0", - "package-hash": "^4.0.0", - "write-file-atomic": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001633", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001633.tgz", - "integrity": "sha512-6sT0yf/z5jqf8tISAgpJDrmwOpLsrpnyCdD/lOZKvKkkJK4Dn0X5i7KF7THEZhOq+30bmhwBlNEaqPUiHiKtZg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ] - }, - "node_modules/chai": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz", - "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==", - "dev": true, - "dependencies": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.3", - "deep-eql": "^4.1.3", - "get-func-name": "^2.0.2", - "loupe": "^2.3.6", - "pathval": "^1.1.1", - "type-detect": "^4.0.8" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/check-error": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", - "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", - "dev": true, - "dependencies": { - "get-func-name": "^2.0.2" - }, - "engines": { - "node": "*" - } - }, - "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/class-transformer": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.4.0.tgz", - "integrity": "sha512-ETWD/H2TbWbKEi7m9N4Km5+cw1hNcqJSxlSYhsLsNjQzWWiZIYA1zafxpK9PwVfaZ6AqR5rrjPVUBGESm5tQUA==" - }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/color": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", - "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", - "dependencies": { - "color-convert": "^1.9.3", - "color-string": "^1.6.0" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/color-string": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", - "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", - "dependencies": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } - }, - "node_modules/color/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "node_modules/colorspace": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", - "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", - "dependencies": { - "color": "^3.1.3", - "text-hex": "1.0.x" - } - }, - "node_modules/commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/deep-eql": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", - "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", - "dev": true, - "dependencies": { - "type-detect": "^4.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/default-require-extensions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.1.tgz", - "integrity": "sha512-eXTJmRbm2TIt9MgWTsOH1wEuhew6XGZcMeGKCtLedIg/NCsg1iBePXkceTdK4Fii7pzmN9tGsZhKzZ4h7O/fxw==", - "dev": true, - "dependencies": { - "strip-bom": "^4.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.4.802", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.802.tgz", - "integrity": "sha512-TnTMUATbgNdPXVSHsxvNVSG0uEd6cSZsANjm8c9HbvflZVVn1yTRcmVXYT1Ma95/ssB/Dcd30AHweH2TE+dNpA==", - "dev": true - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "node_modules/enabled": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", - "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" - }, - "node_modules/es6-error": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", - "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", - "dev": true - }, - "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.0", - "@humanwhocodes/config-array": "^0.11.14", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fabric-contract-api": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/fabric-contract-api/-/fabric-contract-api-2.5.6.tgz", - "integrity": "sha512-AosGb8tA+Jgt+pqMEgYNB3/J/P5QuWOC7yhXbhDmAAwUzn4Sc7pdWDICH1YyrFGZNFxMGQmqJmLVWUX8BKHy0w==", - "dependencies": { - "class-transformer": "^0.4.0", - "fabric-shim-api": "2.5.6", - "fast-safe-stringify": "^2.1.1", - "get-params": "^0.1.2", - "reflect-metadata": "^0.1.13", - "winston": "^3.7.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/fabric-shim": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/fabric-shim/-/fabric-shim-2.5.6.tgz", - "integrity": "sha512-4Y8WNFhYuQ9QYSEgPXWdlXnrXjwOlM10sQQzE4kJ7cDh8a4LX0rn44FxtxTCB18lnzrSLMZ8/8Cr5m0c9NeXWA==", - "dependencies": { - "@fidm/x509": "^1.2.1", - "@grpc/grpc-js": "~1.10.9", - "@hyperledger/fabric-protos": "~0.2.1", - "@types/node": "^16.11.1", - "ajv": "^6.12.2", - "fabric-contract-api": "2.5.6", - "fabric-shim-api": "2.5.6", - "fast-safe-stringify": "^2.1.1", - "long": "^5.2.3", - "reflect-metadata": "^0.1.13", - "winston": "^3.7.2", - "yargs": "^17.4.0", - "yargs-parser": "^21.0.1" - }, - "bin": { - "fabric-chaincode-node": "cli.js" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/fabric-shim-api": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/fabric-shim-api/-/fabric-shim-api-2.5.6.tgz", - "integrity": "sha512-1L0nO7CJ31/gEOWKWHEeCqgB5HkqPVfRbpcS7L9eTscT7tffjg2OkZISvC+a7RiqihL0iyrXNBgBg5MwlSSN9g==", - "engines": { - "eslint": "^6.6.0", - "node": ">=18" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fast-safe-stringify": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", - "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==" - }, - "node_modules/fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fecha": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", - "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-cache-dir": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", - "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", - "dev": true, - "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/avajs/find-cache-dir?sponsor=1" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true, - "bin": { - "flat": "cli.js" - } - }, - "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", - "dev": true, - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", - "dev": true - }, - "node_modules/fn.name": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", - "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" - }, - "node_modules/foreground-child": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", - "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/fromentries": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", - "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-func-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", - "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/get-params": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/get-params/-/get-params-0.1.2.tgz", - "integrity": "sha512-41eOxtlGgHQRbFyA8KTH+w+32Em3cRdfBud7j67ulzmIfmaHX9doq47s0fa4P5o9H64BZX9nrYI6sJvk46Op+Q==" - }, - "node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/google-protobuf": { - "version": "3.21.2", - "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.21.2.tgz", - "integrity": "sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA==" - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/hasha": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", - "integrity": "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==", - "dev": true, - "dependencies": { - "is-stream": "^2.0.0", - "type-fest": "^0.8.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/hasha/node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, - "bin": { - "he": "bin/he" - } - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "node_modules/ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true - }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-hook": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", - "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", - "dev": true, - "dependencies": { - "append-transform": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", - "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", - "dev": true, - "dependencies": { - "@babel/core": "^7.7.5", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-processinfo": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.3.tgz", - "integrity": "sha512-NkwHbo3E00oybX6NGJi6ar0B29vxyvNwoC7eJ4G4Yq28UfY758Hgn/heV8VRFhevPED4LXfFz0DQ8z/0kw9zMg==", - "dev": true, - "dependencies": { - "archy": "^1.0.0", - "cross-spawn": "^7.0.3", - "istanbul-lib-coverage": "^3.2.0", - "p-map": "^3.0.0", - "rimraf": "^3.0.0", - "uuid": "^8.3.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", - "dev": true, - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^4.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-report/node_modules/make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", - "dev": true, - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/istanbul-lib-report/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-reports": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", - "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", - "dev": true, - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/just-extend": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-6.2.0.tgz", - "integrity": "sha512-cYofQu2Xpom82S6qD778jBDpwvvy39s1l/hrYij2u9AMdQcGRpaBu6kY4mVhuno5kJVi1DAz4aiphA2WI1/OAw==", - "dev": true - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/kuler": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", - "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash.camelcase": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" - }, - "node_modules/lodash.flattendeep": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", - "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==", - "dev": true - }, - "node_modules/lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", - "dev": true - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/logform": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.0.tgz", - "integrity": "sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ==", - "dependencies": { - "@colors/colors": "1.6.0", - "@types/triple-beam": "^1.3.2", - "fecha": "^4.2.0", - "ms": "^2.1.1", - "safe-stable-stringify": "^2.3.1", - "triple-beam": "^1.3.0" - }, - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/long": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", - "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" - }, - "node_modules/loupe": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", - "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", - "dev": true, - "dependencies": { - "get-func-name": "^2.0.1" - } - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/mocha": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.4.0.tgz", - "integrity": "sha512-eqhGB8JKapEYcC4ytX/xrzKforgEc3j1pGlAXVy3eRwrtAy5/nIfT1SvgGzfN0XZZxeLq0aQWkOUAmqIJiv+bA==", - "dev": true, - "dependencies": { - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.4", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "8.1.0", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "5.0.1", - "ms": "2.1.3", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "workerpool": "6.2.1", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha.js" - }, - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/mocha/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/mocha/node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/mocha/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/mocha/node_modules/debug/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/mocha/node_modules/minimatch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mocha/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/mocha/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/mocha/node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mocha/node_modules/yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/nise": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/nise/-/nise-6.0.0.tgz", - "integrity": "sha512-K8ePqo9BFvN31HXwEtTNGzgrPpmvgciDsFz8aztFjt4LqKO/JeFD8tBOeuDiCMXrIl/m1YvfH8auSpxfaD09wg==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^3.0.0", - "@sinonjs/fake-timers": "^11.2.2", - "@sinonjs/text-encoding": "^0.7.2", - "just-extend": "^6.2.0", - "path-to-regexp": "^6.2.1" - } - }, - "node_modules/node-preload": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", - "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==", - "dev": true, - "dependencies": { - "process-on-spawn": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/node-releases": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", - "dev": true - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nyc": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz", - "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==", - "dev": true, - "dependencies": { - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "caching-transform": "^4.0.0", - "convert-source-map": "^1.7.0", - "decamelize": "^1.2.0", - "find-cache-dir": "^3.2.0", - "find-up": "^4.1.0", - "foreground-child": "^2.0.0", - "get-package-type": "^0.1.0", - "glob": "^7.1.6", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-hook": "^3.0.0", - "istanbul-lib-instrument": "^4.0.0", - "istanbul-lib-processinfo": "^2.0.2", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.2", - "make-dir": "^3.0.0", - "node-preload": "^0.2.1", - "p-map": "^3.0.0", - "process-on-spawn": "^1.0.0", - "resolve-from": "^5.0.0", - "rimraf": "^3.0.0", - "signal-exit": "^3.0.2", - "spawn-wrap": "^2.0.0", - "test-exclude": "^6.0.0", - "yargs": "^15.0.2" - }, - "bin": { - "nyc": "bin/nyc.js" - }, - "engines": { - "node": ">=8.9" - } - }, - "node_modules/nyc/node_modules/cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "node_modules/nyc/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nyc/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/nyc/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nyc/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/nyc/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nyc/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/nyc/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nyc/node_modules/y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "dev": true - }, - "node_modules/nyc/node_modules/yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "dev": true, - "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nyc/node_modules/yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/one-time": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", - "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", - "dependencies": { - "fn.name": "1.x.x" - } - }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-map": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", - "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", - "dev": true, - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/package-hash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", - "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.15", - "hasha": "^5.0.0", - "lodash.flattendeep": "^4.4.0", - "release-zalgo": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-to-regexp": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.2.tgz", - "integrity": "sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==", - "dev": true - }, - "node_modules/pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/picocolors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pkg-dir/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/process-on-spawn": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", - "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==", - "dev": true, - "dependencies": { - "fromentries": "^1.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/protobufjs": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.3.2.tgz", - "integrity": "sha512-RXyHaACeqXeqAKGLDl68rQKbmObRsTIn4TYVUUug1KfS47YWCo5MacGITEryugIgZqORCvJWEk4l449POg5Txg==", - "hasInstallScript": true, - "dependencies": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/node": ">=13.7.0", - "long": "^5.0.0" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/reflect-metadata": { - "version": "0.1.14", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.14.tgz", - "integrity": "sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A==" - }, - "node_modules/release-zalgo": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", - "integrity": "sha512-gUAyHVHPPC5wdqX/LG4LWtRYtgjxyX78oanFNTMMyFEfOqdC54s3eE82imuWKbOeqYht2CrNf64Qb8vgmmtZGA==", - "dev": true, - "dependencies": { - "es6-error": "^4.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/safe-stable-stringify": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", - "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", - "engines": { - "node": ">=10" - } - }, - "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "dev": true - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", - "dependencies": { - "is-arrayish": "^0.3.1" - } - }, - "node_modules/sinon": { - "version": "18.0.0", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-18.0.0.tgz", - "integrity": "sha512-+dXDXzD1sBO6HlmZDd7mXZCR/y5ECiEiGCBSGuFD/kZ0bDTofPYc6JaeGmPSF+1j1MejGUWkORbYOLDyvqCWpA==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^3.0.1", - "@sinonjs/fake-timers": "^11.2.2", - "@sinonjs/samsam": "^8.0.0", - "diff": "^5.2.0", - "nise": "^6.0.0", - "supports-color": "^7" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/sinon" - } - }, - "node_modules/sinon-chai": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/sinon-chai/-/sinon-chai-3.7.0.tgz", - "integrity": "sha512-mf5NURdUaSdnatJx3uhoBOrY9dtL19fiOtAdT1Azxg3+lNJFiuN0uzaU3xX1LeAfL17kHQhTAJgpsfhbMJMY2g==", - "dev": true, - "peerDependencies": { - "chai": "^4.0.0", - "sinon": ">=4.0.0" - } - }, - "node_modules/sinon/node_modules/diff": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", - "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/spawn-wrap": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", - "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", - "dev": true, - "dependencies": { - "foreground-child": "^2.0.0", - "is-windows": "^1.0.2", - "make-dir": "^3.0.0", - "rimraf": "^3.0.0", - "signal-exit": "^3.0.2", - "which": "^2.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, - "node_modules/stack-trace": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", - "engines": { - "node": "*" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/test-exclude/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/text-hex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", - "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/triple-beam": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", - "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/tweetnacl": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", - "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "dependencies": { - "is-typedarray": "^1.0.0" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz", - "integrity": "sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "escalade": "^3.1.2", - "picocolors": "^1.0.1" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/which-module": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", - "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", - "dev": true - }, - "node_modules/winston": { - "version": "3.13.0", - "resolved": "https://registry.npmjs.org/winston/-/winston-3.13.0.tgz", - "integrity": "sha512-rwidmA1w3SE4j0E5MuIufFhyJPBDG7Nu71RkZor1p2+qHvJSZ9GYDA81AyleQcZbh/+V6HjeBdfnTZJm9rSeQQ==", - "dependencies": { - "@colors/colors": "^1.6.0", - "@dabh/diagnostics": "^2.0.2", - "async": "^3.2.3", - "is-stream": "^2.0.0", - "logform": "^2.4.0", - "one-time": "^1.0.0", - "readable-stream": "^3.4.0", - "safe-stable-stringify": "^2.3.1", - "stack-trace": "0.0.x", - "triple-beam": "^1.3.0", - "winston-transport": "^4.7.0" - }, - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/winston-transport": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.7.0.tgz", - "integrity": "sha512-ajBj65K5I7denzer2IYW6+2bNIVqLGDHqDw3Ow8Ohh+vdW+rv4MZ6eiDvHoKhfJFZ2auyN8byXieDDJ96ViONg==", - "dependencies": { - "logform": "^2.3.2", - "readable-stream": "^3.6.0", - "triple-beam": "^1.3.0" - }, - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/workerpool": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", - "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", - "dev": true - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "node_modules/write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dev": true, - "dependencies": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-unparser/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/yargs-unparser/node_modules/decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - } -} diff --git a/asset-transfer-events/chaincode-javascript/package.json b/asset-transfer-events/chaincode-javascript/package.json deleted file mode 100644 index 05587582..00000000 --- a/asset-transfer-events/chaincode-javascript/package.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "name": "asset-transfer-events", - "version": "1.0.0", - "description": "Asset-Transfer-Events contract implemented in JavaScript", - "main": "index.js", - "engines": { - "node": ">=18" - }, - "scripts": { - "lint": "eslint .", - "pretest": "npm run lint", - "test": "nyc mocha --recursive", - "start": "fabric-chaincode-node start" - }, - "engineStrict": true, - "author": "Hyperledger", - "license": "Apache-2.0", - "dependencies": { - "fabric-contract-api": "~2.5", - "fabric-shim": "~2.5" - }, - "devDependencies": { - "chai": "^4.4.1", - "eslint": "^8.57.0", - "mocha": "^10.4.0", - "nyc": "^15.1.0", - "sinon": "^18.0.0", - "sinon-chai": "^3.7.0" - }, - "nyc": { - "exclude": [ - "coverage/**", - "test/**", - "index.js", - ".eslintrc.js" - ], - "reporter": [ - "text-summary", - "html" - ], - "all": true, - "check-coverage": true, - "statements": 100, - "branches": 100, - "functions": 100, - "lines": 100 - } -} diff --git a/asset-transfer-events/chaincode-javascript/test/assetTransferEvents.test.js b/asset-transfer-events/chaincode-javascript/test/assetTransferEvents.test.js deleted file mode 100644 index 552b8ad7..00000000 --- a/asset-transfer-events/chaincode-javascript/test/assetTransferEvents.test.js +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 -*/ - -'use strict'; -const sinon = require('sinon'); -const chai = require('chai'); -const sinonChai = require('sinon-chai'); -const expect = chai.expect; - -const { Context } = require('fabric-contract-api'); -const { ChaincodeStub, ClientIdentity } = require('fabric-shim'); - -const AssetTransfer = require('../lib/assetTransferEvents.js'); - -let assert = sinon.assert; -chai.use(sinonChai); - -describe('Asset Transfer Events Tests', () => { - let transactionContext, chaincodeStub, clientIdentity, asset; - let transientMap, asset_properties; - - beforeEach(() => { - transactionContext = new Context(); - - chaincodeStub = sinon.createStubInstance(ChaincodeStub); - chaincodeStub.getMspID.returns('org1'); - transactionContext.setChaincodeStub(chaincodeStub); - - clientIdentity = sinon.createStubInstance(ClientIdentity); - clientIdentity.getMSPID.returns('org1'); - transactionContext.clientIdentity = clientIdentity; - - chaincodeStub.putState.callsFake((key, value) => { - if (!chaincodeStub.states) { - chaincodeStub.states = {}; - } - chaincodeStub.states[key] = value; - }); - - chaincodeStub.getState.callsFake(async (key) => { - let ret; - if (chaincodeStub.states) { - ret = chaincodeStub.states[key]; - } - return Promise.resolve(ret); - }); - - chaincodeStub.deleteState.callsFake(async (key) => { - if (chaincodeStub.states) { - delete chaincodeStub.states[key]; - } - return Promise.resolve(key); - }); - - chaincodeStub.getStateByRange.callsFake(async () => { - function* internalGetStateByRange() { - if (chaincodeStub.states) { - // Shallow copy - const copied = Object.assign({}, chaincodeStub.states); - - for (let key in copied) { - yield {value: copied[key]}; - } - } - } - - return Promise.resolve(internalGetStateByRange()); - }); - - asset = { - ID: 'asset1', - Color: 'blue', - Size: 5, - Owner: 'Tomoko', - AppraisedValue: 300, - }; - const randomNumber = Math.floor(Math.random() * 100) + 1; - asset_properties = { - object_type: 'asset_properties', - asset_id: 'asset1', - Price: '90', - salt: Buffer.from(randomNumber.toString()).toString('hex') - }; - transientMap = new Map(); - transientMap.set('asset_properties', Buffer.from(JSON.stringify(asset_properties))); - }); - - describe('Test CreateAsset', () => { - it('should return error on CreateAsset', async () => { - chaincodeStub.putState.rejects('failed inserting key'); - - let assetTransfer = new AssetTransfer(); - try { - await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue); - assert.fail('CreateAsset should have failed'); - } catch(err) { - expect(err.name).to.equal('failed inserting key'); - } - }); - - it('should return success on CreateAsset', async () => { - let assetTransfer = new AssetTransfer(); - - await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue); - - let ret = JSON.parse((await chaincodeStub.getState(asset.ID)).toString()); - expect(ret).to.eql(asset); - }); - it('should return success on CreateAsset with transient data', async () => { - let assetTransfer = new AssetTransfer(); - chaincodeStub.getTransient.returns(transientMap); - await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue); - - let ret = JSON.parse((await chaincodeStub.getState(asset.ID)).toString()); - expect(ret).to.eql(asset); - }); - }); - - describe('Test ReadAsset', () => { - it('should return error on ReadAsset', async () => { - let assetTransfer = new AssetTransfer(); - await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue); - - try { - await assetTransfer.ReadAsset(transactionContext, 'asset2'); - assert.fail('ReadAsset should have failed'); - } catch (err) { - expect(err.message).to.equal('The asset asset2 does not exist'); - } - }); - - it('should return success on ReadAsset', async () => { - let assetTransfer = new AssetTransfer(); - await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue); - const assetString = await assetTransfer.ReadAsset(transactionContext, 'asset1'); - const readAsset = JSON.parse(assetString); - expect(readAsset).to.eql(asset); - }); - - it('should return success on ReadAsset with private data', async () => { - asset.asset_properties = asset_properties; - let assetTransfer = new AssetTransfer(); - await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue); - chaincodeStub.getPrivateData.returns(Buffer.from(JSON.stringify(asset_properties))); - const assetString = await assetTransfer.ReadAsset(transactionContext, 'asset1'); - const readAsset = JSON.parse(assetString); - expect(readAsset).to.eql(asset); - }); - }); - - describe('Test UpdateAsset', () => { - it('should return error on UpdateAsset', async () => { - let assetTransfer = new AssetTransfer(); - await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue); - - try { - await assetTransfer.UpdateAsset(transactionContext, 'asset2', 'orange', 10, 'Me', 500); - assert.fail('UpdateAsset should have failed'); - } catch (err) { - expect(err.message).to.equal('The asset asset2 does not exist'); - } - }); - - it('should return success on UpdateAsset', async () => { - let assetTransfer = new AssetTransfer(); - await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue); - - await assetTransfer.UpdateAsset(transactionContext, 'asset1', 'orange', 10, 'Me', 500); - let ret = JSON.parse(await chaincodeStub.getState(asset.ID)); - let expected = { - ID: 'asset1', - Color: 'orange', - Size: 10, - Owner: 'Me', - AppraisedValue: 500 - }; - expect(ret).to.eql(expected); - }); - }); - - describe('Test DeleteAsset', () => { - it('should return error on DeleteAsset', async () => { - let assetTransfer = new AssetTransfer(); - await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue); - - try { - await assetTransfer.DeleteAsset(transactionContext, 'asset2'); - assert.fail('DeleteAsset should have failed'); - } catch (err) { - expect(err.message).to.equal('The asset asset2 does not exist'); - } - }); - - it('should return success on DeleteAsset', async () => { - let assetTransfer = new AssetTransfer(); - await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue); - - await assetTransfer.DeleteAsset(transactionContext, asset.ID); - let ret = await chaincodeStub.getState(asset.ID); - expect(ret).to.equal(undefined); - }); - }); - - describe('Test TransferAsset', () => { - it('should return error on TransferAsset', async () => { - let assetTransfer = new AssetTransfer(); - await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue); - - try { - await assetTransfer.TransferAsset(transactionContext, 'asset2', 'Me'); - assert.fail('DeleteAsset should have failed'); - } catch (err) { - expect(err.message).to.equal('The asset asset2 does not exist'); - } - }); - - it('should return success on TransferAsset', async () => { - let assetTransfer = new AssetTransfer(); - await assetTransfer.CreateAsset(transactionContext, asset.ID, asset.Color, asset.Size, asset.Owner, asset.AppraisedValue); - - await assetTransfer.TransferAsset(transactionContext, asset.ID, 'Me'); - let ret = JSON.parse((await chaincodeStub.getState(asset.ID)).toString()); - expect(ret).to.eql(Object.assign({}, asset, {Owner: 'Me'})); - }); - }); -}); diff --git a/auction-dutch/README.md b/auction-dutch/README.md deleted file mode 100644 index 12d79b1a..00000000 --- a/auction-dutch/README.md +++ /dev/null @@ -1,615 +0,0 @@ -## Dutch auction - -This example allows you to run a [Dutch auction](https://en.wikipedia.org/wiki/Dutch_auction) that sells multiple items of the same good. All items are sold at the price that clears the auction. You also have the option of adding an auditor organization to the auction. If the organizations running the auction cannot agree, or encounter a technical error that prevents them from updating the auction, one of the auction participants can appeal to an auditor organization. The dutch auction smart contract provides an example of how create a complex signature policy by creating a protobuf and then using the policy for state based endorsement. - -This tutorial uses the example smart contract to run an auction in which a single seller wants to sell 100 tickets to multiple bidders. If you chose to add an auditor to the auction, you can appeal to the auditor to end the auction by overriding the standard auction endorsement policy. - -## Deploy the chaincode - -Change into the test network directory. -``` -cd fabric-samples/test-network -``` - -If the test network is already running, run the following command to bring the network down and start from a clean initial state. -``` -./network.sh down -``` - -You can then run the following command to deploy a new network. -``` -./network.sh up createChannel -ca -``` - -Run the following command to deploy the dutch auction smart contract. -``` -./network.sh deployCC -ccn auction -ccp ../auction-dutch/chaincode-go/ -ccep "OR('Org1MSP.peer','Org2MSP.peer')" -ccl go -``` - -Note that we deploy the smart contract with an endorsement policy of `"OR('Org1MSP.peer','Org2MSP.peer')" ` instead of using the default endorsement policy of the majority of orgs on the channel. Either Org1 or Org2 can create an auction without the endorsement of the other organization. - -## Add an auditor (optional) - -The smart contract allows you to add an auditor organization to the auction. The auditor can add bids, close the auction, or end the auction if participants cannot cooperate. In this tutorial, we will add the Org3 organization to the test network channel and install an auditor specific version of the dutch auction smart contract. This allows you to use Org3 as the auditor organization. - -From the `test-network` directory, issue the following commands to add Org3 to the channel: - -``` -cd addOrg3 -./addOrg3.sh up -``` - -Navigate back to the test network directory: -``` -cd .. -``` - -Set the following environment to interact with the test network as Org3. -``` -export PATH=${PWD}/../bin:$PATH -export FABRIC_CFG_PATH=${PWD}/../config/ -export CORE_PEER_TLS_ENABLED=true -export CORE_PEER_LOCALMSPID=Org3MSP -export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt -export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org3.example.com/users/Admin@org3.example.com/msp -export CORE_PEER_ADDRESS=localhost:11051 -``` - -To deploy the smart contract on the Org3 peer, we need to use the peer lifecycle chaincode commands to install the chaincode package and approve the chaincode definition as Org3. Run the following command to package the auditor version of the dutch auction smart contract: -``` -peer lifecycle chaincode package auction.tar.gz --path ../auction-dutch/chaincode-go-auditor/ --lang golang --label auction_1 -``` -Install the chaincode package on the Org3 peer: -``` -peer lifecycle chaincode install auction.tar.gz -``` - -The next step is to approve the chaincode as the Org3 admin. This requires getting the package ID of the chaincode that we just installed. -``` -peer lifecycle chaincode queryinstalled -``` - -The command should return a response similar to the following: -``` -Installed chaincodes on peer: -Package ID: auction_1:8f0d6b6b5a616a1c2b6a9268418f2ee65718acc3c07ea12e123b189b3fb4fb14, Label: auction_1 -``` - -Save the package ID returned by the command above as an environment variable. The package ID will not be the same for all users, so you need to complete this step using the package ID returned from your console. -``` -export CC_PACKAGE_ID=auction_1:8f0d6b6b5a616a1c2b6a9268418f2ee65718acc3c07ea12e123b189b3fb4fb14 -``` - -You can now approve the auction chaincode for Org3: -``` -peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" --channelID mychannel --name auction --version 1.0 --package-id $CC_PACKAGE_ID --sequence 1 --signature-policy "OR('Org1MSP.peer','Org2MSP.peer')" -``` - -The command will start the dutch auction chaincode on the Org3 peer. Note that we did not update the endorsement policy before we added the auditor organization. Only Org1 and Org2 will be able create an auction. The auditor is added the endorsement policy after the auction is created. Because the auditor does not need to create an auction or create new bids, the auditor can run a different version of the smart contract than the auction participants. The auditor version of the smart contract also adds logic to check that the request is submitted by one of the auction participants before the auditor can intervene. - -## Install the application dependencies - -We will run the dutch auction using a series of Node.js applications. Change into the `application-javascript` directory: -``` -cd fabric-samples/auction-dutch/application-javascript -``` - -From this directory, run the following command to download the application dependencies if you have not done so already: -``` -npm install -``` - -## Register and enroll the application identities - -To interact with the network, you will need to enroll the Certificate Authority administrators of Org1 and Org2. You can use the `enrollAdmin.js` program for this task. Run the following command to enroll the Org1 admin: -``` -node enrollAdmin.js org1 -``` -You should see the logs of the admin wallet being created on your local file system. Now run the command to enroll the CA admin of Org2: -``` -node enrollAdmin.js org2 -``` - -We can use the CA admins of both organizations to register and enroll the identities of the seller that will create the auction and the bidders who will try to purchase the tickets. Run the following command to register and enroll the seller identity that will create the auction. The seller will belong to Org1. -``` -node registerEnrollUser.js org1 seller -``` - -You should see the logs of the seller wallet being created as well. Run the following commands to register and enroll two bidders from Org1 and another three bidders from Org2: -``` -node registerEnrollUser.js org1 bidder1 -node registerEnrollUser.js org1 bidder2 -node registerEnrollUser.js org2 bidder3 -node registerEnrollUser.js org2 bidder4 -node registerEnrollUser.js org2 bidder5 -``` - -## Create the auction - -The seller from Org1 would like to create an auction to sell 100 tickets. Run the following command to use the seller wallet to run the `createAuction.js` application. The seller needs to provide an auction ID, the item to be sold, and the quantity to be sold to create the auction. The seller uses `withAuditor` to indicate that Org3 will be added as the auditor organization. If you do not want to add an auditor, you can provide a value of `noAuditor`. You will see the application query the auction after it is created. -``` -node createAuction.js org1 seller auction1 tickets 100 withAuditor -``` - -Adding an auditor to the auction creates an endorsement policy with the auditor included. Without the auditor, each organization with sellers or bidders participating in the auction is added to the auction endorsement policy. For example, if the auction had two organizations participating in the auction, the auction endorsement policy would be `AND(Org1, Org2)`. However, if the selling organization decides to add an auditor, the auditor organization would be added to the endorsement policy. If the participating organizations disagree, or if a participant has a technical problem, the auditor can join any one of the participating organizations and agree to update the auction. Extending the example above, if the auction with two organizations added an auditor, the auction endorsement policy would be `OR(AND(Org1, Org2), AND(auditor, OR(Org1, Org2)))`. - -## Bid on the auction - -We can now use the bidder wallets to submit bids to the auction: - -### Bid as bidder1 - -Bidder1 will create a bid to purchase 50 tickets for 80 dollars. -``` -node bid.js org1 bidder1 auction1 50 80 -``` - -The application will query the bid after it is created: -``` -*** Result: Bid: { - "objectType": "bid", - "quantity": 50, - "price": 80, - "org": "Org1MSP", - "buyer": "x509::CN=bidder1,OU=client+OU=org1+OU=department1::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US" -} -``` - -The `bid.js` application also prints the bidID: -``` -*** Result ***SAVE THIS VALUE*** BidID: 6630e1bb06e827a2b77023f63677fae8a0ad43126730e450d3252fa58eeb85b1 -``` - -The BidID acts as the unique identifier for the bid. This ID allows you to query the bid using the `queryBid.js` program and add the bid to the auction. Save the bidID returned by the application as an environment variable in your terminal: -``` -export BIDDER1_BID_ID=6630e1bb06e827a2b77023f63677fae8a0ad43126730e450d3252fa58eeb85b1 -``` -This value will be different for each transaction, so you will need to use the value returned in your terminal. - -Now that the bid has been created, you can submit the bid to the auction. Run the following command to submit the bid that was just created: -``` -node submitBid.js org1 bidder1 auction1 $BIDDER1_BID_ID -``` - -The hash of bid is added to the list of private bids in that have been submitted to `auction1`. Storing the hash on the public auction ledger allows users to prove the accuracy of the bids they reveal once bidding is closed. The application queries the auction to verify that the bid was added: -``` -*** Result: Auction: { - "objectType": "auction", - "item": "tickets", - "seller": "x509::CN=seller,OU=client+OU=org1+OU=department1::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US", - "quantity": 100, - "organizations": [ - "Org1MSP" - ], - "privateBids": { - "\u0000bid\u0000auction1\u00006630e1bb06e827a2b77023f63677fae8a0ad43126730e450d3252fa58eeb85b1\u0000": { - "org": "Org1MSP", - "hash": "2f7a62152627d69d73e31b62cd4731d32ecc277de0eef4d30b1235891298abf7" - } - }, - "revealedBids": {}, - "winners": [], - "price": 0, - "status": "open", - "auditor": true -} -``` - -### Bid as bidder2 - -Let's submit another bid. Bidder2 would like to purchase 40 tickets for 50 dollars. -``` -node bid.js org1 bidder2 auction1 40 50 -``` - -Save the Bid ID returned by the application: -``` -export BIDDER2_BID_ID=5796569dae2e95242eadc5cf1cf8aa24f5ae072d801e7decb2547530de5a65e8 -``` - -Submit bidder2's bid to the auction: -``` -node submitBid.js org1 bidder2 auction1 $BIDDER2_BID_ID -``` - -### Bid as bidder3 from Org2 - -Bidder3 will bid for 30 tickets at 70 dollars: -``` -node bid.js org2 bidder3 auction1 30 70 -``` - -Save the Bid ID returned by the application: -``` -export BIDDER3_BID_ID=d52ea4d9b4bc428d395db2d68323bc12cc9b5c1f8617900f459ccd41c38d3c0a -``` - -Add bidder3's bid to the auction: -``` -node submitBid.js org2 bidder3 auction1 $BIDDER3_BID_ID -``` - -Because bidder3 belongs to Org2, submitting the bid will add Org2 to the list of participating organizations. You can see the Org2 MSP ID has been added to the list of `"organizations"` in the updated auction returned by the application: -``` -*** Result: Auction: { - "objectType": "auction", - "item": "tickets", - "seller": "x509::CN=seller,OU=client+OU=org1+OU=department1::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US", - "quantity": 100, - "organizations": [ - "Org1MSP", - "Org2MSP" - ], - "privateBids": { - "\u0000bid\u0000auction1\u00005796569dae2e95242eadc5cf1cf8aa24f5ae072d801e7decb2547530de5a65e8\u0000": { - "org": "Org1MSP", - "hash": "598749480aa3af816a829455e1fdac25a44f31c2ae81f911f85d004f44dbbe6c" - }, - "\u0000bid\u0000auction1\u00006630e1bb06e827a2b77023f63677fae8a0ad43126730e450d3252fa58eeb85b1\u0000": { - "org": "Org1MSP", - "hash": "2f7a62152627d69d73e31b62cd4731d32ecc277de0eef4d30b1235891298abf7" - }, - "\u0000bid\u0000auction1\u0000d52ea4d9b4bc428d395db2d68323bc12cc9b5c1f8617900f459ccd41c38d3c0a\u0000": { - "org": "Org2MSP", - "hash": "bf1e9fb80ea3e29780fe13b4781b6dad28fa83b4b5db68bd7e90252875d152fb" - } - }, - "revealedBids": {}, - "winners": [], - "price": 0, - "status": "open", - "auditor": true -} -``` - -Now that a bid from Org2 has been added to the auction, any updates to the auction need to be endorsed by the Org2 peer. The applications will use the `"organizations"` field to specify which organizations need to endorse submitting a new bid, revealing a bid, or updating the auction status. - -### Bid as bidder4 - -Bidder4 from Org2 would like to purchase 15 tickets for 60 dollars: -``` -node bid.js org2 bidder4 auction1 15 60 -``` - -Save the Bid ID returned by the application: -``` -export BIDDER4_BID_ID=c6464f984bb01e639a46e58b94c496e8bbd829b5e4fa7ffcc150d9a565d45684 -``` - -Add bidder4's bid to the auction: -``` -node submitBid.js org2 bidder4 auction1 $BIDDER4_BID_ID -``` - -### Bid as bidder5 - -Bidder5 from Org2 will bid for 20 tickets at 60 dollars: -``` -node bid.js org2 bidder5 auction1 20 60 -``` - -Save the Bid ID returned by the application: -``` -export BIDDER5_BID_ID=f4024ab09b4dacf0a636927414850dde2a2a5e8ec4601e2a0071f5c233248207 -``` - -Add bidder5's bid to the auction: -``` -node submitBid.js org2 bidder5 auction1 $BIDDER5_BID_ID -``` - - -## Close the auction - -Now that all five bidders have joined the auction, the seller would like to close the auction and allow buyers to reveal their bids. The seller identity that created the auction needs to submit the transaction: -``` -node closeAuction.js org1 seller auction1 -``` - -The application will query the auction to allow you to verify that the auction status has changed to closed. - -## Reveal bids - -After the auction is closed, bidders can try to win the auction by revealing their bids. The transaction to reveal a bid needs to pass four checks: -1. The auction is closed. -2. The transaction was submitted by the identity that created the bid. -3. The hash of the revealed bid matches the hash of the bid on the channel ledger. This confirms that the bid is the same as the bid that is stored in the private data collection. -4. The hash of the revealed bid matches the hash that was submitted to the auction. This confirms that the bid was not altered after the auction was closed. - -Use the `revealBid.js` application to reveal the bid of Bidder1: -``` -node revealBid.js org1 bidder1 auction1 $BIDDER1_BID_ID -``` - -The full bid details, including the quantity and price, are now visible: -``` -*** Result: Auction: { - "objectType": "auction", - "item": "tickets", - "seller": "x509::CN=seller,OU=client+OU=org1+OU=department1::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US", - "quantity": 100, - "organizations": [ - "Org1MSP", - "Org2MSP" - ], - "privateBids": { - "\u0000bid\u0000auction1\u00005796569dae2e95242eadc5cf1cf8aa24f5ae072d801e7decb2547530de5a65e8\u0000": { - "org": "Org1MSP", - "hash": "598749480aa3af816a829455e1fdac25a44f31c2ae81f911f85d004f44dbbe6c" - }, - "\u0000bid\u0000auction1\u00006630e1bb06e827a2b77023f63677fae8a0ad43126730e450d3252fa58eeb85b1\u0000": { - "org": "Org1MSP", - "hash": "2f7a62152627d69d73e31b62cd4731d32ecc277de0eef4d30b1235891298abf7" - }, - "\u0000bid\u0000auction1\u0000c6464f984bb01e639a46e58b94c496e8bbd829b5e4fa7ffcc150d9a565d45684\u0000": { - "org": "Org2MSP", - "hash": "eefcadf8e9e5cb8322a6e642ab6d5512d62e6d68f37a72b00f5b0d9e580eddb9" - }, - "\u0000bid\u0000auction1\u0000d52ea4d9b4bc428d395db2d68323bc12cc9b5c1f8617900f459ccd41c38d3c0a\u0000": { - "org": "Org2MSP", - "hash": "bf1e9fb80ea3e29780fe13b4781b6dad28fa83b4b5db68bd7e90252875d152fb" - }, - "\u0000bid\u0000auction1\u0000f4024ab09b4dacf0a636927414850dde2a2a5e8ec4601e2a0071f5c233248207\u0000": { - "org": "Org2MSP", - "hash": "de82232141bac06ea3818146fb650dc9930d45b9ceab506ac66942b119eec094" - } - }, - "revealedBids": { - "\u0000bid\u0000auction1\u00006630e1bb06e827a2b77023f63677fae8a0ad43126730e450d3252fa58eeb85b1\u0000": { - "objectType": "bid", - "quantity": 50, - "price": 80, - "org": "Org1MSP", - "buyer": "x509::CN=bidder1,OU=client+OU=org1+OU=department1::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US" - } - }, - "winners": [], - "price": 0, - "status": "closed", - "auditor": true -} -``` -We will add three more bidders, the second bidder from Org1 and two bidders from Org2. Run the following commands to reveal the bidders: -``` -node revealBid.js org1 bidder2 auction1 $BIDDER2_BID_ID -node revealBid.js org2 bidder4 auction1 $BIDDER4_BID_ID -node revealBid.js org2 bidder5 auction1 $BIDDER5_BID_ID -``` - -Let's try to end the auction using the seller identity and see what happens. - -``` -node endAuction.js org1 seller auction1 -``` - -The output should look something like the following: - -``` ---> Submit the transaction to end the auction -2021-01-28T16:47:27.501Z - error: [DiscoveryHandler]: compareProposalResponseResults[undefined] - read/writes result sets do not match index=1 -2021-01-28T16:47:27.503Z - error: [Transaction]: Error: No valid responses from any peers. Errors: - peer=undefined, status=grpc, message=Peer endorsements do not match -******** FAILED to submit bid: Error: No valid responses from any peers. Errors: - peer=undefined, status=grpc, message=Peer endorsements do not match -``` - -Instead of ending the auction, the transaction results in an endorsement policy failure. The end of the auction needs to be endorsed by Org2. Before endorsing the transaction, the Org2 peer queries its private data collection for any winning bids that have not yet been revealed. Because the price that would clear the auction with the currently revealed bids is lower than the bid of Bidder3, the Org2 peer refuses to endorse the transaction that would end the auction. - -In order to end the auction, Org1 would either need to wait for Org2 to reveal the final bid or appeal to the auditor. Depending on if you created the organization with an auditor, you can end the auction with either set of steps. - -## End the auction using an auditor - -If Org2 is unable to endorse the transaction to end the auction, Org1 can ask the auditor to intervene. The following program gets an endorsement from the Org3 auditor and Org1 to end the auction. As a result, the transaction would meet the auditor component of the state based endorsement policy. -``` -node endAuctionwithAuditor org1 seller auction1 -``` - -Even though Org2 has not agreed to the end of the auction, the endorsement Org1 is sufficient to end the auction if the auditor agrees. As part of ending the auction, both Org1 and the auditor need to calculate the same price and the same set of winners. Each winning bidder is listed next to the quantity that was allocated to them. -``` -*** Result: Auction: { - "objectType": "auction", - "item": "tickets", - "seller": "x509::CN=seller,OU=client+OU=org1+OU=department1::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US", - "quantity": 100, - "organizations": [ - "Org1MSP", - "Org2MSP" - ], - "privateBids": { - "\u0000bid\u0000auction1\u00005796569dae2e95242eadc5cf1cf8aa24f5ae072d801e7decb2547530de5a65e8\u0000": { - "org": "Org1MSP", - "hash": "598749480aa3af816a829455e1fdac25a44f31c2ae81f911f85d004f44dbbe6c" - }, - "\u0000bid\u0000auction1\u00006630e1bb06e827a2b77023f63677fae8a0ad43126730e450d3252fa58eeb85b1\u0000": { - "org": "Org1MSP", - "hash": "2f7a62152627d69d73e31b62cd4731d32ecc277de0eef4d30b1235891298abf7" - }, - "\u0000bid\u0000auction1\u0000c6464f984bb01e639a46e58b94c496e8bbd829b5e4fa7ffcc150d9a565d45684\u0000": { - "org": "Org2MSP", - "hash": "eefcadf8e9e5cb8322a6e642ab6d5512d62e6d68f37a72b00f5b0d9e580eddb9" - }, - "\u0000bid\u0000auction1\u0000d52ea4d9b4bc428d395db2d68323bc12cc9b5c1f8617900f459ccd41c38d3c0a\u0000": { - "org": "Org2MSP", - "hash": "bf1e9fb80ea3e29780fe13b4781b6dad28fa83b4b5db68bd7e90252875d152fb" - }, - "\u0000bid\u0000auction1\u0000f4024ab09b4dacf0a636927414850dde2a2a5e8ec4601e2a0071f5c233248207\u0000": { - "org": "Org2MSP", - "hash": "de82232141bac06ea3818146fb650dc9930d45b9ceab506ac66942b119eec094" - } - }, - "revealedBids": { - "\u0000bid\u0000auction1\u00005796569dae2e95242eadc5cf1cf8aa24f5ae072d801e7decb2547530de5a65e8\u0000": { - "objectType": "bid", - "quantity": 40, - "price": 50, - "org": "Org1MSP", - "buyer": "x509::CN=bidder2,OU=client+OU=org1+OU=department1::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US" - }, - "\u0000bid\u0000auction1\u00006630e1bb06e827a2b77023f63677fae8a0ad43126730e450d3252fa58eeb85b1\u0000": { - "objectType": "bid", - "quantity": 50, - "price": 80, - "org": "Org1MSP", - "buyer": "x509::CN=bidder1,OU=client+OU=org1+OU=department1::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US" - }, - "\u0000bid\u0000auction1\u0000c6464f984bb01e639a46e58b94c496e8bbd829b5e4fa7ffcc150d9a565d45684\u0000": { - "objectType": "bid", - "quantity": 15, - "price": 60, - "org": "Org2MSP", - "buyer": "x509::CN=bidder4,OU=client+OU=org2+OU=department1::CN=ca.org2.example.com,O=org2.example.com,L=Hursley,ST=Hampshire,C=UK" - }, - "\u0000bid\u0000auction1\u0000f4024ab09b4dacf0a636927414850dde2a2a5e8ec4601e2a0071f5c233248207\u0000": { - "objectType": "bid", - "quantity": 20, - "price": 60, - "org": "Org2MSP", - "buyer": "x509::CN=bidder5,OU=client+OU=org2+OU=department1::CN=ca.org2.example.com,O=org2.example.com,L=Hursley,ST=Hampshire,C=UK" - } - }, - "winners": [ - { - "buyer": "x509::CN=bidder1,OU=client+OU=org1+OU=department1::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US", - "quantity": 50 - }, - { - "buyer": "x509::CN=bidder4,OU=client+OU=org2+OU=department1::CN=ca.org2.example.com,O=org2.example.com,L=Hursley,ST=Hampshire,C=UK", - "quantity": 15 - }, - { - "buyer": "x509::CN=bidder5,OU=client+OU=org2+OU=department1::CN=ca.org2.example.com,O=org2.example.com,L=Hursley,ST=Hampshire,C=UK", - "quantity": 20 - }, - { - "buyer": "x509::CN=bidder2,OU=client+OU=org1+OU=department1::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US", - "quantity": 15 - } - ], - "price": 50, - "status": "ended", - "auditor": true -} -``` - -The auction allocates tickets to the highest bids first. Because all 100 tickets are sold after allocating tickets to the bid that was submitted at 50, 50 is the `"price"` that clears the auction. - -## End the auction without an auditor - -If we did not add an auditor to the auction, we need to add the remaining bid so that Org2 will endorse ending the auction. -``` -node revealBid.js org2 bidder3 auction1 $BIDDER3_BID_ID -``` - -Now that all the winning bids have been revealed, we can submit the transaction to end the auction once more. -``` -node endAuction org1 seller auction1 -``` - -The transaction was successfully endorsed by both Org1 and Org2, who both calculated the same price and winners of the auction. Each winning bidder is listed next to the quantity that was allocated to them. -``` -*** Result: Auction: { - "objectType": "auction", - "item": "tickets", - "seller": "x509::CN=seller,OU=client+OU=org1+OU=department1::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US", - "quantity": 100, - "organizations": [ - "Org1MSP", - "Org2MSP" - ], - "privateBids": { - "\u0000bid\u0000auction1\u0000482b2a68fbbfae329b0b4bc9d70b90f3a55fdcbae5f5274dec34d438efb6847e\u0000": { - "org": "Org1MSP", - "hash": "2f7a62152627d69d73e31b62cd4731d32ecc277de0eef4d30b1235891298abf7" - }, - "\u0000bid\u0000auction1\u000048d93017ac65cff0dd23406cc29918724fd84c8e7014eee30fd492fef760e6a4\u0000": { - "org": "Org2MSP", - "hash": "bf1e9fb80ea3e29780fe13b4781b6dad28fa83b4b5db68bd7e90252875d152fb" - }, - "\u0000bid\u0000auction1\u00005ba4c856224cdc8209b0e42f30a757331e3fb8a8b660b64a55e1bcf688b745ad\u0000": { - "org": "Org1MSP", - "hash": "598749480aa3af816a829455e1fdac25a44f31c2ae81f911f85d004f44dbbe6c" - }, - "\u0000bid\u0000auction1\u000063c8a192dae1332ae42af890f8a966fea2ae8365ca9746447e014a7c0494d64e\u0000": { - "org": "Org2MSP", - "hash": "de82232141bac06ea3818146fb650dc9930d45b9ceab506ac66942b119eec094" - }, - "\u0000bid\u0000auction1\u000066ff6d8bbe81e98654fc417915808031d49e93cd8d7475f15317d801317254fa\u0000": { - "org": "Org2MSP", - "hash": "eefcadf8e9e5cb8322a6e642ab6d5512d62e6d68f37a72b00f5b0d9e580eddb9" - } - }, - "revealedBids": { - "\u0000bid\u0000auction1\u0000482b2a68fbbfae329b0b4bc9d70b90f3a55fdcbae5f5274dec34d438efb6847e\u0000": { - "objectType": "bid", - "quantity": 50, - "price": 80, - "org": "Org1MSP", - "buyer": "x509::CN=bidder1,OU=client+OU=org1+OU=department1::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US" - }, - "\u0000bid\u0000auction1\u000048d93017ac65cff0dd23406cc29918724fd84c8e7014eee30fd492fef760e6a4\u0000": { - "objectType": "bid", - "quantity": 30, - "price": 70, - "org": "Org2MSP", - "buyer": "x509::CN=bidder3,OU=client+OU=org2+OU=department1::CN=ca.org2.example.com,O=org2.example.com,L=Hursley,ST=Hampshire,C=UK" - }, - "\u0000bid\u0000auction1\u00005ba4c856224cdc8209b0e42f30a757331e3fb8a8b660b64a55e1bcf688b745ad\u0000": { - "objectType": "bid", - "quantity": 40, - "price": 50, - "org": "Org1MSP", - "buyer": "x509::CN=bidder2,OU=client+OU=org1+OU=department1::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US" - }, - "\u0000bid\u0000auction1\u000063c8a192dae1332ae42af890f8a966fea2ae8365ca9746447e014a7c0494d64e\u0000": { - "objectType": "bid", - "quantity": 20, - "price": 60, - "org": "Org2MSP", - "buyer": "x509::CN=bidder5,OU=client+OU=org2+OU=department1::CN=ca.org2.example.com,O=org2.example.com,L=Hursley,ST=Hampshire,C=UK" - }, - "\u0000bid\u0000auction1\u000066ff6d8bbe81e98654fc417915808031d49e93cd8d7475f15317d801317254fa\u0000": { - "objectType": "bid", - "quantity": 15, - "price": 60, - "org": "Org2MSP", - "buyer": "x509::CN=bidder4,OU=client+OU=org2+OU=department1::CN=ca.org2.example.com,O=org2.example.com,L=Hursley,ST=Hampshire,C=UK" - } - }, - "winners": [ - { - "buyer": "x509::CN=bidder1,OU=client+OU=org1+OU=department1::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US", - "quantity": 50 - }, - { - "buyer": "x509::CN=bidder3,OU=client+OU=org2+OU=department1::CN=ca.org2.example.com,O=org2.example.com,L=Hursley,ST=Hampshire,C=UK", - "quantity": 30 - }, - { - "buyer": "x509::CN=bidder4,OU=client+OU=org2+OU=department1::CN=ca.org2.example.com,O=org2.example.com,L=Hursley,ST=Hampshire,C=UK", - "quantity": 15 - }, - { - "buyer": "x509::CN=bidder5,OU=client+OU=org2+OU=department1::CN=ca.org2.example.com,O=org2.example.com,L=Hursley,ST=Hampshire,C=UK", - "quantity": 5 - } - ], - "price": 60, - "status": "ended", - "auditor": false -} -``` - -The auction allocates tickets to the highest bids first. Because all 100 tickets are sold after allocating tickets to the bids that were submitted at 60, 60 is the `"price"` that clears the auction. The first 80 tickets are allocated to Bidder1 and Bidder3. The remaining 20 tickers are allocated to Bidder4 and Bidder5. When bids are tied, the auction smart contract fills the smaller bids first. As a result, Bidder4 is awarded their full bid of 15 tickets, while Bidder5 is allocated the remaining 5 tickets. - -## Clean up - -When your are done using the auction smart contract, you can bring down the network and clean up the environment. In the `auction-dutch/application-javascript` directory, run the following command to remove the wallets used to run the applications: -``` -rm -rf wallet -``` - -You can then navigate to the test network directory and bring down the network: -```` -cd ../../test-network/ -./network.sh down -```` diff --git a/auction-dutch/application-javascript/.eslintignore b/auction-dutch/application-javascript/.eslintignore deleted file mode 100644 index 15958470..00000000 --- a/auction-dutch/application-javascript/.eslintignore +++ /dev/null @@ -1,5 +0,0 @@ -# -# SPDX-License-Identifier: Apache-2.0 -# - -coverage diff --git a/auction-dutch/application-javascript/.eslintrc.js b/auction-dutch/application-javascript/.eslintrc.js deleted file mode 100644 index 20d4fcbd..00000000 --- a/auction-dutch/application-javascript/.eslintrc.js +++ /dev/null @@ -1,36 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ - -module.exports = { - env: { - node: true, - mocha: true - }, - parserOptions: { - ecmaVersion: 8, - sourceType: 'script' - }, - extends: 'eslint:recommended', - rules: { - indent: ['error', 'tab'], - 'linebreak-style': ['error', 'unix'], - quotes: ['error', 'single'], - semi: ['error', 'always'], - 'no-unused-vars': ['error', { args: 'none' }], - 'no-console': 'off', - curly: 'error', - eqeqeq: 'error', - 'no-throw-literal': 'error', - strict: 'error', - 'no-var': 'error', - 'dot-notation': 'error', - 'no-trailing-spaces': 'error', - 'no-use-before-define': 'error', - 'no-useless-call': 'error', - 'no-with': 'error', - 'operator-linebreak': 'error', - yoda: 'error', - 'quote-props': ['error', 'as-needed'] - } -}; diff --git a/auction-dutch/application-javascript/bid.js b/auction-dutch/application-javascript/bid.js deleted file mode 100644 index aff30d65..00000000 --- a/auction-dutch/application-javascript/bid.js +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const { Gateway, Wallets } = require('fabric-network'); -const path = require('path'); -const { buildCCPOrg1, buildCCPOrg2, buildWallet, prettyJSONString } = require('../../test-application/javascript/AppUtil.js'); - -const myChannel = 'mychannel'; -const myChaincodeName = 'auction'; - -async function bid (ccp, wallet, user, orgMSP, auctionID, quantity, price) { - try { - const gateway = new Gateway(); - // connect using Discovery enabled - - await gateway.connect(ccp, - { wallet: wallet, identity: user, discovery: { enabled: true, asLocalhost: true } }); - - const network = await gateway.getNetwork(myChannel); - const contract = network.getContract(myChaincodeName); - - console.log('\n--> Evaluate Transaction: get your client ID'); - const buyer = await contract.evaluateTransaction('GetSubmittingClientIdentity'); - console.log('*** Result: Buyer ID is ' + buyer.toString()); - - const bidData = { objectType: 'bid', quantity: parseInt(quantity), price: parseInt(price), org: orgMSP, buyer: buyer.toString() }; - - const statefulTxn = contract.createTransaction('Bid'); - statefulTxn.setEndorsingOrganizations(orgMSP); - const tmapData = Buffer.from(JSON.stringify(bidData)); - statefulTxn.setTransient({ - bid: tmapData - }); - - const bidID = statefulTxn.getTransactionId(); - - console.log('\n--> Submit Transaction: Create the bid that is stored in your private data collection of your organization'); - await statefulTxn.submit(auctionID); - console.log('*** Result: committed'); - console.log('*** Result ***SAVE THIS VALUE*** BidID: ' + bidID.toString()); - - console.log('\n--> Evaluate Transaction: read the bid that was just created'); - const result = await contract.evaluateTransaction('QueryBid', auctionID, bidID); - console.log('*** Result: Bid: ' + prettyJSONString(result.toString())); - - gateway.disconnect(); - } catch (error) { - console.error(`******** FAILED to submit bid: ${error}`); - if (error.stack) { - console.error(error.stack); - } - process.exit(1); - } -} - -async function main () { - try { - if (process.argv[2] === undefined || process.argv[3] === undefined || - process.argv[4] === undefined || process.argv[5] === undefined || - process.argv[6] === undefined) { - console.log('Usage: node bid.js org userID auctionID quantity price'); - process.exit(1); - } - - const org = process.argv[2]; - const user = process.argv[3]; - const auctionID = process.argv[4]; - const quantity = process.argv[5]; - const price = process.argv[6]; - - if (org === 'Org1' || org === 'org1') { - const orgMSP = 'Org1MSP'; - const ccp = buildCCPOrg1(); - const walletPath = path.join(__dirname, 'wallet/org1'); - const wallet = await buildWallet(Wallets, walletPath); - await bid(ccp, wallet, user, orgMSP, auctionID, quantity, price); - } else if (org === 'Org2' || org === 'org2') { - const orgMSP = 'Org2MSP'; - const ccp = buildCCPOrg2(); - const walletPath = path.join(__dirname, 'wallet/org2'); - const wallet = await buildWallet(Wallets, walletPath); - await bid(ccp, wallet, user, orgMSP, auctionID, quantity, price); - } else { - console.log('Usage: node bid.js org userID auctionID quantity price'); - console.log('Org must be Org1 or Org2'); - } - } catch (error) { - console.error(`******** FAILED to run the application: ${error}`); - process.exit(1); - } -} - -main(); diff --git a/auction-dutch/application-javascript/closeAuction.js b/auction-dutch/application-javascript/closeAuction.js deleted file mode 100644 index 55410fb5..00000000 --- a/auction-dutch/application-javascript/closeAuction.js +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const { Gateway, Wallets } = require('fabric-network'); -const path = require('path'); -const { buildCCPOrg1, buildCCPOrg2, buildWallet, prettyJSONString } = require('../../test-application/javascript/AppUtil.js'); - -const myChannel = 'mychannel'; -const myChaincodeName = 'auction'; - -async function closeAuction (ccp, wallet, user, auctionID) { - try { - const gateway = new Gateway(); - // connect using Discovery enabled - - await gateway.connect(ccp, - { wallet: wallet, identity: user, discovery: { enabled: true, asLocalhost: true } }); - - const network = await gateway.getNetwork(myChannel); - const contract = network.getContract(myChaincodeName); - - // Query the auction to get the list of endorsing orgs. - // console.log('\n--> Evaluate Transaction: query the auction you want to close'); - const auctionString = await contract.evaluateTransaction('QueryAuction', auctionID); - // console.log('*** Result: Bid: ' + prettyJSONString(auctionString.toString())); - const auctionJSON = JSON.parse(auctionString); - - const statefulTxn = contract.createTransaction('CloseAuction'); - - if (auctionJSON.organizations.length === 2) { - statefulTxn.setEndorsingOrganizations(auctionJSON.organizations[0], auctionJSON.organizations[1]); - } else { - statefulTxn.setEndorsingOrganizations(auctionJSON.organizations[0]); - } - - console.log('\n--> Submit Transaction: close auction'); - await statefulTxn.submit(auctionID); - console.log('*** Result: committed'); - - console.log('\n--> Evaluate Transaction: query the updated auction'); - const result = await contract.evaluateTransaction('QueryAuction', auctionID); - console.log('*** Result: Auction: ' + prettyJSONString(result.toString())); - - gateway.disconnect(); - } catch (error) { - console.error(`******** FAILED to submit bid: ${error}`); - process.exit(1); - } -} - -async function main () { - try { - if (process.argv[2] === undefined || process.argv[3] === undefined || process.argv[4] === undefined) { - console.log('Usage: node closeAuction.js org userID auctionID'); - process.exit(1); - } - - const org = process.argv[2]; - const user = process.argv[3]; - const auctionID = process.argv[4]; - - if (org === 'Org1' || org === 'org1') { - const ccp = buildCCPOrg1(); - const walletPath = path.join(__dirname, 'wallet/org1'); - const wallet = await buildWallet(Wallets, walletPath); - await closeAuction(ccp, wallet, user, auctionID); - } else if (org === 'Org2' || org === 'org2') { - const ccp = buildCCPOrg2(); - const walletPath = path.join(__dirname, 'wallet/org2'); - const wallet = await buildWallet(Wallets, walletPath); - await closeAuction(ccp, wallet, user, auctionID); - } else { - console.log('Usage: node closeAuction.js org userID auctionID'); - console.log('Org must be Org1 or Org2'); - } - } catch (error) { - console.error(`******** FAILED to run the application: ${error}`); - if (error.stack) { - console.error(error.stack); - } - process.exit(1); - } -} - -main(); diff --git a/auction-dutch/application-javascript/createAuction.js b/auction-dutch/application-javascript/createAuction.js deleted file mode 100644 index 2f46a248..00000000 --- a/auction-dutch/application-javascript/createAuction.js +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const { Gateway, Wallets } = require('fabric-network'); -const path = require('path'); -const { buildCCPOrg1, buildCCPOrg2, buildWallet, prettyJSONString } = require('../../test-application/javascript/AppUtil.js'); - -const myChannel = 'mychannel'; -const myChaincodeName = 'auction'; - -async function createAuction (ccp, wallet, user, auctionID, item, quantity, auditor) { - try { - const gateway = new Gateway(); - // connect using Discovery enabled - - await gateway.connect(ccp, - { wallet: wallet, identity: user, discovery: { enabled: true, asLocalhost: true } }); - - const network = await gateway.getNetwork(myChannel); - const contract = network.getContract(myChaincodeName); - - const statefulTxn = contract.createTransaction('CreateAuction'); - - console.log('\n--> Submit Transaction: Propose a new auction'); - await statefulTxn.submit(auctionID, item, parseInt(quantity), auditor); - console.log('*** Result: committed'); - - console.log('\n--> Evaluate Transaction: query the auction that was just created'); - const result = await contract.evaluateTransaction('QueryAuction', auctionID); - console.log('*** Result: Auction: ' + prettyJSONString(result.toString())); - - gateway.disconnect(); - } catch (error) { - console.error(`******** FAILED to submit bid: ${error}`); - } -} - -async function main () { - try { - if (process.argv[2] === undefined || process.argv[3] === undefined || - process.argv[4] === undefined || process.argv[5] === undefined || - process.argv[6] === undefined) { - console.log('Usage: node createAuction.js org userID auctionID item quantity'); - process.exit(1); - } - - const org = process.argv[2]; - const user = process.argv[3]; - const auctionID = process.argv[4]; - const item = process.argv[5]; - const quantity = process.argv[6]; - const auditor = process.argv[7]; - - if (org === 'Org1' || org === 'org1') { - const ccp = buildCCPOrg1(); - const walletPath = path.join(__dirname, 'wallet/org1'); - const wallet = await buildWallet(Wallets, walletPath); - await createAuction(ccp, wallet, user, auctionID, item, quantity, auditor); - } else if (org === 'Org2' || org === 'org2') { - const ccp = buildCCPOrg2(); - const walletPath = path.join(__dirname, 'wallet/org2'); - const wallet = await buildWallet(Wallets, walletPath); - await createAuction(ccp, wallet, user, auctionID, item, quantity, auditor); - } else { - console.log('Usage: node createAuction.js org userID auctionID item quantity'); - console.log('Org must be Org1 or Org2'); - } - } catch (error) { - console.error(`******** FAILED to run the application: ${error}`); - } -} - -main(); diff --git a/auction-dutch/application-javascript/endAuction.js b/auction-dutch/application-javascript/endAuction.js deleted file mode 100644 index daec75d2..00000000 --- a/auction-dutch/application-javascript/endAuction.js +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const { Gateway, Wallets } = require('fabric-network'); -const path = require('path'); -const { buildCCPOrg1, buildCCPOrg2, buildWallet, prettyJSONString } = require('../../test-application/javascript/AppUtil.js'); - -const myChannel = 'mychannel'; -const myChaincodeName = 'auction'; - -async function endAuction (ccp, wallet, user, auctionID) { - try { - const gateway = new Gateway(); - // connect using Discovery enabled - - await gateway.connect(ccp, - { wallet: wallet, identity: user, discovery: { enabled: true, asLocalhost: true } }); - - const network = await gateway.getNetwork(myChannel); - const contract = network.getContract(myChaincodeName); - - // Query the auction to get the list of endorsing orgs. - // console.log('\n--> Evaluate Transaction: query the auction you want to end'); - const auctionString = await contract.evaluateTransaction('QueryAuction', auctionID); - // console.log('*** Result: Bid: ' + prettyJSONString(auctionString.toString())); - const auctionJSON = JSON.parse(auctionString); - - const statefulTxn = contract.createTransaction('EndAuction'); - - if (auctionJSON.organizations.length === 2) { - statefulTxn.setEndorsingOrganizations(auctionJSON.organizations[0], auctionJSON.organizations[1]); - } else { - statefulTxn.setEndorsingOrganizations(auctionJSON.organizations[0]); - } - - console.log('\n--> Submit the transaction to end the auction'); - await statefulTxn.submit(auctionID); - console.log('*** Result: committed'); - - console.log('\n--> Evaluate Transaction: query the updated auction'); - const result = await contract.evaluateTransaction('QueryAuction', auctionID); - console.log('*** Result: Auction: ' + prettyJSONString(result.toString())); - - gateway.disconnect(); - } catch (error) { - console.error(`******** FAILED to submit bid: ${error}`); - process.exit(1); - } -} - -async function main () { - try { - if (process.argv[2] === undefined || process.argv[3] === undefined || - process.argv[4] === undefined) { - console.log('Usage: node endAuction.js org userID auctionID'); - process.exit(1); - } - - const org = process.argv[2]; - const user = process.argv[3]; - const auctionID = process.argv[4]; - - if (org === 'Org1' || org === 'org1') { - const ccp = buildCCPOrg1(); - const walletPath = path.join(__dirname, 'wallet/org1'); - const wallet = await buildWallet(Wallets, walletPath); - await endAuction(ccp, wallet, user, auctionID); - } else if (org === 'Org2' || org === 'org2') { - const ccp = buildCCPOrg2(); - const walletPath = path.join(__dirname, 'wallet/org2'); - const wallet = await buildWallet(Wallets, walletPath); - await endAuction(ccp, wallet, user, auctionID); - } else { - console.log('Usage: node endAuction.js org userID auctionID'); - console.log('Org must be Org1 or Org2'); - } - } catch (error) { - console.error(`******** FAILED to run the application: ${error}`); - if (error.stack) { - console.error(error.stack); - } - process.exit(1); - } -} - -main(); diff --git a/auction-dutch/application-javascript/endAuctionwithAuditor.js b/auction-dutch/application-javascript/endAuctionwithAuditor.js deleted file mode 100644 index 5e085258..00000000 --- a/auction-dutch/application-javascript/endAuctionwithAuditor.js +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const { Gateway, Wallets } = require('fabric-network'); -const path = require('path'); -const { buildCCPOrg1, buildCCPOrg2, buildWallet, prettyJSONString } = require('../../test-application/javascript/AppUtil.js'); - -const myChannel = 'mychannel'; -const myChaincodeName = 'auction'; - -async function endAuction (ccp, wallet, org, user, auctionID) { - try { - const gateway = new Gateway(); - // connect using Discovery enabled - - await gateway.connect(ccp, - { wallet: wallet, identity: user, discovery: { enabled: true, asLocalhost: true } }); - - const network = await gateway.getNetwork(myChannel); - const contract = network.getContract(myChaincodeName); - - const statefulTxn = contract.createTransaction('EndAuction'); - - statefulTxn.setEndorsingOrganizations(org, 'Org3MSP'); - - console.log('\n--> Submit the transaction to end the auction'); - await statefulTxn.submit(auctionID); - console.log('*** Result: committed'); - - console.log('\n--> Evaluate Transaction: query the updated auction'); - const result = await contract.evaluateTransaction('QueryAuction', auctionID); - console.log('*** Result: Auction: ' + prettyJSONString(result.toString())); - - gateway.disconnect(); - } catch (error) { - console.error(`******** FAILED to submit bid: ${error}`); - process.exit(1); - } -} - -async function main () { - try { - if (process.argv[2] === undefined || process.argv[3] === undefined || - process.argv[4] === undefined) { - console.log('Usage: node endAuction.js org userID auctionID'); - process.exit(1); - } - - const org = process.argv[2]; - const user = process.argv[3]; - const auctionID = process.argv[4]; - - if (org === 'Org1' || org === 'org1') { - const orgMSP = 'Org1MSP'; - const ccp = buildCCPOrg1(); - const walletPath = path.join(__dirname, 'wallet/org1'); - const wallet = await buildWallet(Wallets, walletPath); - await endAuction(ccp, wallet, orgMSP, user, auctionID); - } else if (org === 'Org2' || org === 'org2') { - const orgMSP = 'Org2MSP'; - const ccp = buildCCPOrg2(); - const walletPath = path.join(__dirname, 'wallet/org2'); - const wallet = await buildWallet(Wallets, walletPath); - await endAuction(ccp, wallet, orgMSP, user, auctionID); - } else { - console.log('Usage: node endAuction.js org userID auctionID'); - console.log('Org must be Org1 or Org2'); - } - } catch (error) { - console.error(`******** FAILED to run the application: ${error}`); - if (error.stack) { - console.error(error.stack); - } - process.exit(1); - } -} - -main(); diff --git a/auction-dutch/application-javascript/enrollAdmin.js b/auction-dutch/application-javascript/enrollAdmin.js deleted file mode 100644 index 90998fd8..00000000 --- a/auction-dutch/application-javascript/enrollAdmin.js +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const { Wallets } = require('fabric-network'); -const FabricCAServices = require('fabric-ca-client'); -const path = require('path'); -const { buildCAClient, enrollAdmin } = require('../../test-application/javascript/CAUtil.js'); -const { buildCCPOrg1, buildCCPOrg2, buildWallet } = require('../../test-application/javascript/AppUtil.js'); - -const mspOrg1 = 'Org1MSP'; -const mspOrg2 = 'Org2MSP'; - -async function connectToOrg1CA () { - console.log('\n--> Enrolling the Org1 CA admin'); - const ccpOrg1 = buildCCPOrg1(); - const caOrg1Client = buildCAClient(FabricCAServices, ccpOrg1, 'ca.org1.example.com'); - - const walletPathOrg1 = path.join(__dirname, 'wallet/org1'); - const walletOrg1 = await buildWallet(Wallets, walletPathOrg1); - - await enrollAdmin(caOrg1Client, walletOrg1, mspOrg1); -} - -async function connectToOrg2CA () { - console.log('\n--> Enrolling the Org2 CA admin'); - const ccpOrg2 = buildCCPOrg2(); - const caOrg2Client = buildCAClient(FabricCAServices, ccpOrg2, 'ca.org2.example.com'); - - const walletPathOrg2 = path.join(__dirname, 'wallet/org2'); - const walletOrg2 = await buildWallet(Wallets, walletPathOrg2); - - await enrollAdmin(caOrg2Client, walletOrg2, mspOrg2); -} -async function main () { - if (process.argv[2] === undefined) { - console.log('Usage: node enrollAdmin.js Org'); - process.exit(1); - } - - const org = process.argv[2]; - - try { - if (org === 'Org1' || org === 'org1') { - await connectToOrg1CA(); - } else if (org === 'Org2' || org === 'org2') { - await connectToOrg2CA(); - } else { - console.log('Usage: node registerUser.js org userID'); - console.log('Org must be Org1 or Org2'); - } - } catch (error) { - console.error(`Error in enrolling admin: ${error}`); - process.exit(1); - } -} - -main(); diff --git a/auction-dutch/application-javascript/package.json b/auction-dutch/application-javascript/package.json deleted file mode 100644 index 33954681..00000000 --- a/auction-dutch/application-javascript/package.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "auction", - "version": "1.0.0", - "description": "auction application implemented in JavaScript", - "engines": { - "node": ">=12", - "npm": ">=5" - }, - "engineStrict": true, - "author": "Hyperledger", - "license": "Apache-2.0", - "scripts": { - "lint": "eslint *.js" - }, - "dependencies": { - "fabric-ca-client": "^2.2.19", - "fabric-network": "^2.2.19" - }, - "devDependencies": { - "eslint": "^7.20.0", - "eslint-config-standard": "^16.0.2", - "eslint-plugin-import": "^2.22.1", - "eslint-plugin-node": "^11.1.0", - "eslint-plugin-promise": "^4.3.1" - } -} diff --git a/auction-dutch/application-javascript/queryAuction.js b/auction-dutch/application-javascript/queryAuction.js deleted file mode 100644 index 06471d5e..00000000 --- a/auction-dutch/application-javascript/queryAuction.js +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const { Gateway, Wallets } = require('fabric-network'); -const path = require('path'); -const { buildCCPOrg1, buildCCPOrg2, buildWallet, prettyJSONString } = require('../../test-application/javascript/AppUtil.js'); - -const myChannel = 'mychannel'; -const myChaincodeName = 'auction'; - -async function queryAuction (ccp, wallet, user, auctionID) { - try { - const gateway = new Gateway(); - // connect using Discovery enabled - - await gateway.connect(ccp, - { wallet: wallet, identity: user, discovery: { enabled: true, asLocalhost: true } }); - - const network = await gateway.getNetwork(myChannel); - const contract = network.getContract(myChaincodeName); - - console.log('\n--> Evaluate Transaction: query the auction'); - const result = await contract.evaluateTransaction('QueryAuction', auctionID); - console.log('*** Result: Auction: ' + prettyJSONString(result.toString())); - - gateway.disconnect(); - } catch (error) { - console.error(`******** FAILED to submit bid: ${error}`); - } -} - -async function main () { - try { - if (process.argv[2] === undefined || process.argv[3] === undefined || - process.argv[4] === undefined) { - console.log('Usage: node queryAuction.js org userID auctionID'); - process.exit(1); - } - - const org = process.argv[2]; - const user = process.argv[3]; - const auctionID = process.argv[4]; - - if (org === 'Org1' || org === 'org1') { - const ccp = buildCCPOrg1(); - const walletPath = path.join(__dirname, 'wallet/org1'); - const wallet = await buildWallet(Wallets, walletPath); - await queryAuction(ccp, wallet, user, auctionID); - } else if (org === 'Org2' || org === 'org2') { - const ccp = buildCCPOrg2(); - const walletPath = path.join(__dirname, 'wallet/org2'); - const wallet = await buildWallet(Wallets, walletPath); - await queryAuction(ccp, wallet, user, auctionID); - } else { - console.log('Usage: node queryAuction.js org userID auctionID'); - console.log('Org must be Org1 or Org2'); - } - } catch (error) { - console.error(`******** FAILED to run the application: ${error}`); - } -} - -main(); diff --git a/auction-dutch/application-javascript/queryBid.js b/auction-dutch/application-javascript/queryBid.js deleted file mode 100644 index 1bb17e7d..00000000 --- a/auction-dutch/application-javascript/queryBid.js +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const { Gateway, Wallets } = require('fabric-network'); -const path = require('path'); -const { buildCCPOrg1, buildCCPOrg2, buildWallet, prettyJSONString } = require('../../../test-application/javascript/AppUtil.js'); - -const myChannel = 'mychannel'; -const myChaincodeName = 'auction'; - -async function queryBid (ccp, wallet, user, auctionID, bidID) { - try { - const gateway = new Gateway(); - // connect using Discovery enabled - - await gateway.connect(ccp, - { wallet: wallet, identity: user, discovery: { enabled: true, asLocalhost: true } }); - - const network = await gateway.getNetwork(myChannel); - const contract = network.getContract(myChaincodeName); - - console.log('\n--> Evaluate Transaction: read bid from private data store'); - const result = await contract.evaluateTransaction('QueryBid', auctionID, bidID); - console.log('*** Result: Bid: ' + prettyJSONString(result.toString())); - - gateway.disconnect(); - } catch (error) { - console.error(`******** FAILED to submit bid: ${error}`); - } -} - -async function main () { - try { - if (process.argv[2] === undefined || process.argv[3] === undefined || - process.argv[4] === undefined || process.argv[5] === undefined) { - console.log('Usage: node bid.js org userID auctionID bidID'); - process.exit(1); - } - - const org = process.argv[2]; - const user = process.argv[3]; - const auctionID = process.argv[4]; - const bidID = process.argv[5]; - - if (org === 'Org1' || org === 'org1') { - const ccp = buildCCPOrg1(); - const walletPath = path.join(__dirname, 'wallet/org1'); - const wallet = await buildWallet(Wallets, walletPath); - await queryBid(ccp, wallet, user, auctionID, bidID); - } else if (org === 'Org2' || org === 'org2') { - const ccp = buildCCPOrg2(); - const walletPath = path.join(__dirname, 'wallet/org2'); - const wallet = await buildWallet(Wallets, walletPath); - await queryBid(ccp, wallet, user, auctionID, bidID); - } else { - console.log('Usage: node bid.js org userID auctionID bidID'); - console.log('Org must be Org1 or Org2'); - } - } catch (error) { - console.error(`******** FAILED to run the application: ${error}`); - } -} - -main(); diff --git a/auction-dutch/application-javascript/registerEnrollUser.js b/auction-dutch/application-javascript/registerEnrollUser.js deleted file mode 100644 index 9b7abc32..00000000 --- a/auction-dutch/application-javascript/registerEnrollUser.js +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const { Wallets } = require('fabric-network'); -const FabricCAServices = require('fabric-ca-client'); -const path = require('path'); -const { buildCAClient, registerAndEnrollUser } = require('../../test-application/javascript/CAUtil.js'); -const { buildCCPOrg1, buildCCPOrg2, buildWallet } = require('../../test-application/javascript/AppUtil.js'); - -const mspOrg1 = 'Org1MSP'; -const mspOrg2 = 'Org2MSP'; - -async function connectToOrg1CA (UserID) { - console.log('\n--> Register and enrolling new user'); - const ccpOrg1 = buildCCPOrg1(); - const caOrg1Client = buildCAClient(FabricCAServices, ccpOrg1, 'ca.org1.example.com'); - - const walletPathOrg1 = path.join(__dirname, 'wallet/org1'); - const walletOrg1 = await buildWallet(Wallets, walletPathOrg1); - - await registerAndEnrollUser(caOrg1Client, walletOrg1, mspOrg1, UserID, 'org1.department1'); -} - -async function connectToOrg2CA (UserID) { - console.log('\n--> Register and enrolling new user'); - const ccpOrg2 = buildCCPOrg2(); - const caOrg2Client = buildCAClient(FabricCAServices, ccpOrg2, 'ca.org2.example.com'); - - const walletPathOrg2 = path.join(__dirname, 'wallet/org2'); - const walletOrg2 = await buildWallet(Wallets, walletPathOrg2); - - await registerAndEnrollUser(caOrg2Client, walletOrg2, mspOrg2, UserID, 'org2.department1'); -} -async function main () { - if (process.argv[2] === undefined && process.argv[3] === undefined) { - console.log('Usage: node registerEnrollUser.js org userID'); - process.exit(1); - } - - const org = process.argv[2]; - const userId = process.argv[3]; - - try { - if (org === 'Org1' || org === 'org1') { - await connectToOrg1CA(userId); - } else if (org === 'Org2' || org === 'org2') { - await connectToOrg2CA(userId); - } else { - console.log('Usage: node registerEnrollUser.js org userID'); - console.log('Org must be Org1 or Org2'); - } - } catch (error) { - console.error(`Error in enrolling admin: ${error}`); - process.exit(1); - } -} - -main(); diff --git a/auction-dutch/application-javascript/revealBid.js b/auction-dutch/application-javascript/revealBid.js deleted file mode 100644 index b1fc8dc9..00000000 --- a/auction-dutch/application-javascript/revealBid.js +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const { Gateway, Wallets } = require('fabric-network'); -const path = require('path'); -const { buildCCPOrg1, buildCCPOrg2, buildWallet, prettyJSONString } = require('../../test-application/javascript/AppUtil.js'); - -const myChannel = 'mychannel'; -const myChaincodeName = 'auction'; - -async function addBid (ccp, wallet, user, auctionID, bidID) { - try { - const gateway = new Gateway(); - // connect using Discovery enabled - - await gateway.connect(ccp, - { wallet: wallet, identity: user, discovery: { enabled: true, asLocalhost: true } }); - - const network = await gateway.getNetwork(myChannel); - const contract = network.getContract(myChaincodeName); - - console.log('\n--> Evaluate Transaction: read your bid'); - const bidString = await contract.evaluateTransaction('QueryBid', auctionID, bidID); - const bidJSON = JSON.parse(bidString); - - // console.log('\n--> Evaluate Transaction: query the auction you want to join'); - const auctionString = await contract.evaluateTransaction('QueryAuction', auctionID); - // console.log('*** Result: Bid: ' + prettyJSONString(auctionString.toString())); - const auctionJSON = JSON.parse(auctionString); - - const bidData = { objectType: 'bid', quantity: parseInt(bidJSON.quantity), price: parseInt(bidJSON.price), org: bidJSON.org, buyer: bidJSON.buyer }; - console.log('*** Result: Bid: ' + JSON.stringify(bidData, null, 2)); - - const statefulTxn = contract.createTransaction('RevealBid'); - const tmapData = Buffer.from(JSON.stringify(bidData)); - statefulTxn.setTransient({ - bid: tmapData - }); - - if (auctionJSON.organizations.length === 2) { - statefulTxn.setEndorsingOrganizations(auctionJSON.organizations[0], auctionJSON.organizations[1]); - } else { - statefulTxn.setEndorsingOrganizations(auctionJSON.organizations[0]); - } - - await statefulTxn.submit(auctionID, bidID); - - console.log('\n--> Evaluate Transaction: query the auction to see that our bid was added'); - const result = await contract.evaluateTransaction('QueryAuction', auctionID); - console.log('*** Result: Auction: ' + prettyJSONString(result.toString())); - - gateway.disconnect(); - } catch (error) { - console.error(`******** FAILED to submit bid: ${error}`); - process.exit(1); - } -} - -async function main () { - try { - if (process.argv[2] === undefined || process.argv[3] === undefined || - process.argv[4] === undefined || process.argv[5] === undefined) { - console.log('Usage: node revealBid.js org userID auctionID bidID'); - process.exit(1); - } - - const org = process.argv[2]; - const user = process.argv[3]; - const auctionID = process.argv[4]; - const bidID = process.argv[5]; - - if (org === 'Org1' || org === 'org1') { - const ccp = buildCCPOrg1(); - const walletPath = path.join(__dirname, 'wallet/org1'); - const wallet = await buildWallet(Wallets, walletPath); - await addBid(ccp, wallet, user, auctionID, bidID); - } else if (org === 'Org2' || org === 'org2') { - const ccp = buildCCPOrg2(); - const walletPath = path.join(__dirname, 'wallet/org2'); - const wallet = await buildWallet(Wallets, walletPath); - await addBid(ccp, wallet, user, auctionID, bidID); - } else { - console.log('Usage: node revealBid.js org userID auctionID bidID'); - console.log('Org must be Org1 or Org2'); - } - } catch (error) { - console.error(`******** FAILED to run the application: ${error}`); - if (error.stack) { - console.error(error.stack); - } - process.exit(1); - } -} - -main(); diff --git a/auction-dutch/application-javascript/submitBid.js b/auction-dutch/application-javascript/submitBid.js deleted file mode 100644 index adb3070f..00000000 --- a/auction-dutch/application-javascript/submitBid.js +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const { Gateway, Wallets } = require('fabric-network'); -const path = require('path'); -const { buildCCPOrg1, buildCCPOrg2, buildWallet, prettyJSONString } = require('../../test-application/javascript/AppUtil.js'); - -const myChannel = 'mychannel'; -const myChaincodeName = 'auction'; - -async function submitBid (ccp, wallet, user, auctionID, bidID) { - try { - const gateway = new Gateway(); - // connect using Discovery enabled - - await gateway.connect(ccp, - { wallet: wallet, identity: user, discovery: { enabled: true, asLocalhost: true } }); - - const network = await gateway.getNetwork(myChannel); - const contract = network.getContract(myChaincodeName); - - console.log('\n--> Evaluate Transaction: query the auction you want to join'); - const auctionString = await contract.evaluateTransaction('QueryAuction', auctionID); - const auctionJSON = JSON.parse(auctionString); - - const statefulTxn = contract.createTransaction('SubmitBid'); - - if (auctionJSON.organizations.length === 2) { - statefulTxn.setEndorsingOrganizations(auctionJSON.organizations[0], auctionJSON.organizations[1]); - } else { - statefulTxn.setEndorsingOrganizations(auctionJSON.organizations[0]); - } - - console.log('\n--> Submit Transaction: add bid to the auction'); - await statefulTxn.submit(auctionID, bidID); - - console.log('\n--> Evaluate Transaction: query the auction to see that our bid was added'); - const result = await contract.evaluateTransaction('QueryAuction', auctionID); - console.log('*** Result: Auction: ' + prettyJSONString(result.toString())); - - gateway.disconnect(); - } catch (error) { - console.error(`******** FAILED to submit bid: ${error}`); - process.exit(1); - } -} - -async function main () { - try { - if (process.argv[2] === undefined || process.argv[3] === undefined || - process.argv[4] === undefined || process.argv[5] === undefined) { - console.log('Usage: node submitBid.js org userID auctionID bidID'); - process.exit(1); - } - - const org = process.argv[2]; - const user = process.argv[3]; - const auctionID = process.argv[4]; - const bidID = process.argv[5]; - - if (org === 'Org1' || org === 'org1') { - const ccp = buildCCPOrg1(); - const walletPath = path.join(__dirname, 'wallet/org1'); - const wallet = await buildWallet(Wallets, walletPath); - await submitBid(ccp, wallet, user, auctionID, bidID); - } else if (org === 'Org2' || org === 'org2') { - const ccp = buildCCPOrg2(); - const walletPath = path.join(__dirname, 'wallet/org2'); - const wallet = await buildWallet(Wallets, walletPath); - await submitBid(ccp, wallet, user, auctionID, bidID); - } else { - console.log('Usage: node submitBid.js org userID auctionID bidID'); - console.log('Org must be Org1 or Org2'); - } - } catch (error) { - console.error(`******** FAILED to run the application: ${error}`); - if (error.stack) { - console.error(error.stack); - } - process.exit(1); - } -} - -main(); diff --git a/auction-dutch/chaincode-go-auditor/go.mod b/auction-dutch/chaincode-go-auditor/go.mod deleted file mode 100644 index 9ab750f9..00000000 --- a/auction-dutch/chaincode-go-auditor/go.mod +++ /dev/null @@ -1,34 +0,0 @@ -module github.com/hyperledger/fabric-samples/auction/dutch-auction/chaincode-go-auditor - -go 1.21 - -require ( - github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0-20240618210511-f7903324a8af - github.com/hyperledger/fabric-contract-api-go/v2 v2.0.0 - github.com/hyperledger/fabric-protos-go-apiv2 v0.3.3 - google.golang.org/protobuf v1.34.2 -) - -require ( - github.com/go-openapi/jsonpointer v0.21.0 // indirect - github.com/go-openapi/jsonreference v0.21.0 // indirect - github.com/go-openapi/spec v0.21.0 // indirect - github.com/go-openapi/swag v0.23.0 // indirect - github.com/gobuffalo/envy v1.10.2 // indirect - github.com/gobuffalo/packd v1.0.2 // indirect - github.com/gobuffalo/packr v1.30.1 // indirect - github.com/joho/godotenv v1.5.1 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/mailru/easyjson v0.7.7 // indirect - github.com/rogpeppe/go-internal v1.12.0 // indirect - github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect - github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect - github.com/xeipuuv/gojsonschema v1.2.0 // indirect - golang.org/x/mod v0.17.0 // indirect - golang.org/x/net v0.24.0 // indirect - golang.org/x/sys v0.19.0 // indirect - golang.org/x/text v0.14.0 // indirect - google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect - google.golang.org/grpc v1.64.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) diff --git a/auction-dutch/chaincode-go-auditor/go.sum b/auction-dutch/chaincode-go-auditor/go.sum deleted file mode 100644 index 7c5e414c..00000000 --- a/auction-dutch/chaincode-go-auditor/go.sum +++ /dev/null @@ -1,132 +0,0 @@ -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= -github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= -github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= -github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= -github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= -github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= -github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= -github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= -github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= -github.com/gobuffalo/envy v1.10.2 h1:EIi03p9c3yeuRCFPOKcSfajzkLb3hrRjEpHGI8I2Wo4= -github.com/gobuffalo/envy v1.10.2/go.mod h1:qGAGwdvDsaEtPhfBzb3o0SfDea8ByGn9j8bKmVft9z8= -github.com/gobuffalo/logger v1.0.0/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs= -github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q= -github.com/gobuffalo/packd v1.0.2 h1:Yg523YqnOxGIWCp69W12yYBKsoChwI7mtu6ceM9Bwfw= -github.com/gobuffalo/packd v1.0.2/go.mod h1:sUc61tDqGMXON80zpKGp92lDb86Km28jfvX7IAyxFT8= -github.com/gobuffalo/packr v1.30.1 h1:hu1fuVR3fXEZR7rXNW3h8rqSML8EVAf6KNm0NKO/wKg= -github.com/gobuffalo/packr v1.30.1/go.mod h1:ljMyFO2EcrnzsHsN99cvbq055Y9OhRrIaviy289eRuk= -github.com/gobuffalo/packr/v2 v2.5.1/go.mod h1:8f9c96ITobJlPzI44jj+4tHnEKNt0xXWSVlXRN9X1Iw= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0-20240618210511-f7903324a8af h1:WT4NjX7Uk03GSeH++jF3a0wp4FhybTM86zDPCETvmSk= -github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0-20240618210511-f7903324a8af/go.mod h1:f/ER25FaBepxJugwpLhbD2hLAoZaZEVqkBjOcHjw72Y= -github.com/hyperledger/fabric-contract-api-go/v2 v2.0.0 h1:IDiCGVOBlRd6zpL0Y+f6V7IpBqa4/Z5JAK9SF7a5ea8= -github.com/hyperledger/fabric-contract-api-go/v2 v2.0.0/go.mod h1:pdqhe7ALf4lmXgQdprCyNWYdnCPxgj02Vhf8JF5w8po= -github.com/hyperledger/fabric-protos-go-apiv2 v0.3.3 h1:Xpd6fzG/KjAOHJsq7EQXY2l+qi/y8muxBaY7R6QWABk= -github.com/hyperledger/fabric-protos-go-apiv2 v0.3.3/go.mod h1:2pq0ui6ZWA0cC8J+eCErgnMDCS1kPOEYVY+06ZAK0qE= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= -github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= -github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= -github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= -golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= -google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/auction-dutch/chaincode-go-auditor/smart-contract/auction.go b/auction-dutch/chaincode-go-auditor/smart-contract/auction.go deleted file mode 100644 index e0151f8a..00000000 --- a/auction-dutch/chaincode-go-auditor/smart-contract/auction.go +++ /dev/null @@ -1,440 +0,0 @@ -/* -SPDX-License-Identifier: Apache-2.0 -*/ - -package auction - -import ( - "bytes" - "crypto/sha256" - "encoding/json" - "errors" - "fmt" - "sort" - - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" -) - -type SmartContract struct { - contractapi.Contract -} - -// Auction data -type Auction struct { - Type string `json:"objectType"` - ItemSold string `json:"item"` - Seller string `json:"seller"` - Quantity int `json:"quantity"` - Orgs []string `json:"organizations"` - PrivateBids map[string]BidHash `json:"privateBids"` - RevealedBids map[string]FullBid `json:"revealedBids"` - Winners []Winners `json:"winners"` - Price int `json:"price"` - Status string `json:"status"` - Auditor bool `json:"auditor"` -} - -// FullBid is the structure of a revealed bid -type FullBid struct { - Type string `json:"objectType"` - Quantity int `json:"quantity"` - Price int `json:"price"` - Org string `json:"org"` - Buyer string `json:"buyer"` -} - -// BidHash is the structure of a private bid -type BidHash struct { - Org string `json:"org"` - Hash string `json:"hash"` -} - -// Winners stores the winners of the auction -type Winners struct { - Buyer string `json:"buyer"` - Quantity int `json:"quantity"` -} - -const bidKeyType = "bid" - -// SubmitBid is used by the bidder to add the hash of that bid stored in private data to the -// auction. Note that this function alters the auction in private state, and needs -// to meet the auction endorsement policy. Transaction ID is used identify the bid -func (s *SmartContract) SubmitBid(ctx contractapi.TransactionContextInterface, auctionID string, txID string) error { - - // get the MSP ID of the bidder's org - clientOrgID, err := ctx.GetClientIdentity().GetMSPID() - if err != nil { - return fmt.Errorf("failed to get client MSP ID: %v", err) - } - - // get the auction from public state - auction, err := s.QueryAuction(ctx, auctionID) - if err != nil { - return fmt.Errorf("failed to get auction from public state %v", err) - } - - // the auction needs to be open for users to add their bid - status := auction.Status - if status != "open" { - return fmt.Errorf("cannot join closed or ended auction") - } - - // get the inplicit collection name of bidder's org - collection, err := getCollectionName(ctx) - if err != nil { - return fmt.Errorf("failed to get implicit collection name: %v", err) - } - - // use the transaction ID passed as a parameter to create composite bid key - bidKey, err := ctx.GetStub().CreateCompositeKey(bidKeyType, []string{auctionID, txID}) - if err != nil { - return fmt.Errorf("failed to create composite key: %v", err) - } - - // get the hash of the bid if found in private collection - bidHash, err := ctx.GetStub().GetPrivateDataHash(collection, bidKey) - if err != nil { - return fmt.Errorf("failed to read bid bash from collection: %v", err) - } - if bidHash == nil { - return fmt.Errorf("bid hash does not exist: %s", bidKey) - } - - // store the hash along with the bidder's organization - newHash := BidHash{ - Org: clientOrgID, - Hash: fmt.Sprintf("%x", bidHash), - } - - auction.PrivateBids[bidKey] = newHash - - // Add the bidding organization to the list of participating organization's if it is not already - orgs := auction.Orgs - if !(contains(orgs, clientOrgID)) { - newOrgs := append(orgs, clientOrgID) - auction.Orgs = newOrgs - - err = setAssetStateBasedEndorsement(ctx, auctionID, newOrgs, auction.Auditor) - if err != nil { - return fmt.Errorf("failed setting state based endorsement for new organization: %v", err) - } - } - - newAuctionJSON, _ := json.Marshal(auction) - - err = ctx.GetStub().PutState(auctionID, newAuctionJSON) - if err != nil { - return fmt.Errorf("failed to update auction: %v", err) - } - - return nil -} - -// RevealBid is used by a bidder to reveal their bid after the auction is closed -func (s *SmartContract) RevealBid(ctx contractapi.TransactionContextInterface, auctionID string, txID string) error { - - // get the MSP ID of the bidder's org - clientOrgID, err := ctx.GetClientIdentity().GetMSPID() - if err != nil { - return fmt.Errorf("failed to get client MSP ID: %v", err) - } - - // get bid from transient map - transientMap, err := ctx.GetStub().GetTransient() - if err != nil { - return fmt.Errorf("error getting transient: %v", err) - } - - transientBidJSON, ok := transientMap["bid"] - if !ok { - return fmt.Errorf("bid key not found in the transient map") - } - - // get implicit collection name of organization ID - collection, err := getCollectionName(ctx) - if err != nil { - return fmt.Errorf("failed to get implicit collection name: %v", err) - } - - // use transaction ID to create composit bid key - bidKey, err := ctx.GetStub().CreateCompositeKey(bidKeyType, []string{auctionID, txID}) - if err != nil { - return fmt.Errorf("failed to create composite key: %v", err) - } - - // get bid hash of bid if private bid on the public ledger - bidHash, err := ctx.GetStub().GetPrivateDataHash(collection, bidKey) - if err != nil { - return fmt.Errorf("failed to read bid bash from collection: %v", err) - } - if bidHash == nil { - return fmt.Errorf("bid hash does not exist: %s", bidKey) - } - - // get auction from public state - auction, err := s.QueryAuction(ctx, auctionID) - if err != nil { - return fmt.Errorf("failed to get auction from public state %v", err) - } - - // check that the bidders org is a participant in the auction - orgs := auction.Orgs - if !(contains(orgs, clientOrgID)) { - return fmt.Errorf("particiant %s is not a member of the auction", clientOrgID) - } - - // Complete a series of three checks before we add the bid to the auction - - // check 1: check that the auction is closed. We cannot reveal an - // bid to an open auction - status := auction.Status - if status != "closed" { - return errors.New("cannot reveal bid for open or ended auction") - } - - // check 2: check that hash of revealed bid matches hash of private bid - // on the public ledger. This checks that the bidder is telling the truth - // about the value of their bid - - hash := sha256.New() - hash.Write(transientBidJSON) - calculatedBidJSONHash := hash.Sum(nil) - - // verify that the hash of the passed immutable properties matches the on-chain hash - if !bytes.Equal(calculatedBidJSONHash, bidHash) { - return fmt.Errorf("hash %x for bid JSON %s does not match hash in auction: %x", - calculatedBidJSONHash, - transientBidJSON, - bidHash, - ) - } - - // check 3; check hash of relealed bid matches hash of private bid that was - // added earlier. This ensures that the bid has not changed since it - // was added to the auction - - privateBidHashString := auction.PrivateBids[bidKey].Hash - - onChainBidHashString := fmt.Sprintf("%x", bidHash) - if privateBidHashString != onChainBidHashString { - return fmt.Errorf("hash %s for bid JSON %s does not match hash in auction: %s, bidder must have changed bid", - privateBidHashString, - transientBidJSON, - onChainBidHashString, - ) - } - - // we can add the bid to the auction if all checks have passed - type transientBidInput struct { - Quantity int `json:"quantity"` - Price int `json:"price"` - Org string `json:"org"` - Buyer string `json:"buyer"` - } - - // unmarshal bid imput - var bidInput transientBidInput - err = json.Unmarshal(transientBidJSON, &bidInput) - if err != nil { - return fmt.Errorf("failed to unmarshal JSON: %v", err) - } - - // get ID of submitting client - clientID, err := s.GetSubmittingClientIdentity(ctx) - if err != nil { - return fmt.Errorf("failed to get client identity %v", err) - } - - // marshal transient parameters and ID and MSPID into bid object - newBid := FullBid{ - Type: bidKeyType, - Quantity: bidInput.Quantity, - Price: bidInput.Price, - Org: bidInput.Org, - Buyer: bidInput.Buyer, - } - - // check 4: make sure that the transaction is being submitted is the bidder - if bidInput.Buyer != clientID { - return fmt.Errorf("permission denied, client id %v is not the owner of the bid", clientID) - } - - auction.RevealedBids[bidKey] = newBid - - auctionJSON, _ := json.Marshal(auction) - - // put auction with bid added back into state - err = ctx.GetStub().PutState(auctionID, auctionJSON) - if err != nil { - return fmt.Errorf("failed to update auction: %v", err) - } - - return nil -} - -// CloseAuction can be used by the seller to close the auction. This prevents -// bids from being added to the auction, and allows users to reveal their bid -func (s *SmartContract) CloseAuction(ctx contractapi.TransactionContextInterface, auctionID string) error { - - // get the MSP ID of the bidder's org - clientOrgID, err := ctx.GetClientIdentity().GetMSPID() - if err != nil { - return fmt.Errorf("failed to get client MSP ID: %v", err) - } - - // get auction from public state - auction, err := s.QueryAuction(ctx, auctionID) - if err != nil { - return fmt.Errorf("failed to get auction from public state %v", err) - } - - // check that the bidders org is a participant in the auction - orgs := auction.Orgs - if !(contains(orgs, clientOrgID)) { - return fmt.Errorf("particiant %s is not a member of the auction", clientOrgID) - } - - // the auction can only be closed by the seller - - // get ID of submitting client - clientID, err := s.GetSubmittingClientIdentity(ctx) - if err != nil { - return fmt.Errorf("failed to get client identity %v", err) - } - - seller := auction.Seller - if seller != clientID { - return fmt.Errorf("auction can only be closed by seller: %v", err) - } - - status := auction.Status - if status != "open" { - return errors.New("cannot close auction that is not open") - } - - auction.Status = string("closed") - - closedAuctionJSON, _ := json.Marshal(auction) - - err = ctx.GetStub().PutState(auctionID, closedAuctionJSON) - if err != nil { - return fmt.Errorf("failed to close auction: %v", err) - } - - return nil -} - -// EndAuction both changes the auction status to closed and calculates the winners -// of the auction -func (s *SmartContract) EndAuction(ctx contractapi.TransactionContextInterface, auctionID string) error { - - // get the MSP ID of the bidder's org - clientOrgID, err := ctx.GetClientIdentity().GetMSPID() - if err != nil { - return fmt.Errorf("failed to get client MSP ID: %v", err) - } - - // get auction from public state - auction, err := s.QueryAuction(ctx, auctionID) - if err != nil { - return fmt.Errorf("failed to get auction from public state %v", err) - } - - // check that the bidders org is a participant in the auction - orgs := auction.Orgs - if !(contains(orgs, clientOrgID)) { - return fmt.Errorf("particiant %s is not a member of the auction", clientOrgID) - } - - // Check that the auction is being ended by the seller - - // get ID of submitting client - clientID, err := s.GetSubmittingClientIdentity(ctx) - if err != nil { - return fmt.Errorf("failed to get client identity %v", err) - } - - seller := auction.Seller - if seller != clientID { - return fmt.Errorf("auction can only be ended by seller: %v", err) - } - - status := auction.Status - if status != "closed" { - return errors.New("can only end a closed auction") - } - - // get the list of revealed bids - - revealedBidMap := auction.RevealedBids - if len(auction.RevealedBids) == 0 { - return fmt.Errorf("no bids have been revealed, cannot end auction: %v", err) - } - - // sort the map of revealed bids to make it easier to calculate winners - // if bids are tied, fill smaller bids first - var bidders []FullBid - - for _, bid := range revealedBidMap { - bidders = append(bidders, bid) - } - - sort.Slice(bidders, func(p, q int) bool { - if bidders[p].Price > bidders[q].Price { - return true - } - if bidders[p].Price < bidders[q].Price { - return false - } - return bidders[p].Quantity < bidders[q].Quantity - }) - - i := 0 - remainingQuantity := auction.Quantity - - // calculate the winners - for remainingQuantity > 0 { - - // create the next winning bid - winner := Winners{ - Buyer: bidders[i].Buyer, - Quantity: bidders[i].Quantity, - } - - // add them to the list of winners and change the winning price - auction.Winners = append(auction.Winners, winner) - auction.Price = bidders[i].Price - - // Calculate the quantity that goes to the winner - // if there is sufficient quantity to give them the full bid - if remainingQuantity > bidders[i].Quantity { - remainingQuantity = remainingQuantity - bidders[i].Quantity - - // if there is not, give the remainder - } else { - auction.Winners[i].Quantity = remainingQuantity - remainingQuantity = 0 - } - i++ - if i == len(bidders) { - remainingQuantity = 0 - } - } - - // check if there is a winning bid that has yet to be revealed - err = checkForHigherBid(ctx, auction.Price, auction.RevealedBids, auction.PrivateBids) - if err != nil { - return fmt.Errorf("cannot end auction: %v", err) - } - - auction.Status = "ended" - - endedAuctionJSON, _ := json.Marshal(auction) - - err = ctx.GetStub().PutState(auctionID, endedAuctionJSON) - if err != nil { - return fmt.Errorf("failed to end auction: %v", err) - } - return nil -} diff --git a/auction-dutch/chaincode-go-auditor/smart-contract/auctionQueries.go b/auction-dutch/chaincode-go-auditor/smart-contract/auctionQueries.go deleted file mode 100644 index cee05d2c..00000000 --- a/auction-dutch/chaincode-go-auditor/smart-contract/auctionQueries.go +++ /dev/null @@ -1,91 +0,0 @@ -/* -SPDX-License-Identifier: Apache-2.0 -*/ - -package auction - -import ( - "encoding/json" - "fmt" - - "github.com/hyperledger/fabric-chaincode-go/v2/shim" - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" -) - -// QueryAuction allows all members of the channel to read a public auction -func (s *SmartContract) QueryAuction(ctx contractapi.TransactionContextInterface, auctionID string) (*Auction, error) { - - auctionJSON, err := ctx.GetStub().GetState(auctionID) - if err != nil { - return nil, fmt.Errorf("failed to get auction object %v: %v", auctionID, err) - } - if auctionJSON == nil { - return nil, fmt.Errorf("auction does not exist") - } - - var auction *Auction - err = json.Unmarshal(auctionJSON, &auction) - if err != nil { - return nil, err - } - - return auction, nil -} - -// checkForHigherBid is an internal function that is used to determine if a winning bid has yet to be revealed -func checkForHigherBid(ctx contractapi.TransactionContextInterface, auctionPrice int, revealedBidders map[string]FullBid, bidders map[string]BidHash) error { - - // Get MSP ID of peer org - peerMSPID, err := shim.GetMSPID() - if err != nil { - return fmt.Errorf("failed getting the peer's MSPID: %v", err) - } - - var error error - error = nil - - for bidKey, privateBid := range bidders { - - if _, bidInAuction := revealedBidders[bidKey]; bidInAuction { - - // bid is already revealed, no action to take - - } else { - - collection := "_implicit_org_" + privateBid.Org - - if privateBid.Org == peerMSPID { - - bidJSON, err := ctx.GetStub().GetPrivateData(collection, bidKey) - if err != nil { - return fmt.Errorf("failed to get bid %v: %v", bidKey, err) - } - if bidJSON == nil { - return fmt.Errorf("bid %v does not exist", bidKey) - } - - var bid *FullBid - err = json.Unmarshal(bidJSON, &bid) - if err != nil { - return err - } - - if bid.Price > auctionPrice { - error = fmt.Errorf("Cannot close auction, bidder has a higher price: %v", err) - } - - } else { - - hash, err := ctx.GetStub().GetPrivateDataHash(collection, bidKey) - if err != nil { - return fmt.Errorf("failed to read bid hash from collection: %v", err) - } - if hash == nil { - return fmt.Errorf("bid hash does not exist: %s", bidKey) - } - } - } - } - - return error -} diff --git a/auction-dutch/chaincode-go-auditor/smart-contract/utils.go b/auction-dutch/chaincode-go-auditor/smart-contract/utils.go deleted file mode 100644 index 4b73a7f3..00000000 --- a/auction-dutch/chaincode-go-auditor/smart-contract/utils.go +++ /dev/null @@ -1,203 +0,0 @@ -/* -SPDX-License-Identifier: Apache-2.0 -*/ - -package auction - -import ( - "encoding/base64" - "fmt" - - "github.com/hyperledger/fabric-chaincode-go/v2/shim" - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" - "github.com/hyperledger/fabric-protos-go-apiv2/common" - "github.com/hyperledger/fabric-protos-go-apiv2/msp" - "google.golang.org/protobuf/proto" -) - -func (s *SmartContract) GetSubmittingClientIdentity(ctx contractapi.TransactionContextInterface) (string, error) { - - b64ID, err := ctx.GetClientIdentity().GetID() - if err != nil { - return "", fmt.Errorf("Failed to read clientID: %v", err) - } - decodeID, err := base64.StdEncoding.DecodeString(b64ID) - if err != nil { - return "", fmt.Errorf("failed to base64 decode clientID: %v", err) - } - return string(decodeID), nil -} - -// getCollectionName is an internal helper function to get collection of submitting client identity. -func getCollectionName(ctx contractapi.TransactionContextInterface) (string, error) { - - // Get the MSP ID of submitting client identity - clientMSPID, err := ctx.GetClientIdentity().GetMSPID() - if err != nil { - return "", fmt.Errorf("failed to get verified MSPID: %v", err) - } - - // Create the collection name - orgCollection := "_implicit_org_" + clientMSPID - - return orgCollection, nil -} - -// verifyClientOrgMatchesPeerOrg is an internal function used to verify that client org id matches peer org id. -func verifyClientOrgMatchesPeerOrg(ctx contractapi.TransactionContextInterface) error { - - clientMSPID, err := ctx.GetClientIdentity().GetMSPID() - if err != nil { - return fmt.Errorf("failed getting the client's MSPID: %v", err) - } - peerMSPID, err := shim.GetMSPID() - if err != nil { - return fmt.Errorf("failed getting the peer's MSPID: %v", err) - } - - if clientMSPID != peerMSPID { - return fmt.Errorf("client from org %v is not authorized to read or write private data from an org %v peer", clientMSPID, peerMSPID) - } - - return nil -} - -func contains(sli []string, str string) bool { - for _, a := range sli { - if a == str { - return true - } - } - return false -} - -func setAssetStateBasedEndorsement(ctx contractapi.TransactionContextInterface, assetId string, mspids []string, auditor bool) error { - - principals := make([]*msp.MSPPrincipal, len(mspids)) - participantSigsPolicy := make([]*common.SignaturePolicy, len(mspids)) - - for i, id := range mspids { - principal, err := proto.Marshal( - &msp.MSPRole{ - Role: msp.MSPRole_PEER, - MspIdentifier: id, - }, - ) - if err != nil { - return err - } - principals[i] = &msp.MSPPrincipal{ - PrincipalClassification: msp.MSPPrincipal_ROLE, - Principal: principal, - } - participantSigsPolicy[i] = &common.SignaturePolicy{ - Type: &common.SignaturePolicy_SignedBy{ - SignedBy: int32(i), - }, - } - } - - if auditor == false { - // create the defalt policy for an auction without an auditor - - policy := &common.SignaturePolicyEnvelope{ - Version: 0, - Rule: &common.SignaturePolicy{ - Type: &common.SignaturePolicy_NOutOf_{ - NOutOf: &common.SignaturePolicy_NOutOf{ - N: int32(len(mspids)), - Rules: participantSigsPolicy, - }, - }, - }, - Identities: principals, - } - - spBytes, err := proto.Marshal(policy) - if err != nil { - return err - } - err = ctx.GetStub().SetStateValidationParameter(assetId, spBytes) - if err != nil { - return fmt.Errorf("failed to set validation parameter on auction: %v", err) - } - } else { - - // create the defalt policy for an auction with an auditor - - // create the auditor identity and signature policy - auditorMSP, err := proto.Marshal( - &msp.MSPRole{ - Role: msp.MSPRole_PEER, - MspIdentifier: "Org3MSP", - }, - ) - if err != nil { - return err - } - principals = append(principals, &msp.MSPPrincipal{ - PrincipalClassification: msp.MSPPrincipal_ROLE, - Principal: auditorMSP, - }, - ) - // Create the policies in case the auditor is needed. In this case, an - // auditor and 1 participant can update the auction. - auditorPolicies := make([]*common.SignaturePolicy, 2) - auditorPolicies[0] = &common.SignaturePolicy{ - Type: &common.SignaturePolicy_SignedBy{ - SignedBy: int32(len(principals) - 1), - }, - } - auditorPolicies[1] = &common.SignaturePolicy{ - Type: &common.SignaturePolicy_NOutOf_{ - NOutOf: &common.SignaturePolicy_NOutOf{ - N: 1, - Rules: participantSigsPolicy, - }, - }, - } - - // The auditor policy below is equivilent to AND(auditor, OR(participants)) - policies := make([]*common.SignaturePolicy, 2) - policies[0] = &common.SignaturePolicy{ - Type: &common.SignaturePolicy_NOutOf_{ - NOutOf: &common.SignaturePolicy_NOutOf{ - N: 2, - Rules: auditorPolicies, - }, - }, - } - // Participants can also update the auction without an auditor - policies[1] = &common.SignaturePolicy{ - Type: &common.SignaturePolicy_NOutOf_{ - NOutOf: &common.SignaturePolicy_NOutOf{ - N: int32(len(mspids)), - Rules: participantSigsPolicy, - }, - }, - } - // Either the auditor policy or the participant policy can update - // the auction - policy := &common.SignaturePolicyEnvelope{ - Version: 0, - Rule: &common.SignaturePolicy{ - Type: &common.SignaturePolicy_NOutOf_{ - NOutOf: &common.SignaturePolicy_NOutOf{ - N: 1, - Rules: policies, - }, - }, - }, - Identities: principals, - } - spBytes, err := proto.Marshal(policy) - if err != nil { - return err - } - err = ctx.GetStub().SetStateValidationParameter(assetId, spBytes) - if err != nil { - return fmt.Errorf("failed to set validation parameter on auction: %v", err) - } - } - return nil -} diff --git a/auction-dutch/chaincode-go-auditor/smartContract.go b/auction-dutch/chaincode-go-auditor/smartContract.go deleted file mode 100644 index f5feca58..00000000 --- a/auction-dutch/chaincode-go-auditor/smartContract.go +++ /dev/null @@ -1,23 +0,0 @@ -/* -SPDX-License-Identifier: Apache-2.0 -*/ - -package main - -import ( - "log" - - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" - auction "github.com/hyperledger/fabric-samples/auction/dutch-auction/chaincode-go-auditor/smart-contract" -) - -func main() { - auctionSmartContract, err := contractapi.NewChaincode(&auction.SmartContract{}) - if err != nil { - log.Panicf("Error creating auction chaincode: %v", err) - } - - if err := auctionSmartContract.Start(); err != nil { - log.Panicf("Error starting auction chaincode: %v", err) - } -} diff --git a/auction-dutch/chaincode-go/go.mod b/auction-dutch/chaincode-go/go.mod deleted file mode 100644 index a597e410..00000000 --- a/auction-dutch/chaincode-go/go.mod +++ /dev/null @@ -1,34 +0,0 @@ -module github.com/hyperledger/fabric-samples/auction/dutch-auction/chaincode-go - -go 1.21 - -require ( - github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0-20240618210511-f7903324a8af - github.com/hyperledger/fabric-contract-api-go/v2 v2.0.0 - github.com/hyperledger/fabric-protos-go-apiv2 v0.3.3 - google.golang.org/protobuf v1.34.2 -) - -require ( - github.com/go-openapi/jsonpointer v0.21.0 // indirect - github.com/go-openapi/jsonreference v0.21.0 // indirect - github.com/go-openapi/spec v0.21.0 // indirect - github.com/go-openapi/swag v0.23.0 // indirect - github.com/gobuffalo/envy v1.10.2 // indirect - github.com/gobuffalo/packd v1.0.2 // indirect - github.com/gobuffalo/packr v1.30.1 // indirect - github.com/joho/godotenv v1.5.1 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/mailru/easyjson v0.7.7 // indirect - github.com/rogpeppe/go-internal v1.12.0 // indirect - github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect - github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect - github.com/xeipuuv/gojsonschema v1.2.0 // indirect - golang.org/x/mod v0.17.0 // indirect - golang.org/x/net v0.24.0 // indirect - golang.org/x/sys v0.19.0 // indirect - golang.org/x/text v0.14.0 // indirect - google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect - google.golang.org/grpc v1.64.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) diff --git a/auction-dutch/chaincode-go/go.sum b/auction-dutch/chaincode-go/go.sum deleted file mode 100644 index 7c5e414c..00000000 --- a/auction-dutch/chaincode-go/go.sum +++ /dev/null @@ -1,132 +0,0 @@ -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= -github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= -github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= -github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= -github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= -github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= -github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= -github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= -github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= -github.com/gobuffalo/envy v1.10.2 h1:EIi03p9c3yeuRCFPOKcSfajzkLb3hrRjEpHGI8I2Wo4= -github.com/gobuffalo/envy v1.10.2/go.mod h1:qGAGwdvDsaEtPhfBzb3o0SfDea8ByGn9j8bKmVft9z8= -github.com/gobuffalo/logger v1.0.0/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs= -github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q= -github.com/gobuffalo/packd v1.0.2 h1:Yg523YqnOxGIWCp69W12yYBKsoChwI7mtu6ceM9Bwfw= -github.com/gobuffalo/packd v1.0.2/go.mod h1:sUc61tDqGMXON80zpKGp92lDb86Km28jfvX7IAyxFT8= -github.com/gobuffalo/packr v1.30.1 h1:hu1fuVR3fXEZR7rXNW3h8rqSML8EVAf6KNm0NKO/wKg= -github.com/gobuffalo/packr v1.30.1/go.mod h1:ljMyFO2EcrnzsHsN99cvbq055Y9OhRrIaviy289eRuk= -github.com/gobuffalo/packr/v2 v2.5.1/go.mod h1:8f9c96ITobJlPzI44jj+4tHnEKNt0xXWSVlXRN9X1Iw= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0-20240618210511-f7903324a8af h1:WT4NjX7Uk03GSeH++jF3a0wp4FhybTM86zDPCETvmSk= -github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0-20240618210511-f7903324a8af/go.mod h1:f/ER25FaBepxJugwpLhbD2hLAoZaZEVqkBjOcHjw72Y= -github.com/hyperledger/fabric-contract-api-go/v2 v2.0.0 h1:IDiCGVOBlRd6zpL0Y+f6V7IpBqa4/Z5JAK9SF7a5ea8= -github.com/hyperledger/fabric-contract-api-go/v2 v2.0.0/go.mod h1:pdqhe7ALf4lmXgQdprCyNWYdnCPxgj02Vhf8JF5w8po= -github.com/hyperledger/fabric-protos-go-apiv2 v0.3.3 h1:Xpd6fzG/KjAOHJsq7EQXY2l+qi/y8muxBaY7R6QWABk= -github.com/hyperledger/fabric-protos-go-apiv2 v0.3.3/go.mod h1:2pq0ui6ZWA0cC8J+eCErgnMDCS1kPOEYVY+06ZAK0qE= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= -github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= -github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= -github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= -golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= -google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/auction-dutch/chaincode-go/smart-contract/auction.go b/auction-dutch/chaincode-go/smart-contract/auction.go deleted file mode 100644 index e71ae843..00000000 --- a/auction-dutch/chaincode-go/smart-contract/auction.go +++ /dev/null @@ -1,512 +0,0 @@ -/* -SPDX-License-Identifier: Apache-2.0 -*/ - -package auction - -import ( - "bytes" - "crypto/sha256" - "encoding/json" - "fmt" - "sort" - - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" -) - -type SmartContract struct { - contractapi.Contract -} - -// Auction data -type Auction struct { - Type string `json:"objectType"` - ItemSold string `json:"item"` - Seller string `json:"seller"` - Quantity int `json:"quantity"` - Orgs []string `json:"organizations"` - PrivateBids map[string]BidHash `json:"privateBids"` - RevealedBids map[string]FullBid `json:"revealedBids"` - Winners []Winners `json:"winners"` - Price int `json:"price"` - Status string `json:"status"` - Auditor bool `json:"auditor"` -} - -// FullBid is the structure of a revealed bid -type FullBid struct { - Type string `json:"objectType"` - Quantity int `json:"quantity"` - Price int `json:"price"` - Org string `json:"org"` - Buyer string `json:"buyer"` -} - -// BidHash is the structure of a private bid -type BidHash struct { - Org string `json:"org"` - Hash string `json:"hash"` -} - -// Winners stores the winners of the auction -type Winners struct { - Buyer string `json:"buyer"` - Quantity int `json:"quantity"` -} - -const bidKeyType = "bid" - -// CreateAuction creates on auction on the public channel. The identity that -// submits the transacion becomes the seller of the auction -func (s *SmartContract) CreateAuction(ctx contractapi.TransactionContextInterface, auctionID string, itemsold string, quantity int, withAuditor string) error { - - // get ID of submitting client - clientID, err := s.GetSubmittingClientIdentity(ctx) - if err != nil { - return fmt.Errorf("failed to get client identity %v", err) - } - - // get org of submitting client - clientOrgID, err := ctx.GetClientIdentity().GetMSPID() - if err != nil { - return fmt.Errorf("failed to get client identity %v", err) - } - - auditor := false - - if withAuditor == "withAuditor" { - auditor = true - } - - // Create auction - bidders := make(map[string]BidHash) - revealedBids := make(map[string]FullBid) - - auction := Auction{ - Type: "auction", - ItemSold: itemsold, - Quantity: quantity, - Price: 0, - Seller: clientID, - Orgs: []string{clientOrgID}, - PrivateBids: bidders, - RevealedBids: revealedBids, - Winners: []Winners{}, - Status: "open", - Auditor: auditor, - } - - auctionJSON, err := json.Marshal(auction) - if err != nil { - return err - } - - // put auction into state - err = ctx.GetStub().PutState(auctionID, auctionJSON) - if err != nil { - return fmt.Errorf("failed to put auction in public data: %v", err) - } - - // set the seller of the auction as an endorser - err = setAssetStateBasedEndorsement(ctx, auctionID, []string{clientOrgID}, auditor) - if err != nil { - return fmt.Errorf("failed setting state based endorsement for new organization: %v", err) - } - - return nil -} - -// Bid is used to add a users bid to the auction. The bid is stored in the private -// data collection on the peer of the bidder's organization. The function returns -// the transaction ID so that users can identify and query their bid -func (s *SmartContract) Bid(ctx contractapi.TransactionContextInterface, auctionID string) (string, error) { - - // get bid from transient map - transientMap, err := ctx.GetStub().GetTransient() - if err != nil { - return "", fmt.Errorf("error getting transient: %v", err) - } - - bidJSON, ok := transientMap["bid"] - if !ok { - return "", fmt.Errorf("bid key not found in the transient map") - } - - // get the implicit collection name using the bidder's organization ID - collection, err := getCollectionName(ctx) - if err != nil { - return "", fmt.Errorf("failed to get implicit collection name: %v", err) - } - - // the bidder has to target their peer to store the bid - err = verifyClientOrgMatchesPeerOrg(ctx) - if err != nil { - return "", fmt.Errorf("cannot store bid on this peer, not a member of this org: %v", err) - } - - // the transaction ID is used as a unique index for the bid - txID := ctx.GetStub().GetTxID() - - // create a composite key using the transaction ID - bidKey, err := ctx.GetStub().CreateCompositeKey(bidKeyType, []string{auctionID, txID}) - if err != nil { - return "", fmt.Errorf("failed to create composite key: %v", err) - } - - // put the bid into the organization's implicit data collection - err = ctx.GetStub().PutPrivateData(collection, bidKey, bidJSON) - if err != nil { - return "", fmt.Errorf("failed to input price into collection: %v", err) - } - - // return the trannsaction ID so that the uset can identify their bid - return txID, nil -} - -// SubmitBid is used by the bidder to add the hash of that bid stored in private data to the -// auction. Note that this function alters the auction in private state, and needs -// to meet the auction endorsement policy. Transaction ID is used identify the bid -func (s *SmartContract) SubmitBid(ctx contractapi.TransactionContextInterface, auctionID string, txID string) error { - - // get the MSP ID of the bidder's org - clientOrgID, err := ctx.GetClientIdentity().GetMSPID() - if err != nil { - return fmt.Errorf("failed to get client MSP ID: %v", err) - } - - // get the auction from public state - auction, err := s.QueryAuction(ctx, auctionID) - if err != nil { - return fmt.Errorf("failed to get auction from public state %v", err) - } - - // the auction needs to be open for users to add their bid - status := auction.Status - if status != "open" { - return fmt.Errorf("cannot join closed or ended auction") - } - - // get the inplicit collection name of bidder's org - collection, err := getCollectionName(ctx) - if err != nil { - return fmt.Errorf("failed to get implicit collection name: %v", err) - } - - // use the transaction ID passed as a parameter to create composite bid key - bidKey, err := ctx.GetStub().CreateCompositeKey(bidKeyType, []string{auctionID, txID}) - if err != nil { - return fmt.Errorf("failed to create composite key: %v", err) - } - - // get the hash of the bid if found in private collection - bidHash, err := ctx.GetStub().GetPrivateDataHash(collection, bidKey) - if err != nil { - return fmt.Errorf("failed to read bid bash from collection: %v", err) - } - if bidHash == nil { - return fmt.Errorf("bid hash does not exist: %s", bidKey) - } - - // store the hash along with the bidder's organization - newHash := BidHash{ - Org: clientOrgID, - Hash: fmt.Sprintf("%x", bidHash), - } - - auction.PrivateBids[bidKey] = newHash - - // Add the bidding organization to the list of participating organization's if it is not already - orgs := auction.Orgs - if !(contains(orgs, clientOrgID)) { - newOrgs := append(orgs, clientOrgID) - auction.Orgs = newOrgs - - err = setAssetStateBasedEndorsement(ctx, auctionID, newOrgs, auction.Auditor) - if err != nil { - return fmt.Errorf("failed setting state based endorsement for new organization: %v", err) - } - } - - newAuctionJSON, _ := json.Marshal(auction) - - err = ctx.GetStub().PutState(auctionID, newAuctionJSON) - if err != nil { - return fmt.Errorf("failed to update auction: %v", err) - } - - return nil -} - -// RevealBid is used by a bidder to reveal their bid after the auction is closed -func (s *SmartContract) RevealBid(ctx contractapi.TransactionContextInterface, auctionID string, txID string) error { - - // get bid from transient map - transientMap, err := ctx.GetStub().GetTransient() - if err != nil { - return fmt.Errorf("error getting transient: %v", err) - } - - transientBidJSON, ok := transientMap["bid"] - if !ok { - return fmt.Errorf("bid key not found in the transient map") - } - - // get implicit collection name of organization ID - collection, err := getCollectionName(ctx) - if err != nil { - return fmt.Errorf("failed to get implicit collection name: %v", err) - } - - // use transaction ID to create composit bid key - bidKey, err := ctx.GetStub().CreateCompositeKey(bidKeyType, []string{auctionID, txID}) - if err != nil { - return fmt.Errorf("failed to create composite key: %v", err) - } - - // get bid hash of bid if private bid on the public ledger - bidHash, err := ctx.GetStub().GetPrivateDataHash(collection, bidKey) - if err != nil { - return fmt.Errorf("failed to read bid bash from collection: %v", err) - } - if bidHash == nil { - return fmt.Errorf("bid hash does not exist: %s", bidKey) - } - - // get auction from public state - auction, err := s.QueryAuction(ctx, auctionID) - if err != nil { - return fmt.Errorf("failed to get auction from public state %v", err) - } - - // Complete a series of three checks before we add the bid to the auction - - // check 1: check that the auction is closed. We cannot reveal an - // bid to an open auction - status := auction.Status - if status != "closed" { - return fmt.Errorf("cannot reveal bid for open or ended auction") - } - - // check 2: check that hash of revealed bid matches hash of private bid - // on the public ledger. This checks that the bidder is telling the truth - // about the value of their bid - - hash := sha256.New() - hash.Write(transientBidJSON) - calculatedBidJSONHash := hash.Sum(nil) - - // verify that the hash of the passed immutable properties matches the on-chain hash - if !bytes.Equal(calculatedBidJSONHash, bidHash) { - return fmt.Errorf("hash %x for bid JSON %s does not match hash in auction: %x", - calculatedBidJSONHash, - transientBidJSON, - bidHash, - ) - } - - // check 3; check hash of relealed bid matches hash of private bid that was - // added earlier. This ensures that the bid has not changed since it - // was added to the auction - - privateBidHashString := auction.PrivateBids[bidKey].Hash - - onChainBidHashString := fmt.Sprintf("%x", bidHash) - if privateBidHashString != onChainBidHashString { - return fmt.Errorf("hash %s for bid JSON %s does not match hash in auction: %s, bidder must have changed bid", - privateBidHashString, - transientBidJSON, - onChainBidHashString, - ) - } - - // we can add the bid to the auction if all checks have passed - type transientBidInput struct { - Quantity int `json:"quantity"` - Price int `json:"price"` - Org string `json:"org"` - Buyer string `json:"buyer"` - } - - // unmarshal bid imput - var bidInput transientBidInput - err = json.Unmarshal(transientBidJSON, &bidInput) - if err != nil { - return fmt.Errorf("failed to unmarshal JSON: %v", err) - } - - // get ID of submitting client - clientID, err := s.GetSubmittingClientIdentity(ctx) - if err != nil { - return fmt.Errorf("failed to get client identity %v", err) - } - - // marshal transient parameters and ID and MSPID into bid object - newBid := FullBid{ - Type: bidKeyType, - Quantity: bidInput.Quantity, - Price: bidInput.Price, - Org: bidInput.Org, - Buyer: bidInput.Buyer, - } - - // check 4: make sure that the transaction is being submitted is the bidder - if bidInput.Buyer != clientID { - return fmt.Errorf("permission denied, client id %v is not the owner of the bid", clientID) - } - - revealedBids := auction.RevealedBids - revealedBids[bidKey] = newBid - auction.RevealedBids = revealedBids - - auctionJSON, _ := json.Marshal(auction) - - // put auction with bid added back into state - err = ctx.GetStub().PutState(auctionID, auctionJSON) - if err != nil { - return fmt.Errorf("failed to update auction: %v", err) - } - - return nil -} - -// CloseAuction can be used by the seller to close the auction. This prevents -// bids from being added to the auction, and allows users to reveal their bid -func (s *SmartContract) CloseAuction(ctx contractapi.TransactionContextInterface, auctionID string) error { - - // get auction from public state - auction, err := s.QueryAuction(ctx, auctionID) - if err != nil { - return fmt.Errorf("failed to get auction from public state %v", err) - } - - // the auction can only be closed by the seller - - // get ID of submitting client - clientID, err := s.GetSubmittingClientIdentity(ctx) - if err != nil { - return fmt.Errorf("failed to get client identity %v", err) - } - - seller := auction.Seller - if seller != clientID { - return fmt.Errorf("auction can only be closed by seller: %v", err) - } - - status := auction.Status - if status != "open" { - return fmt.Errorf("cannot close auction that is not open") - } - - auction.Status = string("closed") - - closedAuctionJSON, _ := json.Marshal(auction) - - err = ctx.GetStub().PutState(auctionID, closedAuctionJSON) - if err != nil { - return fmt.Errorf("failed to close auction: %v", err) - } - - return nil -} - -// EndAuction both changes the auction status to closed and calculates the winners -// of the auction -func (s *SmartContract) EndAuction(ctx contractapi.TransactionContextInterface, auctionID string) error { - - // get auction from public state - auction, err := s.QueryAuction(ctx, auctionID) - if err != nil { - return fmt.Errorf("failed to get auction from public state %v", err) - } - - // Check that the auction is being ended by the seller - - // get ID of submitting client - clientID, err := s.GetSubmittingClientIdentity(ctx) - if err != nil { - return fmt.Errorf("failed to get client identity %v", err) - } - - seller := auction.Seller - if seller != clientID { - return fmt.Errorf("auction can only be ended by seller: %v", err) - } - - status := auction.Status - if status != "closed" { - return fmt.Errorf("can only end a closed auction") - } - - // get the list of revealed bids - - revealedBidMap := auction.RevealedBids - if len(auction.RevealedBids) == 0 { - return fmt.Errorf("no bids have been revealed, cannot end auction: %v", err) - } - - // sort the map of revealed bids to make it easier to calculate winners - // if bids are tied, fill smaller bids first - var bidders []FullBid - - for _, bid := range revealedBidMap { - bidders = append(bidders, bid) - } - - sort.Slice(bidders, func(p, q int) bool { - if bidders[p].Price > bidders[q].Price { - return true - } - if bidders[p].Price < bidders[q].Price { - return false - } - return bidders[p].Quantity < bidders[q].Quantity - }) - - i := 0 - remainingQuantity := auction.Quantity - - // calculate the winners - for remainingQuantity > 0 { - - // create the next winning bid - winner := Winners{ - Buyer: bidders[i].Buyer, - Quantity: bidders[i].Quantity, - } - - // add them to the list of winners and change the winning price - auction.Winners = append(auction.Winners, winner) - auction.Price = bidders[i].Price - - // Calculate the quantity that goes to the winner - // if there is sufficient quantity to give them the full bid - if remainingQuantity > bidders[i].Quantity { - remainingQuantity = remainingQuantity - bidders[i].Quantity - - // if there is not, give the remainder - } else { - auction.Winners[i].Quantity = remainingQuantity - remainingQuantity = 0 - } - i++ - if i == len(bidders) { - remainingQuantity = 0 - } - } - - // check if there is a winning bid that has yet to be revealed - err = checkForHigherBid(ctx, auction.Price, auction.RevealedBids, auction.PrivateBids) - if err != nil { - return fmt.Errorf("cannot end auction: %v", err) - } - - auction.Status = "ended" - - endedAuctionJSON, _ := json.Marshal(auction) - - err = ctx.GetStub().PutState(auctionID, endedAuctionJSON) - if err != nil { - return fmt.Errorf("failed to end auction: %v", err) - } - return nil -} diff --git a/auction-dutch/chaincode-go/smart-contract/auctionQueries.go b/auction-dutch/chaincode-go/smart-contract/auctionQueries.go deleted file mode 100644 index 67d42f61..00000000 --- a/auction-dutch/chaincode-go/smart-contract/auctionQueries.go +++ /dev/null @@ -1,136 +0,0 @@ -/* -SPDX-License-Identifier: Apache-2.0 -*/ - -package auction - -import ( - "encoding/json" - "fmt" - - "github.com/hyperledger/fabric-chaincode-go/v2/shim" - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" -) - -// QueryAuction allows all members of the channel to read a public auction -func (s *SmartContract) QueryAuction(ctx contractapi.TransactionContextInterface, auctionID string) (*Auction, error) { - - auctionJSON, err := ctx.GetStub().GetState(auctionID) - if err != nil { - return nil, fmt.Errorf("failed to get auction object %v: %v", auctionID, err) - } - if auctionJSON == nil { - return nil, fmt.Errorf("auction does not exist") - } - - var auction *Auction - err = json.Unmarshal(auctionJSON, &auction) - if err != nil { - return nil, err - } - - return auction, nil -} - -// QueryBid allows the submitter of the bid to read their bid from public state -func (s *SmartContract) QueryBid(ctx contractapi.TransactionContextInterface, auctionID string, txID string) (*FullBid, error) { - - err := verifyClientOrgMatchesPeerOrg(ctx) - if err != nil { - return nil, fmt.Errorf("failed to get implicit collection name: %v", err) - } - - clientID, err := s.GetSubmittingClientIdentity(ctx) - if err != nil { - return nil, fmt.Errorf("failed to get client identity %v", err) - } - - collection, err := getCollectionName(ctx) - if err != nil { - return nil, fmt.Errorf("failed to get implicit collection name: %v", err) - } - - bidKey, err := ctx.GetStub().CreateCompositeKey(bidKeyType, []string{auctionID, txID}) - if err != nil { - return nil, fmt.Errorf("failed to create composite key: %v", err) - } - - bidJSON, err := ctx.GetStub().GetPrivateData(collection, bidKey) - if err != nil { - return nil, fmt.Errorf("failed to get bid %v: %v", bidKey, err) - } - if bidJSON == nil { - return nil, fmt.Errorf("bid %v does not exist", bidKey) - } - - var bid *FullBid - err = json.Unmarshal(bidJSON, &bid) - if err != nil { - return nil, err - } - - // check that the client querying the bid is the bid owner - if bid.Buyer != clientID { - return nil, fmt.Errorf("permission denied, client id %v is not the owner of the bid", clientID) - } - - return bid, nil -} - -// checkForHigherBid is an internal function that is used to determine if a winning bid has yet to be revealed -func checkForHigherBid(ctx contractapi.TransactionContextInterface, auctionPrice int, revealedBidders map[string]FullBid, bidders map[string]BidHash) error { - - // Get MSP ID of peer org - peerMSPID, err := shim.GetMSPID() - if err != nil { - return fmt.Errorf("failed getting the peer's MSPID: %v", err) - } - - var error error - error = nil - - for bidKey, privateBid := range bidders { - - if _, bidInAuction := revealedBidders[bidKey]; bidInAuction { - - // bid is already revealed, no action to take - - } else { - - collection := "_implicit_org_" + privateBid.Org - - if privateBid.Org == peerMSPID { - - bidJSON, err := ctx.GetStub().GetPrivateData(collection, bidKey) - if err != nil { - return fmt.Errorf("failed to get bid %v: %v", bidKey, err) - } - if bidJSON == nil { - return fmt.Errorf("bid %v does not exist", bidKey) - } - - var bid *FullBid - err = json.Unmarshal(bidJSON, &bid) - if err != nil { - return err - } - - if bid.Price > auctionPrice { - error = fmt.Errorf("cannot close auction, bidder has a higher price: %v", err) - } - - } else { - - hash, err := ctx.GetStub().GetPrivateDataHash(collection, bidKey) - if err != nil { - return fmt.Errorf("failed to read bid hash from collection: %v", err) - } - if hash == nil { - return fmt.Errorf("bid hash does not exist: %s", bidKey) - } - } - } - } - - return error -} diff --git a/auction-dutch/chaincode-go/smart-contract/utils.go b/auction-dutch/chaincode-go/smart-contract/utils.go deleted file mode 100644 index 351826fb..00000000 --- a/auction-dutch/chaincode-go/smart-contract/utils.go +++ /dev/null @@ -1,205 +0,0 @@ -/* -SPDX-License-Identifier: Apache-2.0 -*/ - -package auction - -import ( - "encoding/base64" - "fmt" - - "github.com/hyperledger/fabric-chaincode-go/v2/shim" - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" - "github.com/hyperledger/fabric-protos-go-apiv2/common" - "github.com/hyperledger/fabric-protos-go-apiv2/msp" - "google.golang.org/protobuf/proto" -) - -func (s *SmartContract) GetSubmittingClientIdentity(ctx contractapi.TransactionContextInterface) (string, error) { - - b64ID, err := ctx.GetClientIdentity().GetID() - if err != nil { - return "", fmt.Errorf("failed to read clientID: %v", err) - } - decodeID, err := base64.StdEncoding.DecodeString(b64ID) - if err != nil { - return "", fmt.Errorf("failed to base64 decode clientID: %v", err) - } - return string(decodeID), nil -} - -// getCollectionName is an internal helper function to get collection of submitting client identity. -func getCollectionName(ctx contractapi.TransactionContextInterface) (string, error) { - - // Get the MSP ID of submitting client identity - clientMSPID, err := ctx.GetClientIdentity().GetMSPID() - if err != nil { - return "", fmt.Errorf("failed to get verified MSPID: %v", err) - } - - // Create the collection name - orgCollection := "_implicit_org_" + clientMSPID - - return orgCollection, nil -} - -// verifyClientOrgMatchesPeerOrg is an internal function used to verify that client org id matches peer org id. -func verifyClientOrgMatchesPeerOrg(ctx contractapi.TransactionContextInterface) error { - - clientMSPID, err := ctx.GetClientIdentity().GetMSPID() - if err != nil { - return fmt.Errorf("failed getting the client's MSPID: %v", err) - } - peerMSPID, err := shim.GetMSPID() - if err != nil { - return fmt.Errorf("failed getting the peer's MSPID: %v", err) - } - - if clientMSPID != peerMSPID { - return fmt.Errorf("client from org %v is not authorized to read or write private data from an org %v peer", clientMSPID, peerMSPID) - } - - return nil -} - -func contains(sli []string, str string) bool { - for _, a := range sli { - if a == str { - return true - } - } - return false -} - -func setAssetStateBasedEndorsement(ctx contractapi.TransactionContextInterface, assetId string, mspids []string, auditor bool) error { - - principals := make([]*msp.MSPPrincipal, len(mspids)) - participantSigsPolicy := make([]*common.SignaturePolicy, len(mspids)) - - for i, id := range mspids { - principal, err := proto.Marshal( - &msp.MSPRole{ - Role: msp.MSPRole_PEER, - MspIdentifier: id, - }, - ) - if err != nil { - return err - } - principals[i] = &msp.MSPPrincipal{ - PrincipalClassification: msp.MSPPrincipal_ROLE, - Principal: principal, - } - participantSigsPolicy[i] = &common.SignaturePolicy{ - Type: &common.SignaturePolicy_SignedBy{ - SignedBy: int32(i), - }, - } - } - - if !auditor { - // create the defalt policy for an auction without an auditor - - policy := &common.SignaturePolicyEnvelope{ - Version: 0, - Rule: &common.SignaturePolicy{ - Type: &common.SignaturePolicy_NOutOf_{ - NOutOf: &common.SignaturePolicy_NOutOf{ - N: int32(len(mspids)), - Rules: participantSigsPolicy, - }, - }, - }, - Identities: principals, - } - - spBytes, err := proto.Marshal(policy) - if err != nil { - return err - } - err = ctx.GetStub().SetStateValidationParameter(assetId, spBytes) - if err != nil { - return fmt.Errorf("failed to set validation parameter on auction: %v", err) - } - } else { - - // create the defalt policy for an auction with an auditor - - // create the auditor identity and signature policy - auditorMSP, err := proto.Marshal( - &msp.MSPRole{ - Role: msp.MSPRole_PEER, - MspIdentifier: "Org3MSP", - }, - ) - if err != nil { - return err - } - principals = append(principals, &msp.MSPPrincipal{ - PrincipalClassification: msp.MSPPrincipal_ROLE, - Principal: auditorMSP, - }, - ) - // Create the policies in case the auditor is needed. In this case, an - // auditor and 1 participant can update the auction. - auditorPolicies := make([]*common.SignaturePolicy, 2) - auditorPolicies[0] = &common.SignaturePolicy{ - Type: &common.SignaturePolicy_SignedBy{ - SignedBy: int32(len(principals) - 1), - }, - } - auditorPolicies[1] = &common.SignaturePolicy{ - Type: &common.SignaturePolicy_NOutOf_{ - NOutOf: &common.SignaturePolicy_NOutOf{ - N: 1, - Rules: participantSigsPolicy, - }, - }, - } - - // For two organizations, the auditor policy below is equivilent to - // AND(auditor, OR(Org1, Org2)) - policies := make([]*common.SignaturePolicy, 2) - policies[0] = &common.SignaturePolicy{ - Type: &common.SignaturePolicy_NOutOf_{ - NOutOf: &common.SignaturePolicy_NOutOf{ - N: 2, - Rules: auditorPolicies, - }, - }, - } - // Participants can also update the auction without an auditor - policies[1] = &common.SignaturePolicy{ - Type: &common.SignaturePolicy_NOutOf_{ - NOutOf: &common.SignaturePolicy_NOutOf{ - N: int32(len(mspids)), - Rules: participantSigsPolicy, - }, - }, - } - // Either the auditor policy or the participant policy can update - // the auction. For example, for two organizations, the full policy would be - // equivilent to OR(AND(Org1, Org2),AND(auditor, OR(Org1, Org2))) - policy := &common.SignaturePolicyEnvelope{ - Version: 0, - Rule: &common.SignaturePolicy{ - Type: &common.SignaturePolicy_NOutOf_{ - NOutOf: &common.SignaturePolicy_NOutOf{ - N: 1, - Rules: policies, - }, - }, - }, - Identities: principals, - } - spBytes, err := proto.Marshal(policy) - if err != nil { - return err - } - err = ctx.GetStub().SetStateValidationParameter(assetId, spBytes) - if err != nil { - return fmt.Errorf("failed to set validation parameter on auction: %v", err) - } - } - return nil -} diff --git a/auction-dutch/chaincode-go/smartContract.go b/auction-dutch/chaincode-go/smartContract.go deleted file mode 100644 index 939a519c..00000000 --- a/auction-dutch/chaincode-go/smartContract.go +++ /dev/null @@ -1,23 +0,0 @@ -/* -SPDX-License-Identifier: Apache-2.0 -*/ - -package main - -import ( - "log" - - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" - auction "github.com/hyperledger/fabric-samples/auction/dutch-auction/chaincode-go/smart-contract" -) - -func main() { - auctionSmartContract, err := contractapi.NewChaincode(&auction.SmartContract{}) - if err != nil { - log.Panicf("Error creating auction chaincode: %v", err) - } - - if err := auctionSmartContract.Start(); err != nil { - log.Panicf("Error starting auction chaincode: %v", err) - } -} diff --git a/auction-simple/README.md b/auction-simple/README.md deleted file mode 100644 index e6bb6308..00000000 --- a/auction-simple/README.md +++ /dev/null @@ -1,410 +0,0 @@ -## Simple blind auction sample - -The simple blind auction sample uses Hyperledger Fabric to run an auction where bids are kept private until the auction period is over. Instead of displaying the full bid on the public ledger, buyers can only see hashes of other bids while bidding is underway. This prevents buyers from changing their bids in response to bids submitted by others. After the bidding period ends, participants reveal their bid to try to win the auction. The organizations participating in the auction verify that a revealed bid matches the hash on the public ledger. Whichever has the highest bid wins. - -A user that wants to sell one item can use the smart contract to create an auction. The auction is stored on the channel ledger and can be read by all channel members. The auctions created by the smart contract are run in three steps: -1. Each auction is created with the status **open**. While the auction is open, buyers can add new bids to the auction. The full bids of each buyer are stored in the implicit private data collections of their organization. After the bid is created, the bidder can submit the hash of the bid to the auction. A bid is added to the auction in two steps because the transaction that creates the bid only needs to be endorsed by a peer of the bidders organization, while a transaction that updates the auction may need to be endorsed by multiple organizations. When the bid is added to the auction, the bidder's organization is added to the list of organizations that need to endorse any updates to the auction. -2. The auction is **closed** to prevent additional bids from being added to the auction. After the auction is closed, bidders that submitted bids to the auction can reveal their full bid. Only revealed bids can win the auction. -3. The auction is **ended** to calculate the winner from the set of revealed bids. All organizations participating in the auction calculate the price that clears the auction and the winning bid. The seller can end the auction only if all bidding organizations endorse the same winner and price. - -Before endorsing the transaction that ends the auction, each organization queries the implicit private data collection on their peers to check if any organization member has a winning bid that has not yet been revealed. If a winning bid is found, the organization will withhold their endorsement and prevent the auction from being closed. This prevents the seller from ending the auction prematurely, or colluding with buyers to end the auction at an artificially low price. - -The sample uses several Fabric features to make the auction private and secure. Bids are stored in private data collections to prevent bids from being distributed to other peers in the channel. When bidding is closed, the auction smart contract uses the `GetPrivateDataHash()` API to verify that the bid stored in private data is the same bid that is being revealed. State based endorsement is used to add the organization of each bidder to the auction endorsement policy. The smart contract uses the `GetClientIdentity.GetID()` API to ensure that only the potential buyer can read their bid from private state and only the seller can close or end the auction. - -This tutorial uses the auction smart contract in a scenario where one seller wants to auction a painting. Four potential buyers from two different organizations will submit bids to the auction and try to win the auction. - -## Deploy the chaincode - -We will run the auction smart contract using the Fabric test network. Open a command terminal and navigate to the test network directory: -``` -cd fabric-samples/test-network -``` - -You can then run the following command to deploy the test network. -``` -./network.sh up createChannel -ca -``` - -Note that we use the `-ca` flag to deploy the network using certificate authorities. We will use the CA to register and enroll our sellers and buyers. - -Run the following command to deploy the auction smart contract. We will override the default endorsement policy to allow any channel member to create an auction without requiring an endorsement from another organization. -``` -./network.sh deployCC -ccn auction -ccp ../auction-simple/chaincode-go/ -ccl go -ccep "OR('Org1MSP.peer','Org2MSP.peer')" -``` - -## Install the application dependencies - -We will interact with the auction smart contract through a set of Node.js applications. Change into the `application-javascript` directory: -``` -cd fabric-samples/auction-simple/application-javascript -``` - -From this directory, run the following command to download the application dependencies: -``` -npm install -``` - -## Register and enroll the application identities - -To interact with the network, you will need to enroll the Certificate Authority administrators of Org1 and Org2. You can use the `enrollAdmin.js` program for this task. Run the following command to enroll the Org1 admin: -``` -node enrollAdmin.js org1 -``` -You should see the logs of the admin wallet being created on your local file system. Now run the command to enroll the CA admin of Org2: -``` -node enrollAdmin.js org2 -``` - -We can use the CA admins of both organizations to register and enroll the identities of the seller that will create the auction and the bidders who will try to purchase the painting. - -Run the following command to register and enroll the seller identity that will create the auction. The seller will belong to Org1. -``` -node registerEnrollUser.js org1 seller -``` - -You should see the logs of the seller wallet being created as well. Run the following commands to register and enroll 2 bidders from Org1 and another 2 bidders from Org2: -``` -node registerEnrollUser.js org1 bidder1 -node registerEnrollUser.js org1 bidder2 -node registerEnrollUser.js org2 bidder3 -node registerEnrollUser.js org2 bidder4 -``` - -## Create the auction - -The seller from Org1 would like to create an auction to sell a vintage Matchbox painting. Run the following command to use the seller wallet to run the `createAuction.js` application. The program will submit a transaction to the network that creates the auction on the channel ledger. The organization and identity name are passed to the application to use the wallet that was created by the `registerEnrollUser.js` application. The seller needs to provide an ID for the auction and the item to be sold to create the auction: -``` -node createAuction.js org1 seller PaintingAuction painting -``` - -After the transaction is complete, the `createAuction.js` application will query the auction stored in the public channel ledger: -``` -*** Result: Auction: { - "objectType": "auction", - "item": "painting", - "seller": "x509::CN=seller,OU=client+OU=org1+OU=department1::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US", - "organizations": [ - "Org1MSP" - ], - "privateBids": {}, - "revealedBids": {}, - "winner": "", - "price": 0, - "status": "open" -} -``` -The smart contract uses the `GetClientIdentity().GetID()` API to read the identity that creates the auction and defines that identity as the auction `"seller"`. The seller is identified by the name and issuer of the seller's certificate. - -## Bid on the auction - -We can now use the bidder wallets to submit bids to the auction: - -### Bid as bidder1 - -Bidder1 will create a bid to purchase the painting for 800 dollars. -``` -node bid.js org1 bidder1 PaintingAuction 800 -``` - -The application will query the bid after it is created: -``` -*** Result: Bid: { - "objectType": "bid", - "price": 800, - "org": "Org1MSP", - "bidder": "x509::CN=bidder1,OU=client+OU=org1+OU=department1::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US" -} -``` - -The bid is stored in the Org1 implicit data collection. The `"bidder"` parameter is the information from the certificate of the user that created the bid. Only this identity will be able can query the bid from private state or reveal the bid during the auction. - -The `bid.js` application also prints the bidID: -``` -*** Result ***SAVE THIS VALUE*** BidID: 67d85ef08e32de20994c816362d0952fe5c2ae3f2d1083600c3ac61f65a89f60 -``` - -The BidID acts as the unique identifier for the bid. This ID allows you to query the bid using the `queryBid.js` program and add the bid to the auction. Save the bidID returned by the application as an environment variable in your terminal: -``` -export BIDDER1_BID_ID=67d85ef08e32de20994c816362d0952fe5c2ae3f2d1083600c3ac61f65a89f60 -``` -This value will be different for each transaction, so you will need to use the value returned in your terminal. - -Now that the bid has been created, you can submit the bid to the auction. Run the following command to submit the bid that was just created: -``` -node submitBid.js org1 bidder1 PaintingAuction $BIDDER1_BID_ID -``` - -The hash of bid will be added to the list private bids in that have been submitted to `PaintingAuction`. Storing the hash in the public auction allows users to accurately reveal the bid after bidding is closed. The application will query the auction to verify that the bid was added: -``` -*** Result: Auction: { - "objectType": "auction", - "item": "painting", - "seller": "x509::CN=seller,OU=client+OU=org1+OU=department1::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US", - "organizations": [ - "Org1MSP" - ], - "privateBids": { - "\u0000bid\u0000PaintingAuction\u00005c049b0b4552d34c88e0f8fb5abca31fa04472b7e1336a16650ac8cfb0b16472\u0000": { - "org": "Org1MSP", - "hash": "0b8bbdb96b1d252e71ac1ed71df3580f7a0e31a743a4a09bbf5196dffef426b2" - } - }, - "revealedBids": {}, - "winner": "", - "price": 0, - "status": "open" -} -``` - -### Bid as bidder2 - -Let's submit another bid. Bidder2 would like to purchase the painting for 500 dollars. -``` -node bid.js org1 bidder2 PaintingAuction 500 -``` - -Save the Bid ID returned by the application: -``` -export BIDDER2_BID_ID=0fa8b3b15923966f205a1f5ebd163d2707d069ffa055105114fc654d225f511d -``` - -Submit bidder2's bid to the auction: -``` -node submitBid.js org1 bidder2 PaintingAuction $BIDDER2_BID_ID -``` - -### Bid as bidder3 from Org2 - -Bidder3 will bid 700 dollars for the painting: -``` -node bid.js org2 bidder3 PaintingAuction 700 -``` - -Save the Bid ID returned by the application: -``` -export BIDDER3_BID_ID=cda8bb2849fc0553efb036c56ea86d82791a695b5641941dac797dc6e2d75768 -``` - -Add bidder3's bid to the auction: -``` -node submitBid.js org2 bidder3 PaintingAuction $BIDDER3_BID_ID -``` - -Because bidder3 belongs to Org2, submitting the bid will add Org2 to the list of participating organizations. You can see the Org2 MSP ID has been added to the list of `"organizations"` in the updated auction returned by the application: -``` -*** Result: Auction: { - "objectType": "auction", - "item": "painting", - "seller": "x509::CN=seller,OU=client+OU=org1+OU=department1::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US", - "organizations": [ - "Org1MSP", - "Org2MSP" - ], - "privateBids": { - "\u0000bid\u0000PaintingAuction\u00001b9dc0006fef10413df5cca927cabdf73ab854fe92b7a7b2eebfa00961fdac67\u0000": { - "org": "Org1MSP", - "hash": "15cd9a3e12825017f3e758499ac6138ebbe1adec4c49cc6ea6a0973fc6514666" - }, - "\u0000bid\u0000PaintingAuction\u00005c049b0b4552d34c88e0f8fb5abca31fa04472b7e1336a16650ac8cfb0b16472\u0000": { - "org": "Org1MSP", - "hash": "0b8bbdb96b1d252e71ac1ed71df3580f7a0e31a743a4a09bbf5196dffef426b2" - }, - "\u0000bid\u0000PaintingAuction\u00005ee4fa53b54ea0821e57a6884a1ada5eb04f136ee222e92d7399bcdf47556ea1\u0000": { - "org": "Org2MSP", - "hash": "14d47d17acceceb483e87c14a4349844874fce549d71c6a23457d953ed8ffbd3" - } - }, - "revealedBids": {}, - "winner": "", - "price": 0, - "status": "open" -} -``` - -Now that a bid from Org2 has been added to the auction, any updates to the auction need to be endorsed by the Org2 peer. The applications will use `"organizations"` field to specify which organizations need to endorse submitting a new bid, revealing a bid, or updating the auction status. - -### Bid as bidder4 - -Bidder4 from Org2 would like to purchase the painting for 900 dollars: -``` -node bid.js org2 bidder4 PaintingAuction 900 -``` - -Save the Bid ID returned by the application: -``` -export BIDDER4_BID_ID=83861eb17715ff537a1e73cd2d08509dc7199572806a5368706516759af1a257 -``` - -Add bidder4's bid to the auction: -``` -node submitBid.js org2 bidder4 PaintingAuction $BIDDER4_BID_ID -``` - -## Close the auction - -Now that all four bidders have joined the auction, the seller would like to close the auction and allow buyers to reveal their bids. The seller identity that created the auction needs to submit the transaction: -``` -node closeAuction.js org1 seller PaintingAuction -``` - -The application will query the auction to allow you to verify that the auction status has changed to closed. As a test, you can try to create and submit a new bid to verify that no new bids can be added to the auction. - -## Reveal bids - -After the auction is closed, bidders can try to win the auction by revealing their bids. The transaction to reveal a bid needs to pass four checks: -1. The auction is closed. -2. The transaction was submitted by the identity that created the bid. -3. The hash of the revealed bid matches the hash of the bid on the channel ledger. This confirms that the bid is the same as the bid that is stored in the private data collection. -4. The hash of the revealed bid matches the hash that was submitted to the auction. This confirms that the bid was not altered after the auction was closed. - -Use the `revealBid.js` application to reveal the bid of Bidder1: -``` -node revealBid.js org1 bidder1 PaintingAuction $BIDDER1_BID_ID -``` - -The full bid details, including the price, are now visible: -``` -*** Result: Auction: { - "objectType": "auction", - "item": "painting", - "seller": "x509::CN=seller,OU=client+OU=org1+OU=department1::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US", - "organizations": [ - "Org1MSP", - "Org2MSP" - ], - "privateBids": { - "\u0000bid\u0000PaintingAuction\u000019a7a0dd2c5456a3f79c2f9ccb09dddd0f1c9ece514dfea7cbea06e7cbc79855\u0000": { - "org": "Org2MSP", - "hash": "08db66c6cc226577a3153dadeb0b77d3834162fcf5f008b344058a1bc5c1b3a4" - }, - "\u0000bid\u0000PaintingAuction\u00001b9dc0006fef10413df5cca927cabdf73ab854fe92b7a7b2eebfa00961fdac67\u0000": { - "org": "Org1MSP", - "hash": "15cd9a3e12825017f3e758499ac6138ebbe1adec4c49cc6ea6a0973fc6514666" - }, - "\u0000bid\u0000PaintingAuction\u00005c049b0b4552d34c88e0f8fb5abca31fa04472b7e1336a16650ac8cfb0b16472\u0000": { - "org": "Org1MSP", - "hash": "0b8bbdb96b1d252e71ac1ed71df3580f7a0e31a743a4a09bbf5196dffef426b2" - }, - "\u0000bid\u0000PaintingAuction\u00005ee4fa53b54ea0821e57a6884a1ada5eb04f136ee222e92d7399bcdf47556ea1\u0000": { - "org": "Org2MSP", - "hash": "14d47d17acceceb483e87c14a4349844874fce549d71c6a23457d953ed8ffbd3" - } - }, - "revealedBids": { - "\u0000bid\u0000PaintingAuction\u00005c049b0b4552d34c88e0f8fb5abca31fa04472b7e1336a16650ac8cfb0b16472\u0000": { - "objectType": "bid", - "price": 800, - "org": "Org1MSP", - "bidder": "x509::CN=bidder1,OU=client+OU=org1+OU=department1::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US" - } - }, - "winner": "", - "price": 0, - "status": "closed" -} -``` - -Bidder3 from Org2 will also reveal their bid: -``` -node revealBid.js org2 bidder3 PaintingAuction $BIDDER3_BID_ID -``` - -If the auction ended now, Bidder1 would win. Let's try to end the auction using the seller identity and see what happens. - -``` -node endAuction.js org1 seller PaintingAuction -``` - -The output should look something like the following: - -``` ---> Submit the transaction to end the auction -2021-01-28T16:47:27.501Z - error: [DiscoveryHandler]: compareProposalResponseResults[undefined] - read/writes result sets do not match index=1 -2021-01-28T16:47:27.503Z - error: [Transaction]: Error: No valid responses from any peers. Errors: - peer=undefined, status=grpc, message=Peer endorsements do not match -******** FAILED to submit bid: Error: No valid responses from any peers. Errors: - peer=undefined, status=grpc, message=Peer endorsements do not match -``` - -Instead of ending the auction, the transaction results in an endorsement policy failure. The end of the auction needs to be endorsed by Org2. Before endorsing the transaction, the Org2 peer queries its private data collection for any winning bids that have not yet been revealed. Because Bidder4 created a bid that is above the winning price, the Org2 peer refuses to endorse the transaction that would end the auction. - -Before we can end the auction, we need to reveal the bid from bidder4. -``` -node revealBid.js org2 bidder4 PaintingAuction $BIDDER4_BID_ID -``` - -Bidder2 from Org1 would not win the auction in either case. As a result, Bidder2 decides not to reveal their bid. - -## End the auction - -Now that the winning bids have been revealed, we can end the auction: -``` -node endAuction org1 seller PaintingAuction -``` - -The transaction was successfully endorsed by both Org1 and Org2, who both calculated the same price and winner. The winning bidder is listed along with the price: -``` -*** Result: Auction: { - "objectType": "auction", - "item": "painting", - "seller": "x509::CN=seller,OU=client+OU=org1+OU=department1::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US", - "organizations": [ - "Org1MSP", - "Org2MSP" - ], - "privateBids": { - "\u0000bid\u0000PaintingAuction\u000019a7a0dd2c5456a3f79c2f9ccb09dddd0f1c9ece514dfea7cbea06e7cbc79855\u0000": { - "org": "Org2MSP", - "hash": "08db66c6cc226577a3153dadeb0b77d3834162fcf5f008b344058a1bc5c1b3a4" - }, - "\u0000bid\u0000PaintingAuction\u00001b9dc0006fef10413df5cca927cabdf73ab854fe92b7a7b2eebfa00961fdac67\u0000": { - "org": "Org1MSP", - "hash": "15cd9a3e12825017f3e758499ac6138ebbe1adec4c49cc6ea6a0973fc6514666" - }, - "\u0000bid\u0000PaintingAuction\u00005c049b0b4552d34c88e0f8fb5abca31fa04472b7e1336a16650ac8cfb0b16472\u0000": { - "org": "Org1MSP", - "hash": "0b8bbdb96b1d252e71ac1ed71df3580f7a0e31a743a4a09bbf5196dffef426b2" - }, - "\u0000bid\u0000PaintingAuction\u00005ee4fa53b54ea0821e57a6884a1ada5eb04f136ee222e92d7399bcdf47556ea1\u0000": { - "org": "Org2MSP", - "hash": "14d47d17acceceb483e87c14a4349844874fce549d71c6a23457d953ed8ffbd3" - } - }, - "revealedBids": { - "\u0000bid\u0000PaintingAuction\u000019a7a0dd2c5456a3f79c2f9ccb09dddd0f1c9ece514dfea7cbea06e7cbc79855\u0000": { - "objectType": "bid", - "price": 900, - "org": "Org2MSP", - "bidder": "x509::CN=bidder4,OU=client+OU=org2+OU=department1::CN=ca.org2.example.com,O=org2.example.com,L=Hursley,ST=Hampshire,C=UK" - }, - "\u0000bid\u0000PaintingAuction\u00005c049b0b4552d34c88e0f8fb5abca31fa04472b7e1336a16650ac8cfb0b16472\u0000": { - "objectType": "bid", - "price": 800, - "org": "Org1MSP", - "bidder": "x509::CN=bidder1,OU=client+OU=org1+OU=department1::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US" - }, - "\u0000bid\u0000PaintingAuction\u00005ee4fa53b54ea0821e57a6884a1ada5eb04f136ee222e92d7399bcdf47556ea1\u0000": { - "objectType": "bid", - "price": 700, - "org": "Org2MSP", - "bidder": "x509::CN=bidder3,OU=client+OU=org2+OU=department1::CN=ca.org2.example.com,O=org2.example.com,L=Hursley,ST=Hampshire,C=UK" - } - }, - "winner": "x509::CN=bidder4,OU=client+OU=org2+OU=department1::CN=ca.org2.example.com,O=org2.example.com,L=Hursley,ST=Hampshire,C=UK", - "price": 900, - "status": "ended" -} -``` - -## Clean up - -When your are done using the auction smart contract, you can bring down the network and clean up the environment. In the `auction-simple/application-javascript` directory, run the following command to remove the wallets used to run the applications: -``` -rm -rf wallet -``` - -You can then navigate to the test network directory and bring down the network: -```` -cd ../../test-network/ -./network.sh down -```` diff --git a/auction-simple/application-javascript/.eslintignore b/auction-simple/application-javascript/.eslintignore deleted file mode 100644 index 15958470..00000000 --- a/auction-simple/application-javascript/.eslintignore +++ /dev/null @@ -1,5 +0,0 @@ -# -# SPDX-License-Identifier: Apache-2.0 -# - -coverage diff --git a/auction-simple/application-javascript/.eslintrc.js b/auction-simple/application-javascript/.eslintrc.js deleted file mode 100644 index 20d4fcbd..00000000 --- a/auction-simple/application-javascript/.eslintrc.js +++ /dev/null @@ -1,36 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ - -module.exports = { - env: { - node: true, - mocha: true - }, - parserOptions: { - ecmaVersion: 8, - sourceType: 'script' - }, - extends: 'eslint:recommended', - rules: { - indent: ['error', 'tab'], - 'linebreak-style': ['error', 'unix'], - quotes: ['error', 'single'], - semi: ['error', 'always'], - 'no-unused-vars': ['error', { args: 'none' }], - 'no-console': 'off', - curly: 'error', - eqeqeq: 'error', - 'no-throw-literal': 'error', - strict: 'error', - 'no-var': 'error', - 'dot-notation': 'error', - 'no-trailing-spaces': 'error', - 'no-use-before-define': 'error', - 'no-useless-call': 'error', - 'no-with': 'error', - 'operator-linebreak': 'error', - yoda: 'error', - 'quote-props': ['error', 'as-needed'] - } -}; diff --git a/auction-simple/application-javascript/bid.js b/auction-simple/application-javascript/bid.js deleted file mode 100644 index d4b4de56..00000000 --- a/auction-simple/application-javascript/bid.js +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const { Gateway, Wallets } = require('fabric-network'); -const path = require('path'); -const { buildCCPOrg1, buildCCPOrg2, buildWallet, prettyJSONString} = require('../../test-application/javascript/AppUtil.js'); - -const myChannel = 'mychannel'; -const myChaincodeName = 'auction'; - -async function bid(ccp,wallet,user,orgMSP,auctionID,price) { - try { - - const gateway = new Gateway(); - // Connect using Discovery enabled - - await gateway.connect(ccp, - { wallet: wallet, identity: user, discovery: { enabled: true, asLocalhost: true } }); - - const network = await gateway.getNetwork(myChannel); - const contract = network.getContract(myChaincodeName); - - console.log('\n--> Evaluate Transaction: get your client ID'); - let bidder = await contract.evaluateTransaction('GetSubmittingClientIdentity'); - console.log('*** Result: Bidder ID is ' + bidder.toString()); - - let bidData = { objectType: 'bid', price: parseInt(price), org: orgMSP, bidder: bidder.toString()}; - - let statefulTxn = contract.createTransaction('Bid'); - statefulTxn.setEndorsingOrganizations(orgMSP); - let tmapData = Buffer.from(JSON.stringify(bidData)); - statefulTxn.setTransient({ - bid: tmapData - }); - - let bidID = statefulTxn.getTransactionId(); - - console.log('\n--> Submit Transaction: Create the bid that is stored in your organization\'s private data collection'); - await statefulTxn.submit(auctionID); - console.log('*** Result: committed'); - console.log('*** Result ***SAVE THIS VALUE*** BidID: ' + bidID.toString()); - - console.log('\n--> Evaluate Transaction: read the bid that was just created'); - let result = await contract.evaluateTransaction('QueryBid',auctionID,bidID); - console.log('*** Result: Bid: ' + prettyJSONString(result.toString())); - - gateway.disconnect(); - } catch (error) { - console.error(`******** FAILED to submit bid: ${error}`); - if (error.stack) { - console.error(error.stack); - } - process.exit(1); - } -} - -async function main() { - try { - - if (process.argv[2] === undefined || process.argv[3] === undefined || - process.argv[4] === undefined || process.argv[5] === undefined) { - console.log('Usage: node bid.js org userID auctionID price'); - process.exit(1); - } - - const org = process.argv[2]; - const user = process.argv[3]; - const auctionID = process.argv[4]; - const price = process.argv[5]; - - if (org === 'Org1' || org === 'org1') { - - const orgMSP = 'Org1MSP'; - const ccp = buildCCPOrg1(); - const walletPath = path.join(__dirname, 'wallet/org1'); - const wallet = await buildWallet(Wallets, walletPath); - await bid(ccp,wallet,user,orgMSP,auctionID,price); - } - else if (org === 'Org2' || org === 'org2') { - - const orgMSP = 'Org2MSP'; - const ccp = buildCCPOrg2(); - const walletPath = path.join(__dirname, 'wallet/org2'); - const wallet = await buildWallet(Wallets, walletPath); - await bid(ccp,wallet,user,orgMSP,auctionID,price); - } else { - console.log('Usage: node bid.js org userID auctionID price'); - console.log('Org must be Org1 or Org2'); - } - } catch (error) { - console.error(`******** FAILED to run the application: ${error}`); - process.exit(1); - } -} - -main(); diff --git a/auction-simple/application-javascript/closeAuction.js b/auction-simple/application-javascript/closeAuction.js deleted file mode 100644 index b637e761..00000000 --- a/auction-simple/application-javascript/closeAuction.js +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const { Gateway, Wallets } = require('fabric-network'); -const path = require('path'); -const { buildCCPOrg1, buildCCPOrg2, buildWallet, prettyJSONString} = require('../../test-application/javascript/AppUtil.js'); - -const myChannel = 'mychannel'; -const myChaincodeName = 'auction'; - -async function closeAuction(ccp,wallet,user,auctionID) { - try { - - const gateway = new Gateway(); - - // Connect using Discovery enabled - await gateway.connect(ccp, - { wallet: wallet, identity: user, discovery: { enabled: true, asLocalhost: true } }); - - const network = await gateway.getNetwork(myChannel); - const contract = network.getContract(myChaincodeName); - - // Query the auction to get the list of endorsing orgs. - let auctionString = await contract.evaluateTransaction('QueryAuction',auctionID); - let auctionJSON = JSON.parse(auctionString); - - let statefulTxn = contract.createTransaction('CloseAuction'); - - if (auctionJSON.organizations.length === 2) { - statefulTxn.setEndorsingOrganizations(auctionJSON.organizations[0],auctionJSON.organizations[1]); - } else { - statefulTxn.setEndorsingOrganizations(auctionJSON.organizations[0]); - } - - console.log('\n--> Submit Transaction: close auction'); - await statefulTxn.submit(auctionID); - console.log('*** Result: committed'); - - console.log('\n--> Evaluate Transaction: query the updated auction'); - let result = await contract.evaluateTransaction('QueryAuction',auctionID); - console.log('*** Result: Auction: ' + prettyJSONString(result.toString())); - - gateway.disconnect(); - } catch (error) { - console.error(`******** FAILED to submit bid: ${error}`); - process.exit(1); - } -} - -async function main() { - try { - - if (process.argv[2] === undefined || process.argv[3] === undefined || - process.argv[4] === undefined) { - console.log('Usage: node closeAuction.js org userID auctionID'); - process.exit(1); - } - - const org = process.argv[2]; - const user = process.argv[3]; - const auctionID = process.argv[4]; - - if (org === 'Org1' || org === 'org1') { - const ccp = buildCCPOrg1(); - const walletPath = path.join(__dirname, 'wallet/org1'); - const wallet = await buildWallet(Wallets, walletPath); - await closeAuction(ccp,wallet,user,auctionID); - } - else if (org === 'Org2' || org === 'org2') { - const ccp = buildCCPOrg2(); - const walletPath = path.join(__dirname, 'wallet/org2'); - const wallet = await buildWallet(Wallets, walletPath); - await closeAuction(ccp,wallet,user,auctionID); - } else { - console.log('Usage: node closeAuction.js org userID auctionID '); - console.log('Org must be Org1 or Org2'); - } - } catch (error) { - console.error(`******** FAILED to run the application: ${error}`); - if (error.stack) { - console.error(error.stack); - } - process.exit(1); - } -} - - -main(); diff --git a/auction-simple/application-javascript/createAuction.js b/auction-simple/application-javascript/createAuction.js deleted file mode 100644 index a05d4f96..00000000 --- a/auction-simple/application-javascript/createAuction.js +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const { Gateway, Wallets } = require('fabric-network'); -const path = require('path'); -const { buildCCPOrg1, buildCCPOrg2, buildWallet, prettyJSONString} = require('../../test-application/javascript/AppUtil.js'); - -const myChannel = 'mychannel'; -const myChaincodeName = 'auction'; - -async function createAuction(ccp,wallet,user,auctionID,item) { - try { - - const gateway = new Gateway(); - - // Connect using Discovery enabled - await gateway.connect(ccp, - { wallet: wallet, identity: user, discovery: { enabled: true, asLocalhost: true } }); - - const network = await gateway.getNetwork(myChannel); - const contract = network.getContract(myChaincodeName); - - let statefulTxn = contract.createTransaction('CreateAuction'); - - console.log('\n--> Submit Transaction: Propose a new auction'); - await statefulTxn.submit(auctionID,item); - console.log('*** Result: committed'); - - console.log('\n--> Evaluate Transaction: query the auction that was just created'); - let result = await contract.evaluateTransaction('QueryAuction',auctionID); - console.log('*** Result: Auction: ' + prettyJSONString(result.toString())); - - gateway.disconnect(); - } catch (error) { - console.error(`******** FAILED to submit bid: ${error}`); - } -} - -async function main() { - try { - - if (process.argv[2] === undefined || process.argv[3] === undefined || - process.argv[4] === undefined || process.argv[5] === undefined) { - console.log('Usage: node createAuction.js org userID auctionID item'); - process.exit(1); - } - - const org = process.argv[2]; - const user = process.argv[3]; - const auctionID = process.argv[4]; - const item = process.argv[5]; - - if (org === 'Org1' || org === 'org1') { - const ccp = buildCCPOrg1(); - const walletPath = path.join(__dirname, 'wallet/org1'); - const wallet = await buildWallet(Wallets, walletPath); - await createAuction(ccp,wallet,user,auctionID,item); - } - else if (org === 'Org2' || org === 'org2') { - const ccp = buildCCPOrg2(); - const walletPath = path.join(__dirname, 'wallet/org2'); - const wallet = await buildWallet(Wallets, walletPath); - await createAuction(ccp,wallet,user,auctionID,item); - } else { - console.log('Usage: node createAuction.js org userID auctionID item'); - console.log('Org must be Org1 or Org2'); - } - } catch (error) { - console.error(`******** FAILED to run the application: ${error}`); - } -} - - -main(); diff --git a/auction-simple/application-javascript/endAuction.js b/auction-simple/application-javascript/endAuction.js deleted file mode 100644 index 27ea5983..00000000 --- a/auction-simple/application-javascript/endAuction.js +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const { Gateway, Wallets } = require('fabric-network'); -const path = require('path'); -const { buildCCPOrg1, buildCCPOrg2, buildWallet, prettyJSONString} = require('../../test-application/javascript/AppUtil.js'); - -const myChannel = 'mychannel'; -const myChaincodeName = 'auction'; - -async function endAuction(ccp,wallet,user,auctionID) { - try { - - const gateway = new Gateway(); - - // Connect using Discovery enabled - await gateway.connect(ccp, - { wallet: wallet, identity: user, discovery: { enabled: true, asLocalhost: true } }); - - const network = await gateway.getNetwork(myChannel); - const contract = network.getContract(myChaincodeName); - - // Query the auction to get the list of endorsing orgs. - let auctionString = await contract.evaluateTransaction('QueryAuction',auctionID); - let auctionJSON = JSON.parse(auctionString); - - let statefulTxn = contract.createTransaction('EndAuction'); - - if (auctionJSON.organizations.length === 2) { - statefulTxn.setEndorsingOrganizations(auctionJSON.organizations[0],auctionJSON.organizations[1]); - } else { - statefulTxn.setEndorsingOrganizations(auctionJSON.organizations[0]); - } - - console.log('\n--> Submit the transaction to end the auction'); - await statefulTxn.submit(auctionID); - console.log('*** Result: committed'); - - console.log('\n--> Evaluate Transaction: query the updated auction'); - let result = await contract.evaluateTransaction('QueryAuction',auctionID); - console.log('*** Result: Auction: ' + prettyJSONString(result.toString())); - - gateway.disconnect(); - } catch (error) { - console.error(`******** FAILED to submit bid: ${error}`); - process.exit(1); - } -} - -async function main() { - try { - - if (process.argv[2] === undefined || process.argv[3] === undefined || - process.argv[4] === undefined) { - console.log('Usage: node endAuction.js org userID auctionID'); - process.exit(1); - } - - const org = process.argv[2]; - const user = process.argv[3]; - const auctionID = process.argv[4]; - - if (org === 'Org1' || org === 'org1') { - const ccp = buildCCPOrg1(); - const walletPath = path.join(__dirname, 'wallet/org1'); - const wallet = await buildWallet(Wallets, walletPath); - await endAuction(ccp,wallet,user,auctionID); - } - else if (org === 'Org2' || org === 'org2') { - const ccp = buildCCPOrg2(); - const walletPath = path.join(__dirname, 'wallet/org2'); - const wallet = await buildWallet(Wallets, walletPath); - await endAuction(ccp,wallet,user,auctionID); - } else { - console.log('Usage: node endAuction.js org userID auctionID'); - console.log('Org must be Org1 or Org2'); - } - } catch (error) { - console.error(`******** FAILED to run the application: ${error}`); - if (error.stack) { - console.error(error.stack); - } - process.exit(1); - } -} - - -main(); diff --git a/auction-simple/application-javascript/enrollAdmin.js b/auction-simple/application-javascript/enrollAdmin.js deleted file mode 100644 index 1c87cad5..00000000 --- a/auction-simple/application-javascript/enrollAdmin.js +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const { Wallets } = require('fabric-network'); -const FabricCAServices = require('fabric-ca-client'); -const path = require('path'); -const { buildCAClient, enrollAdmin } = require('../../test-application/javascript/CAUtil.js'); -const { buildCCPOrg1, buildCCPOrg2, buildWallet } = require('../../test-application/javascript/AppUtil.js'); - -const mspOrg1 = 'Org1MSP'; -const mspOrg2 = 'Org2MSP'; - -async function connectToOrg1CA() { - console.log('\n--> Enrolling the Org1 CA admin'); - const ccpOrg1 = buildCCPOrg1(); - const caOrg1Client = buildCAClient(FabricCAServices, ccpOrg1, 'ca.org1.example.com'); - - const walletPathOrg1 = path.join(__dirname, 'wallet/org1'); - const walletOrg1 = await buildWallet(Wallets, walletPathOrg1); - - await enrollAdmin(caOrg1Client, walletOrg1, mspOrg1); - -} - -async function connectToOrg2CA() { - console.log('\n--> Enrolling the Org2 CA admin'); - const ccpOrg2 = buildCCPOrg2(); - const caOrg2Client = buildCAClient(FabricCAServices, ccpOrg2, 'ca.org2.example.com'); - - const walletPathOrg2 = path.join(__dirname, 'wallet/org2'); - const walletOrg2 = await buildWallet(Wallets, walletPathOrg2); - - await enrollAdmin(caOrg2Client, walletOrg2, mspOrg2); - -} -async function main() { - - if (process.argv[2] === undefined) { - console.log('Usage: node enrollAdmin.js Org'); - process.exit(1); - } - - const org = process.argv[2]; - - try { - - if (org === 'Org1' || org === 'org1') { - await connectToOrg1CA(); - } - else if (org === 'Org2' || org === 'org2') { - await connectToOrg2CA(); - } else { - console.log('Usage: node registerUser.js org userID'); - console.log('Org must be Org1 or Org2'); - } - } catch (error) { - console.error(`Error in enrolling admin: ${error}`); - process.exit(1); - } -} - -main(); diff --git a/auction-simple/application-javascript/package.json b/auction-simple/application-javascript/package.json deleted file mode 100644 index 49bf01e8..00000000 --- a/auction-simple/application-javascript/package.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "auction", - "version": "1.0.0", - "description": "auction application implemented in JavaScript", - "engines": { - "node": ">=12", - "npm": ">=5" - }, - "engineStrict": true, - "author": "Hyperledger", - "license": "Apache-2.0", - "scripts": { - "lint": "eslint *.js" - }, - "dependencies": { - "fabric-ca-client": "^2.2.19", - "fabric-network": "^2.2.19" - }, - "devDependencies": { - "eslint": "^7.32.0" - } -} diff --git a/auction-simple/application-javascript/queryAuction.js b/auction-simple/application-javascript/queryAuction.js deleted file mode 100644 index 046267af..00000000 --- a/auction-simple/application-javascript/queryAuction.js +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const { Gateway, Wallets } = require('fabric-network'); -const path = require('path'); -const { buildCCPOrg1, buildCCPOrg2, buildWallet, prettyJSONString} = require('../../test-application/javascript/AppUtil.js'); - -const myChannel = 'mychannel'; -const myChaincodeName = 'auction'; - -async function queryAuction(ccp,wallet,user,auctionID) { - try { - - const gateway = new Gateway(); - - // Connect using Discovery enabled - await gateway.connect(ccp, - { wallet: wallet, identity: user, discovery: { enabled: true, asLocalhost: true } }); - - const network = await gateway.getNetwork(myChannel); - const contract = network.getContract(myChaincodeName); - - console.log('\n--> Evaluate Transaction: query the auction'); - let result = await contract.evaluateTransaction('QueryAuction',auctionID); - console.log('*** Result: Auction: ' + prettyJSONString(result.toString())); - - gateway.disconnect(); - } catch (error) { - console.error(`******** FAILED to submit bid: ${error}`); - } -} - -async function main() { - try { - - if (process.argv[2] === undefined || process.argv[3] === undefined || - process.argv[4] === undefined) { - console.log('Usage: node queryAuction.js org userID auctionID'); - process.exit(1); - } - - const org = process.argv[2]; - const user = process.argv[3]; - const auctionID = process.argv[4]; - - if (org === 'Org1' || org === 'org1') { - const ccp = buildCCPOrg1(); - const walletPath = path.join(__dirname, 'wallet/org1'); - const wallet = await buildWallet(Wallets, walletPath); - await queryAuction(ccp,wallet,user,auctionID); - } - else if (org === 'Org2' || org === 'org2') { - const ccp = buildCCPOrg2(); - const walletPath = path.join(__dirname, 'wallet/org2'); - const wallet = await buildWallet(Wallets, walletPath); - await queryAuction(ccp,wallet,user,auctionID); - } else { - console.log('Usage: node queryAuction.js org userID auctionID'); - console.log('Org must be Org1 or Org2'); - } - } catch (error) { - console.error(`******** FAILED to run the application: ${error}`); - } -} - - -main(); diff --git a/auction-simple/application-javascript/queryBid.js b/auction-simple/application-javascript/queryBid.js deleted file mode 100644 index 57ce37ba..00000000 --- a/auction-simple/application-javascript/queryBid.js +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const { Gateway, Wallets } = require('fabric-network'); -const path = require('path'); -const { buildCCPOrg1, buildCCPOrg2, buildWallet, prettyJSONString} = require('../../test-application/javascript/AppUtil.js'); - -const myChannel = 'mychannel'; -const myChaincodeName = 'auction'; - -async function queryBid(ccp,wallet,user,auctionID,bidID) { - try { - - const gateway = new Gateway(); - - // Connect using Discovery enabled - await gateway.connect(ccp, - { wallet: wallet, identity: user, discovery: { enabled: true, asLocalhost: true } }); - - const network = await gateway.getNetwork(myChannel); - const contract = network.getContract(myChaincodeName); - - console.log('\n--> Evaluate Transaction: read bid from private data store'); - let result = await contract.evaluateTransaction('QueryBid',auctionID,bidID); - console.log('*** Result: Bid: ' + prettyJSONString(result.toString())); - - gateway.disconnect(); - } catch (error) { - console.error(`******** FAILED to submit bid: ${error}`); - } -} - -async function main() { - try { - - if (process.argv[2] === undefined || process.argv[3] === undefined || - process.argv[4] === undefined || process.argv[5] === undefined) { - console.log('Usage: node bid.js org userID auctionID bidID'); - process.exit(1); - } - - const org = process.argv[2]; - const user = process.argv[3]; - const auctionID = process.argv[4]; - const bidID = process.argv[5]; - - if (org === 'Org1' || org === 'org1') { - const ccp = buildCCPOrg1(); - const walletPath = path.join(__dirname, 'wallet/org1'); - const wallet = await buildWallet(Wallets, walletPath); - await queryBid(ccp,wallet,user,auctionID,bidID); - } - else if (org === 'Org2' || org === 'org2') { - const ccp = buildCCPOrg2(); - const walletPath = path.join(__dirname, 'wallet/org2'); - const wallet = await buildWallet(Wallets, walletPath); - await queryBid(ccp,wallet,user,auctionID,bidID); - } else { - console.log('Usage: node bid.js org userID auctionID bidID'); - console.log('Org must be Org1 or Org2'); - } - } catch (error) { - console.error(`******** FAILED to run the application: ${error}`); - } -} - - -main(); diff --git a/auction-simple/application-javascript/registerEnrollUser.js b/auction-simple/application-javascript/registerEnrollUser.js deleted file mode 100644 index d6cb9a66..00000000 --- a/auction-simple/application-javascript/registerEnrollUser.js +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const { Wallets } = require('fabric-network'); -const FabricCAServices = require('fabric-ca-client'); -const path = require('path'); -const { buildCAClient, registerAndEnrollUser } = require('../../test-application/javascript/CAUtil.js'); -const { buildCCPOrg1, buildCCPOrg2, buildWallet } = require('../../test-application/javascript/AppUtil.js'); - -const mspOrg1 = 'Org1MSP'; -const mspOrg2 = 'Org2MSP'; - -async function connectToOrg1CA(UserID) { - console.log('\n--> Register and enrolling new user'); - const ccpOrg1 = buildCCPOrg1(); - const caOrg1Client = buildCAClient(FabricCAServices, ccpOrg1, 'ca.org1.example.com'); - - const walletPathOrg1 = path.join(__dirname, 'wallet/org1'); - const walletOrg1 = await buildWallet(Wallets, walletPathOrg1); - - await registerAndEnrollUser(caOrg1Client, walletOrg1, mspOrg1, UserID, 'org1.department1'); - -} - -async function connectToOrg2CA(UserID) { - console.log('\n--> Register and enrolling new user'); - const ccpOrg2 = buildCCPOrg2(); - const caOrg2Client = buildCAClient(FabricCAServices, ccpOrg2, 'ca.org2.example.com'); - - const walletPathOrg2 = path.join(__dirname, 'wallet/org2'); - const walletOrg2 = await buildWallet(Wallets, walletPathOrg2); - - await registerAndEnrollUser(caOrg2Client, walletOrg2, mspOrg2, UserID, 'org2.department1'); - -} -async function main() { - - if (process.argv[2] === undefined && process.argv[3] === undefined) { - console.log('Usage: node registerEnrollUser.js org userID'); - process.exit(1); - } - - const org = process.argv[2]; - const userId = process.argv[3]; - - try { - - if (org === 'Org1' || org === 'org1') { - await connectToOrg1CA(userId); - } - else if (org === 'Org2' || org === 'org2') { - await connectToOrg2CA(userId); - } else { - console.log('Usage: node registerEnrollUser.js org userID'); - console.log('Org must be Org1 or Org2'); - } - } catch (error) { - console.error(`Error in enrolling admin: ${error}`); - process.exit(1); - } -} - -main(); diff --git a/auction-simple/application-javascript/revealBid.js b/auction-simple/application-javascript/revealBid.js deleted file mode 100644 index bb0b1a7f..00000000 --- a/auction-simple/application-javascript/revealBid.js +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const { Gateway, Wallets } = require('fabric-network'); -const path = require('path'); -const { buildCCPOrg1, buildCCPOrg2, buildWallet, prettyJSONString} = require('../../test-application/javascript/AppUtil.js'); - -const myChannel = 'mychannel'; -const myChaincodeName = 'auction'; - -async function addBid(ccp,wallet,user,auctionID,bidID) { - try { - - const gateway = new Gateway(); - await gateway.connect(ccp, - { wallet: wallet, identity: user, discovery: { enabled: true, asLocalhost: true } }); - - const network = await gateway.getNetwork(myChannel); - const contract = network.getContract(myChaincodeName); - - console.log('\n--> Evaluate Transaction: read your bid'); - let bidString = await contract.evaluateTransaction('QueryBid',auctionID,bidID); - let bidJSON = JSON.parse(bidString); - - // console.log('\n--> Evaluate Transaction: query the auction you want to join'); - let auctionString = await contract.evaluateTransaction('QueryAuction',auctionID); - // console.log('*** Result: Bid: ' + prettyJSONString(auctionString.toString())); - let auctionJSON = JSON.parse(auctionString); - - let bidData = { objectType: 'bid', price: parseInt(bidJSON.price), org: bidJSON.org, bidder: bidJSON.bidder}; - console.log('*** Result: Bid: ' + JSON.stringify(bidData,null,2)); - - let statefulTxn = contract.createTransaction('RevealBid'); - let tmapData = Buffer.from(JSON.stringify(bidData)); - statefulTxn.setTransient({ - bid: tmapData - }); - - if (auctionJSON.organizations.length === 2) { - statefulTxn.setEndorsingOrganizations(auctionJSON.organizations[0],auctionJSON.organizations[1]); - } else { - statefulTxn.setEndorsingOrganizations(auctionJSON.organizations[0]); - } - - await statefulTxn.submit(auctionID,bidID); - - console.log('\n--> Evaluate Transaction: query the auction to see that our bid was added'); - let result = await contract.evaluateTransaction('QueryAuction',auctionID); - console.log('*** Result: Auction: ' + prettyJSONString(result.toString())); - - gateway.disconnect(); - } catch (error) { - console.error(`******** FAILED to submit bid: ${error}`); - process.exit(1); - } -} - -async function main() { - try { - - if (process.argv[2] === undefined || process.argv[3] === undefined || - process.argv[4] === undefined || process.argv[5] === undefined) { - console.log('Usage: node revealBid.js org userID auctionID bidID'); - process.exit(1); - } - - const org = process.argv[2]; - const user = process.argv[3]; - const auctionID = process.argv[4]; - const bidID = process.argv[5]; - - if (org === 'Org1' || org === 'org1') { - const ccp = buildCCPOrg1(); - const walletPath = path.join(__dirname, 'wallet/org1'); - const wallet = await buildWallet(Wallets, walletPath); - await addBid(ccp,wallet,user,auctionID,bidID); - } - else if (org === 'Org2' || org === 'org2') { - const ccp = buildCCPOrg2(); - const walletPath = path.join(__dirname, 'wallet/org2'); - const wallet = await buildWallet(Wallets, walletPath); - await addBid(ccp,wallet,user,auctionID,bidID); - } - else { - console.log('Usage: node revealBid.js org userID auctionID bidID'); - console.log('Org must be Org1 or Org2'); - } - } catch (error) { - console.error(`******** FAILED to run the application: ${error}`); - if (error.stack) { - console.error(error.stack); - } - process.exit(1); - } -} - - -main(); diff --git a/auction-simple/application-javascript/submitBid.js b/auction-simple/application-javascript/submitBid.js deleted file mode 100644 index 6c2e0669..00000000 --- a/auction-simple/application-javascript/submitBid.js +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict'; - -const { Gateway, Wallets } = require('fabric-network'); -const path = require('path'); -const { buildCCPOrg1, buildCCPOrg2, buildWallet } = require('../../test-application/javascript/AppUtil.js'); - -const myChannel = 'mychannel'; -const myChaincodeName = 'auction'; - - -function prettyJSONString(inputString) { - if (inputString) { - return JSON.stringify(JSON.parse(inputString), null, 2); - } - else { - return inputString; - } -} - -async function submitBid(ccp,wallet,user,auctionID,bidID) { - try { - - const gateway = new Gateway(); - - // Connect using Discovery enabled - await gateway.connect(ccp, - { wallet: wallet, identity: user, discovery: { enabled: true, asLocalhost: true } }); - - const network = await gateway.getNetwork(myChannel); - const contract = network.getContract(myChaincodeName); - - console.log('\n--> Evaluate Transaction: query the auction you want to join'); - let auctionString = await contract.evaluateTransaction('QueryAuction',auctionID); - let auctionJSON = JSON.parse(auctionString); - - let statefulTxn = contract.createTransaction('SubmitBid'); - - if (auctionJSON.organizations.length === 2) { - statefulTxn.setEndorsingOrganizations(auctionJSON.organizations[0],auctionJSON.organizations[1]); - } else { - statefulTxn.setEndorsingOrganizations(auctionJSON.organizations[0]); - } - - console.log('\n--> Submit Transaction: add bid to the auction'); - await statefulTxn.submit(auctionID,bidID); - - console.log('\n--> Evaluate Transaction: query the auction to see that our bid was added'); - let result = await contract.evaluateTransaction('QueryAuction',auctionID); - console.log('*** Result: Auction: ' + prettyJSONString(result.toString())); - - gateway.disconnect(); - } catch (error) { - console.error(`******** FAILED to submit bid: ${error}`); - process.exit(1); - } -} - -async function main() { - try { - - if (process.argv[2] === undefined || process.argv[3] === undefined || - process.argv[4] === undefined || process.argv[5] === undefined) { - console.log('Usage: node submitBid.js org userID auctionID bidID'); - process.exit(1); - } - - const org = process.argv[2]; - const user = process.argv[3]; - const auctionID = process.argv[4]; - const bidID = process.argv[5]; - - if (org === 'Org1' || org === 'org1') { - const ccp = buildCCPOrg1(); - const walletPath = path.join(__dirname, 'wallet/org1'); - const wallet = await buildWallet(Wallets, walletPath); - await submitBid(ccp,wallet,user,auctionID,bidID); - } - else if (org === 'Org2' || org === 'org2') { - const ccp = buildCCPOrg2(); - const walletPath = path.join(__dirname, 'wallet/org2'); - const wallet = await buildWallet(Wallets, walletPath); - await submitBid(ccp,wallet,user,auctionID,bidID); - } - else { - console.log('Usage: node submitBid.js org userID auctionID bidID'); - console.log('Org must be Org1 or Org2'); - } - } catch (error) { - console.error(`******** FAILED to run the application: ${error}`); - if (error.stack) { - console.error(error.stack); - } - process.exit(1); - } -} - - -main(); diff --git a/auction-simple/chaincode-go/go.mod b/auction-simple/chaincode-go/go.mod deleted file mode 100644 index 8cd1510c..00000000 --- a/auction-simple/chaincode-go/go.mod +++ /dev/null @@ -1,34 +0,0 @@ -module github.com/hyperledger/fabric-samples/auction/chaincode-go - -go 1.21 - -require ( - github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0-20240618210511-f7903324a8af - github.com/hyperledger/fabric-contract-api-go/v2 v2.0.0 -) - -require ( - github.com/go-openapi/jsonpointer v0.21.0 // indirect - github.com/go-openapi/jsonreference v0.21.0 // indirect - github.com/go-openapi/spec v0.21.0 // indirect - github.com/go-openapi/swag v0.23.0 // indirect - github.com/gobuffalo/envy v1.10.2 // indirect - github.com/gobuffalo/packd v1.0.2 // indirect - github.com/gobuffalo/packr v1.30.1 // indirect - github.com/hyperledger/fabric-protos-go-apiv2 v0.3.3 // indirect - github.com/joho/godotenv v1.5.1 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/mailru/easyjson v0.7.7 // indirect - github.com/rogpeppe/go-internal v1.12.0 // indirect - github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect - github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect - github.com/xeipuuv/gojsonschema v1.2.0 // indirect - golang.org/x/mod v0.17.0 // indirect - golang.org/x/net v0.24.0 // indirect - golang.org/x/sys v0.19.0 // indirect - golang.org/x/text v0.14.0 // indirect - google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect - google.golang.org/grpc v1.64.0 // indirect - google.golang.org/protobuf v1.34.2 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) diff --git a/auction-simple/chaincode-go/go.sum b/auction-simple/chaincode-go/go.sum deleted file mode 100644 index 7c5e414c..00000000 --- a/auction-simple/chaincode-go/go.sum +++ /dev/null @@ -1,132 +0,0 @@ -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= -github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= -github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= -github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= -github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= -github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= -github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= -github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= -github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= -github.com/gobuffalo/envy v1.10.2 h1:EIi03p9c3yeuRCFPOKcSfajzkLb3hrRjEpHGI8I2Wo4= -github.com/gobuffalo/envy v1.10.2/go.mod h1:qGAGwdvDsaEtPhfBzb3o0SfDea8ByGn9j8bKmVft9z8= -github.com/gobuffalo/logger v1.0.0/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs= -github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q= -github.com/gobuffalo/packd v1.0.2 h1:Yg523YqnOxGIWCp69W12yYBKsoChwI7mtu6ceM9Bwfw= -github.com/gobuffalo/packd v1.0.2/go.mod h1:sUc61tDqGMXON80zpKGp92lDb86Km28jfvX7IAyxFT8= -github.com/gobuffalo/packr v1.30.1 h1:hu1fuVR3fXEZR7rXNW3h8rqSML8EVAf6KNm0NKO/wKg= -github.com/gobuffalo/packr v1.30.1/go.mod h1:ljMyFO2EcrnzsHsN99cvbq055Y9OhRrIaviy289eRuk= -github.com/gobuffalo/packr/v2 v2.5.1/go.mod h1:8f9c96ITobJlPzI44jj+4tHnEKNt0xXWSVlXRN9X1Iw= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0-20240618210511-f7903324a8af h1:WT4NjX7Uk03GSeH++jF3a0wp4FhybTM86zDPCETvmSk= -github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0-20240618210511-f7903324a8af/go.mod h1:f/ER25FaBepxJugwpLhbD2hLAoZaZEVqkBjOcHjw72Y= -github.com/hyperledger/fabric-contract-api-go/v2 v2.0.0 h1:IDiCGVOBlRd6zpL0Y+f6V7IpBqa4/Z5JAK9SF7a5ea8= -github.com/hyperledger/fabric-contract-api-go/v2 v2.0.0/go.mod h1:pdqhe7ALf4lmXgQdprCyNWYdnCPxgj02Vhf8JF5w8po= -github.com/hyperledger/fabric-protos-go-apiv2 v0.3.3 h1:Xpd6fzG/KjAOHJsq7EQXY2l+qi/y8muxBaY7R6QWABk= -github.com/hyperledger/fabric-protos-go-apiv2 v0.3.3/go.mod h1:2pq0ui6ZWA0cC8J+eCErgnMDCS1kPOEYVY+06ZAK0qE= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= -github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= -github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= -github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= -golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= -google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/auction-simple/chaincode-go/smart-contract/auction.go b/auction-simple/chaincode-go/smart-contract/auction.go deleted file mode 100644 index f0f5e14d..00000000 --- a/auction-simple/chaincode-go/smart-contract/auction.go +++ /dev/null @@ -1,448 +0,0 @@ -/* -SPDX-License-Identifier: Apache-2.0 -*/ - -package auction - -import ( - "bytes" - "crypto/sha256" - "encoding/json" - "errors" - "fmt" - - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" -) - -type SmartContract struct { - contractapi.Contract -} - -// Auction data -type Auction struct { - Type string `json:"objectType"` - ItemSold string `json:"item"` - Seller string `json:"seller"` - Orgs []string `json:"organizations"` - PrivateBids map[string]BidHash `json:"privateBids"` - RevealedBids map[string]FullBid `json:"revealedBids"` - Winner string `json:"winner"` - Price int `json:"price"` - Status string `json:"status"` -} - -// FullBid is the structure of a revealed bid -type FullBid struct { - Type string `json:"objectType"` - Price int `json:"price"` - Org string `json:"org"` - Bidder string `json:"bidder"` -} - -// BidHash is the structure of a private bid -type BidHash struct { - Org string `json:"org"` - Hash string `json:"hash"` -} - -const bidKeyType = "bid" - -// CreateAuction creates on auction on the public channel. The identity that -// submits the transacion becomes the seller of the auction -func (s *SmartContract) CreateAuction(ctx contractapi.TransactionContextInterface, auctionID string, itemsold string) error { - - // get ID of submitting client - clientID, err := s.GetSubmittingClientIdentity(ctx) - if err != nil { - return fmt.Errorf("failed to get client identity %v", err) - } - - // get org of submitting client - clientOrgID, err := ctx.GetClientIdentity().GetMSPID() - if err != nil { - return fmt.Errorf("failed to get client identity %v", err) - } - - // Create auction - bidders := make(map[string]BidHash) - revealedBids := make(map[string]FullBid) - - auction := Auction{ - Type: "auction", - ItemSold: itemsold, - Price: 0, - Seller: clientID, - Orgs: []string{clientOrgID}, - PrivateBids: bidders, - RevealedBids: revealedBids, - Winner: "", - Status: "open", - } - - auctionJSON, err := json.Marshal(auction) - if err != nil { - return err - } - - // put auction into state - err = ctx.GetStub().PutState(auctionID, auctionJSON) - if err != nil { - return fmt.Errorf("failed to put auction in public data: %v", err) - } - - // set the seller of the auction as an endorser - err = setAssetStateBasedEndorsement(ctx, auctionID, clientOrgID) - if err != nil { - return fmt.Errorf("failed setting state based endorsement for new organization: %v", err) - } - - return nil -} - -// Bid is used to add a user's bid to the auction. The bid is stored in the private -// data collection on the peer of the bidder's organization. The function returns -// the transaction ID so that users can identify and query their bid -func (s *SmartContract) Bid(ctx contractapi.TransactionContextInterface, auctionID string) (string, error) { - - // get bid from transient map - transientMap, err := ctx.GetStub().GetTransient() - if err != nil { - return "", fmt.Errorf("error getting transient: %v", err) - } - - BidJSON, ok := transientMap["bid"] - if !ok { - return "", errors.New("bid key not found in the transient map") - } - - // get the implicit collection name using the bidder's organization ID - collection, err := getCollectionName(ctx) - if err != nil { - return "", fmt.Errorf("failed to get implicit collection name: %v", err) - } - - // the bidder has to target their peer to store the bid - err = verifyClientOrgMatchesPeerOrg(ctx) - if err != nil { - return "", fmt.Errorf("cannot store bid on this peer, not a member of this org: Error %v", err) - } - - // the transaction ID is used as a unique index for the bid - txID := ctx.GetStub().GetTxID() - - // create a composite key using the transaction ID - bidKey, err := ctx.GetStub().CreateCompositeKey(bidKeyType, []string{auctionID, txID}) - if err != nil { - return "", fmt.Errorf("failed to create composite key: %v", err) - } - - // put the bid into the organization's implicit data collection - err = ctx.GetStub().PutPrivateData(collection, bidKey, BidJSON) - if err != nil { - return "", fmt.Errorf("failed to input price into collection: %v", err) - } - - // return the trannsaction ID so that the uset can identify their bid - return txID, nil -} - -// SubmitBid is used by the bidder to add the hash of that bid stored in private data to the -// auction. Note that this function alters the auction in private state, and needs -// to meet the auction endorsement policy. Transaction ID is used identify the bid -func (s *SmartContract) SubmitBid(ctx contractapi.TransactionContextInterface, auctionID string, txID string) error { - - // get the MSP ID of the bidder's org - clientOrgID, err := ctx.GetClientIdentity().GetMSPID() - if err != nil { - return fmt.Errorf("failed to get client MSP ID: %v", err) - } - - // get the auction from public state - auction, err := s.QueryAuction(ctx, auctionID) - if err != nil { - return fmt.Errorf("failed to get auction from public state %v", err) - } - - // the auction needs to be open for users to add their bid - Status := auction.Status - if Status != "open" { - return errors.New("cannot join closed or ended auction") - } - - // get the inplicit collection name of bidder's org - collection, err := getCollectionName(ctx) - if err != nil { - return fmt.Errorf("failed to get implicit collection name: %v", err) - } - - // use the transaction ID passed as a parameter to create composite bid key - bidKey, err := ctx.GetStub().CreateCompositeKey(bidKeyType, []string{auctionID, txID}) - if err != nil { - return fmt.Errorf("failed to create composite key: %v", err) - } - - // get the hash of the bid stored in private data collection - bidHash, err := ctx.GetStub().GetPrivateDataHash(collection, bidKey) - if err != nil { - return fmt.Errorf("failed to read bid bash from collection: %v", err) - } - if bidHash == nil { - return fmt.Errorf("bid hash does not exist: %s", bidKey) - } - - // store the hash along with the bidder's organization - NewHash := BidHash{ - Org: clientOrgID, - Hash: fmt.Sprintf("%x", bidHash), - } - - auction.PrivateBids[bidKey] = NewHash - - // Add the bidding organization to the list of participating organizations if it is not already - Orgs := auction.Orgs - if !(contains(Orgs, clientOrgID)) { - newOrgs := append(Orgs, clientOrgID) - auction.Orgs = newOrgs - - err = addAssetStateBasedEndorsement(ctx, auctionID, clientOrgID) - if err != nil { - return fmt.Errorf("failed setting state based endorsement for new organization: %v", err) - } - } - - newAuctionJSON, _ := json.Marshal(auction) - - err = ctx.GetStub().PutState(auctionID, newAuctionJSON) - if err != nil { - return fmt.Errorf("failed to update auction: %v", err) - } - - return nil -} - -// RevealBid is used by a bidder to reveal their bid after the auction is closed -func (s *SmartContract) RevealBid(ctx contractapi.TransactionContextInterface, auctionID string, txID string) error { - - // get bid from transient map - transientMap, err := ctx.GetStub().GetTransient() - if err != nil { - return fmt.Errorf("error getting transient: %v", err) - } - - transientBidJSON, ok := transientMap["bid"] - if !ok { - return errors.New("bid key not found in the transient map") - } - - // get implicit collection name of organization ID - collection, err := getCollectionName(ctx) - if err != nil { - return fmt.Errorf("failed to get implicit collection name: %v", err) - } - - // use transaction ID to create composit bid key - bidKey, err := ctx.GetStub().CreateCompositeKey(bidKeyType, []string{auctionID, txID}) - if err != nil { - return fmt.Errorf("failed to create composite key: %v", err) - } - - // get bid hash of bid if private bid on the public ledger - bidHash, err := ctx.GetStub().GetPrivateDataHash(collection, bidKey) - if err != nil { - return fmt.Errorf("failed to read bid bash from collection: %v", err) - } - if bidHash == nil { - return fmt.Errorf("bid hash does not exist: %s", bidKey) - } - - // get auction from public state - auction, err := s.QueryAuction(ctx, auctionID) - if err != nil { - return fmt.Errorf("failed to get auction from public state %v", err) - } - - // Complete a series of three checks before we add the bid to the auction - - // check 1: check that the auction is closed. We cannot reveal a - // bid to an open auction - Status := auction.Status - if Status != "closed" { - return errors.New("cannot reveal bid for open or ended auction") - } - - // check 2: check that hash of revealed bid matches hash of private bid - // on the public ledger. This checks that the bidder is telling the truth - // about the value of their bid - - hash := sha256.New() - hash.Write(transientBidJSON) - calculatedBidJSONHash := hash.Sum(nil) - - // verify that the hash of the passed immutable properties matches the on-chain hash - if !bytes.Equal(calculatedBidJSONHash, bidHash) { - return fmt.Errorf("hash %x for bid JSON %s does not match hash in auction: %x", - calculatedBidJSONHash, - transientBidJSON, - bidHash, - ) - } - - // check 3; check hash of relealed bid matches hash of private bid that was - // added earlier. This ensures that the bid has not changed since it - // was added to the auction - - privateBidHashString := auction.PrivateBids[bidKey].Hash - - onChainBidHashString := fmt.Sprintf("%x", bidHash) - if privateBidHashString != onChainBidHashString { - return fmt.Errorf("hash %s for bid JSON %s does not match hash in auction: %s, bidder must have changed bid", - privateBidHashString, - transientBidJSON, - onChainBidHashString, - ) - } - - // we can add the bid to the auction if all checks have passed - type transientBidInput struct { - Price int `json:"price"` - Org string `json:"org"` - Bidder string `json:"bidder"` - } - - // unmarshal bid input - var bidInput transientBidInput - err = json.Unmarshal(transientBidJSON, &bidInput) - if err != nil { - return fmt.Errorf("failed to unmarshal JSON: %v", err) - } - - // Get ID of submitting client identity - clientID, err := s.GetSubmittingClientIdentity(ctx) - if err != nil { - return fmt.Errorf("failed to get client identity %v", err) - } - - // marshal transient parameters and ID and MSPID into bid object - NewBid := FullBid{ - Type: bidKeyType, - Price: bidInput.Price, - Org: bidInput.Org, - Bidder: bidInput.Bidder, - } - - // check 4: make sure that the transaction is being submitted is the bidder - if bidInput.Bidder != clientID { - return fmt.Errorf("permission denied, client id %v is not the owner of the bid", clientID) - } - - auction.RevealedBids[bidKey] = NewBid - - newAuctionJSON, _ := json.Marshal(auction) - - // put auction with bid added back into state - err = ctx.GetStub().PutState(auctionID, newAuctionJSON) - if err != nil { - return fmt.Errorf("failed to update auction: %v", err) - } - - return nil -} - -// CloseAuction can be used by the seller to close the auction. This prevents -// bids from being added to the auction, and allows users to reveal their bid -func (s *SmartContract) CloseAuction(ctx contractapi.TransactionContextInterface, auctionID string) error { - - // get auction from public state - auction, err := s.QueryAuction(ctx, auctionID) - if err != nil { - return fmt.Errorf("failed to get auction from public state %v", err) - } - - // the auction can only be closed by the seller - - // get ID of submitting client - clientID, err := s.GetSubmittingClientIdentity(ctx) - if err != nil { - return fmt.Errorf("failed to get client identity %v", err) - } - - Seller := auction.Seller - if Seller != clientID { - return fmt.Errorf("auction can only be closed by seller: %v", err) - } - - Status := auction.Status - if Status != "open" { - return errors.New("cannot close auction that is not open") - } - - auction.Status = string("closed") - - closedAuctionJSON, _ := json.Marshal(auction) - - err = ctx.GetStub().PutState(auctionID, closedAuctionJSON) - if err != nil { - return fmt.Errorf("failed to close auction: %v", err) - } - - return nil -} - -// EndAuction both changes the auction status to closed and calculates the winners -// of the auction -func (s *SmartContract) EndAuction(ctx contractapi.TransactionContextInterface, auctionID string) error { - - // get auction from public state - auction, err := s.QueryAuction(ctx, auctionID) - if err != nil { - return fmt.Errorf("failed to get auction from public state %v", err) - } - - // Check that the auction is being ended by the seller - - // get ID of submitting client - clientID, err := s.GetSubmittingClientIdentity(ctx) - if err != nil { - return fmt.Errorf("failed to get client identity %v", err) - } - - Seller := auction.Seller - if Seller != clientID { - return fmt.Errorf("auction can only be ended by seller: %v", err) - } - - Status := auction.Status - if Status != "closed" { - return errors.New("can only end a closed auction") - } - - // get the list of revealed bids - revealedBidMap := auction.RevealedBids - if len(auction.RevealedBids) == 0 { - return fmt.Errorf("no bids have been revealed, cannot end auction: %v", err) - } - - // determine the highest bid - for _, bid := range revealedBidMap { - if bid.Price > auction.Price { - auction.Winner = bid.Bidder - auction.Price = bid.Price - } - } - - // check if there is a winning bid that has yet to be revealed - err = checkForHigherBid(ctx, auction.Price, auction.RevealedBids, auction.PrivateBids) - if err != nil { - return fmt.Errorf("cannot end auction: %v", err) - } - - auction.Status = "ended" - - endedAuctionJSON, _ := json.Marshal(auction) - - err = ctx.GetStub().PutState(auctionID, endedAuctionJSON) - if err != nil { - return fmt.Errorf("failed to end auction: %v", err) - } - return nil -} diff --git a/auction-simple/chaincode-go/smart-contract/auctionQueries.go b/auction-simple/chaincode-go/smart-contract/auctionQueries.go deleted file mode 100644 index cd99558b..00000000 --- a/auction-simple/chaincode-go/smart-contract/auctionQueries.go +++ /dev/null @@ -1,137 +0,0 @@ -/* -SPDX-License-Identifier: Apache-2.0 -*/ - -package auction - -import ( - "encoding/json" - "errors" - "fmt" - - "github.com/hyperledger/fabric-chaincode-go/v2/shim" - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" -) - -// QueryAuction allows all members of the channel to read a public auction -func (s *SmartContract) QueryAuction(ctx contractapi.TransactionContextInterface, auctionID string) (*Auction, error) { - - auctionJSON, err := ctx.GetStub().GetState(auctionID) - if err != nil { - return nil, fmt.Errorf("failed to get auction object %v: %v", auctionID, err) - } - if auctionJSON == nil { - return nil, errors.New("auction does not exist") - } - - var auction *Auction - err = json.Unmarshal(auctionJSON, &auction) - if err != nil { - return nil, err - } - - return auction, nil -} - -// QueryBid allows the submitter of the bid to read their bid from public state -func (s *SmartContract) QueryBid(ctx contractapi.TransactionContextInterface, auctionID string, txID string) (*FullBid, error) { - - err := verifyClientOrgMatchesPeerOrg(ctx) - if err != nil { - return nil, fmt.Errorf("failed to get implicit collection name: %v", err) - } - - clientID, err := s.GetSubmittingClientIdentity(ctx) - if err != nil { - return nil, fmt.Errorf("failed to get client identity %v", err) - } - - collection, err := getCollectionName(ctx) - if err != nil { - return nil, fmt.Errorf("failed to get implicit collection name: %v", err) - } - - bidKey, err := ctx.GetStub().CreateCompositeKey(bidKeyType, []string{auctionID, txID}) - if err != nil { - return nil, fmt.Errorf("failed to create composite key: %v", err) - } - - bidJSON, err := ctx.GetStub().GetPrivateData(collection, bidKey) - if err != nil { - return nil, fmt.Errorf("failed to get bid %v: %v", bidKey, err) - } - if bidJSON == nil { - return nil, fmt.Errorf("bid %v does not exist", bidKey) - } - - var bid *FullBid - err = json.Unmarshal(bidJSON, &bid) - if err != nil { - return nil, err - } - - // check that the client querying the bid is the bid owner - if bid.Bidder != clientID { - return nil, fmt.Errorf("permission denied, client id %v is not the owner of the bid", clientID) - } - - return bid, nil -} - -// checkForHigherBid is an internal function that is used to determine if a winning bid has yet to be revealed -func checkForHigherBid(ctx contractapi.TransactionContextInterface, auctionPrice int, revealedBidders map[string]FullBid, bidders map[string]BidHash) error { - - // Get MSP ID of peer org - peerMSPID, err := shim.GetMSPID() - if err != nil { - return fmt.Errorf("failed getting the peer's MSPID: %v", err) - } - - var error error - error = nil - - for bidKey, privateBid := range bidders { - - if _, bidInAuction := revealedBidders[bidKey]; bidInAuction { - - // bid is already revealed, no action to take - - } else { - - collection := "_implicit_org_" + privateBid.Org - - if privateBid.Org == peerMSPID { - - bidJSON, err := ctx.GetStub().GetPrivateData(collection, bidKey) - if err != nil { - return fmt.Errorf("failed to get bid %v: %v", bidKey, err) - } - if bidJSON == nil { - return fmt.Errorf("bid %v does not exist", bidKey) - } - - var bid *FullBid - err = json.Unmarshal(bidJSON, &bid) - if err != nil { - return err - } - - if bid.Price > auctionPrice { - error = fmt.Errorf("cannot close auction, bidder has a higher price: %v", err) - } - - } else { - - Hash, err := ctx.GetStub().GetPrivateDataHash(collection, bidKey) - if err != nil { - return fmt.Errorf("failed to read bid hash from collection: %v", err) - } - if Hash == nil { - return fmt.Errorf("bid hash does not exist: %s", bidKey) - } - } - } - } - - return error -} diff --git a/auction-simple/chaincode-go/smart-contract/utils.go b/auction-simple/chaincode-go/smart-contract/utils.go deleted file mode 100644 index b663e608..00000000 --- a/auction-simple/chaincode-go/smart-contract/utils.go +++ /dev/null @@ -1,121 +0,0 @@ -/* -SPDX-License-Identifier: Apache-2.0 -*/ - -package auction - -import ( - "encoding/base64" - "fmt" - - "github.com/hyperledger/fabric-chaincode-go/v2/pkg/statebased" - "github.com/hyperledger/fabric-chaincode-go/v2/shim" - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" -) - -func (s *SmartContract) GetSubmittingClientIdentity(ctx contractapi.TransactionContextInterface) (string, error) { - - b64ID, err := ctx.GetClientIdentity().GetID() - if err != nil { - return "", fmt.Errorf("failed to read clientID: %v", err) - } - decodeID, err := base64.StdEncoding.DecodeString(b64ID) - if err != nil { - return "", fmt.Errorf("failed to base64 decode clientID: %v", err) - } - return string(decodeID), nil -} - -// setAssetStateBasedEndorsement sets the endorsement policy of a new auction -func setAssetStateBasedEndorsement(ctx contractapi.TransactionContextInterface, auctionID string, orgToEndorse string) error { - - endorsementPolicy, err := statebased.NewStateEP(nil) - if err != nil { - return err - } - err = endorsementPolicy.AddOrgs(statebased.RoleTypePeer, orgToEndorse) - if err != nil { - return fmt.Errorf("failed to add org to endorsement policy: %v", err) - } - policy, err := endorsementPolicy.Policy() - if err != nil { - return fmt.Errorf("failed to create endorsement policy bytes from org: %v", err) - } - err = ctx.GetStub().SetStateValidationParameter(auctionID, policy) - if err != nil { - return fmt.Errorf("failed to set validation parameter on auction: %v", err) - } - - return nil -} - -// addAssetStateBasedEndorsement adds a new organization as an endorser of the auction -func addAssetStateBasedEndorsement(ctx contractapi.TransactionContextInterface, auctionID string, orgToEndorse string) error { - - endorsementPolicy, err := ctx.GetStub().GetStateValidationParameter(auctionID) - if err != nil { - return err - } - - newEndorsementPolicy, err := statebased.NewStateEP(endorsementPolicy) - if err != nil { - return err - } - - err = newEndorsementPolicy.AddOrgs(statebased.RoleTypePeer, orgToEndorse) - if err != nil { - return fmt.Errorf("failed to add org to endorsement policy: %v", err) - } - policy, err := newEndorsementPolicy.Policy() - if err != nil { - return fmt.Errorf("failed to create endorsement policy bytes from org: %v", err) - } - err = ctx.GetStub().SetStateValidationParameter(auctionID, policy) - if err != nil { - return fmt.Errorf("failed to set validation parameter on auction: %v", err) - } - - return nil -} - -// getCollectionName is an internal helper function to get collection of submitting client identity. -func getCollectionName(ctx contractapi.TransactionContextInterface) (string, error) { - - // Get the MSP ID of submitting client identity - clientMSPID, err := ctx.GetClientIdentity().GetMSPID() - if err != nil { - return "", fmt.Errorf("failed to get verified MSPID: %v", err) - } - - // Create the collection name - orgCollection := "_implicit_org_" + clientMSPID - - return orgCollection, nil -} - -// verifyClientOrgMatchesPeerOrg is an internal function used to verify that client org id matches peer org id. -func verifyClientOrgMatchesPeerOrg(ctx contractapi.TransactionContextInterface) error { - clientMSPID, err := ctx.GetClientIdentity().GetMSPID() - if err != nil { - return fmt.Errorf("failed getting the client's MSPID: %v", err) - } - peerMSPID, err := shim.GetMSPID() - if err != nil { - return fmt.Errorf("failed getting the peer's MSPID: %v", err) - } - - if clientMSPID != peerMSPID { - return fmt.Errorf("client from org %v is not authorized to read or write private data from an org %v peer", clientMSPID, peerMSPID) - } - - return nil -} - -func contains(sli []string, str string) bool { - for _, a := range sli { - if a == str { - return true - } - } - return false -} diff --git a/auction-simple/chaincode-go/smartContract.go b/auction-simple/chaincode-go/smartContract.go deleted file mode 100644 index c165075d..00000000 --- a/auction-simple/chaincode-go/smartContract.go +++ /dev/null @@ -1,23 +0,0 @@ -/* -SPDX-License-Identifier: Apache-2.0 -*/ - -package main - -import ( - "log" - - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" - "github.com/hyperledger/fabric-samples/auction/chaincode-go/smart-contract" -) - -func main() { - auctionSmartContract, err := contractapi.NewChaincode(&auction.SmartContract{}) - if err != nil { - log.Panicf("Error creating auction chaincode: %v", err) - } - - if err := auctionSmartContract.Start(); err != nil { - log.Panicf("Error starting auction chaincode: %v", err) - } -} diff --git a/token-erc-1155/README.md b/token-erc-1155/README.md deleted file mode 100644 index c6ddfc49..00000000 --- a/token-erc-1155/README.md +++ /dev/null @@ -1,276 +0,0 @@ -# ERC-1155 Chaincode - -This is a sample ERC-1155 chaincode written in Go. - -ERC-20 is the standard for fungible tokens. ERC-721 is the standard for non-fungible tokens. ERC-1155 is the standard for multiple tokens (both fungible and non-fungible). [More information about the ERC-1155 standard can be found here.](https://eips.ethereum.org/EIPS/eip-1155) - -## Architecture -This implementation aims for high throughput by minimizing key collisions. The balance of accounts is distributed over multiple keys. The token transfers can be batched using the batched versions of functions (e.g. BatchTransferFrom, BalanceOfBatch). Since ERC-1155 is account-based, the interface of the chaincode is account-based. However, since the balances are distributed over multiple keys, the chaincode has a model similar to a UTXO-based chaincode internally. - -In this chaincode, one organization has a minter/burner role just like in the [ERC-20 example in this repository](https://github.com/hyperledger/fabric-samples/tree/main/token-erc-20). - - -## Functions Implemented -The following required functions of ERC-1155 are implemented: -- safeTransferFrom -- safeBatchTransferFrom -- balanceOf -- balanceOfBatch -- setApprovalForAll -- isApprovedForAll - -Note: The "safe" prefix is omitted from "TransferFrom" in the implementation because the prefix is related to some issue about backwards compatibility with older smart contracts in Ethereum. - -Note: TransferFrom is used to send a single token type between two users. BatchTransferFrom is used to send multiple tokens between two users. So, BatchTransferFrom is a more general form of TransferFrom. Ethereum defined two functions instead of one because this reduces gas costs. Since there is no gas cost in Fabric, implementing these two functions is unnecessary. Nevertheless, both of them are implemented to to conform the ERC-1155 standard. - -## Additional Functions Implemented - -The following additional functions are also implemented. The following paragraphs give the reasoning behind adding these functions: -- Optional Metadata URI extension: -Defined in ERC-1155 but not required. Allows one to set a URI for tokens and get the URI. - - SetURI - - URI -- Mint/Burn extension: -Although Mint / Burn are not required, they are necessary to change the supply of tokens, create new fungible or non-fungible tokens. In a real implementation, they will be implemented unless the supply of the tokens is fixed beforehand. MintBatch / BurnBatch is only implemented to complement the TransferFrom/BatchTransferFrom. Actually, using only MintBatch and BurnBatch would be enough. - - Mint - - MintBatch - - Burn - - BurnBatch -- Extra/utility functions - - BatchTransferFromMultiRecipient: This is not defined in the standard. We created this function to solve an issue we encountered. It is only required if a person wants to send tokens to multiple persons in a blockchain block. If a person doesn't use this function and create two transactions in a single block, there will be key conflicts because the chaincode will try to decrement the balance of the sender twice in a block and this causes a key conflict in Fabric [just like explained in here](https://github.com/hyperledger/fabric-samples/tree/main/high-throughput). This problem does not exist in Ethereum because, in Ethereum, the transactions are ordered before they are executed. - - BroadcastTokenExistence: Explained in ERC-1155 but it is not required. It is only used if a token minter wants to announce the existence of a token without minting it. - - ClientAccountID: This function is special for Fabric because we do not have wallet addresses in Fabric and users need to know their account ID to transfer tokens. - - ClientAccountBalance: A shorthand for BalanceOf function. - -## Example Usage - -### Launch test network - -Open a command terminal and navigate to the test network directory. - -```bash -cd fabric-samples/test-network -``` - -Clean up the existing network if you have any. -```bash -./network.sh down -``` - -Start test network -```bash -./network.sh up createChannel -ca -``` - -### Deploy chaincode - -Deploy ERC-1155 chaincode. - -```bash -./network.sh deployCC -ccn erc1155 -ccp ../token-erc-1155/chaincode-go/ -ccl go -``` - -### Register identities - -In this example, there are two organizations (org). We will register new identities using the Org1 and Org2 Certificate Authorities (CA's), and then use the CA's to generate each identity's certificate and private key. - -We need to set the following environment variables to use the Fabric CA client (and subsequent commands). The first command sets Fabric config path. The second command adds Fabric CLI utilities to path. - -```bash -export FABRIC_CFG_PATH=${PWD}/../config/ -export PATH=${PWD}/../bin:$PATH -``` - -The terminal we have been using will represent Org1. We will use the Org1 CA to create a new identity. Set the Fabric CA client home to the MSP of the Org1 CA admin (this identity was generated by the test network script). - -```bash -export FABRIC_CA_CLIENT_HOME=${PWD}/organizations/peerOrganizations/org1.example.com/ -``` - -Register `Person1` identity to Org1. -```bash -fabric-ca-client register --caname ca-org1 --id.name person1 --id.secret person1pw --id.type client --tls.certfiles "${PWD}/organizations/fabric-ca/org1/tls-cert.pem" -``` - -Generate the identity certificates and MSP folder. - -```bash -fabric-ca-client enroll -u https://person1:person1pw@localhost:7054 --caname ca-org1 -M "${PWD}/organizations/peerOrganizations/org1.example.com/users/person1@org1.example.com/msp" --tls.certfiles "${PWD}/organizations/fabric-ca/org1/tls-cert.pem" -``` - -Copy the Node OU configuration file into the identity MSP folder. - -```bash -cp "${PWD}/organizations/peerOrganizations/org1.example.com/msp/config.yaml" "${PWD}/organizations/peerOrganizations/org1.example.com/users/person1@org1.example.com/msp/config.yaml" -``` - -Open a new terminal to represent Org2 and navigate to fabric-samples/test-network. We'll use the Org2 CA to create the Org2 identities. Set the Fabric CA client home to the MSP of the Org2 CA admin. - -```bash -cd fabric-samples/test-network -export FABRIC_CFG_PATH=${PWD}/../config/ -export PATH=${PWD}/../bin:$PATH -export FABRIC_CA_CLIENT_HOME=${PWD}/organizations/peerOrganizations/org2.example.com/ -``` - -Register `Person2`, `Person3`, `Person4`, `Person5` to Org2. - -```bash -fabric-ca-client register --caname ca-org2 --id.name person2 --id.secret person2pw --id.type client --tls.certfiles "${PWD}/organizations/fabric-ca/org2/tls-cert.pem" -fabric-ca-client enroll -u https://person2:person2pw@localhost:8054 --caname ca-org2 -M "${PWD}/organizations/peerOrganizations/org2.example.com/users/person2@org2.example.com/msp" --tls.certfiles "${PWD}/organizations/fabric-ca/org2/tls-cert.pem" -cp "${PWD}/organizations/peerOrganizations/org2.example.com/msp/config.yaml" "${PWD}/organizations/peerOrganizations/org2.example.com/users/person2@org2.example.com/msp/config.yaml" - -fabric-ca-client register --caname ca-org2 --id.name person3 --id.secret person3pw --id.type client --tls.certfiles "${PWD}/organizations/fabric-ca/org2/tls-cert.pem" -fabric-ca-client enroll -u https://person3:person3pw@localhost:8054 --caname ca-org2 -M "${PWD}/organizations/peerOrganizations/org2.example.com/users/person3@org2.example.com/msp" --tls.certfiles "${PWD}/organizations/fabric-ca/org2/tls-cert.pem" -cp "${PWD}/organizations/peerOrganizations/org2.example.com/msp/config.yaml" "${PWD}/organizations/peerOrganizations/org2.example.com/users/person3@org2.example.com/msp/config.yaml" - -fabric-ca-client register --caname ca-org2 --id.name person4 --id.secret person4pw --id.type client --tls.certfiles "${PWD}/organizations/fabric-ca/org2/tls-cert.pem" -fabric-ca-client enroll -u https://person4:person4pw@localhost:8054 --caname ca-org2 -M "${PWD}/organizations/peerOrganizations/org2.example.com/users/person4@org2.example.com/msp" --tls.certfiles "${PWD}/organizations/fabric-ca/org2/tls-cert.pem" -cp "${PWD}/organizations/peerOrganizations/org2.example.com/msp/config.yaml" "${PWD}/organizations/peerOrganizations/org2.example.com/users/person4@org2.example.com/msp/config.yaml" - -fabric-ca-client register --caname ca-org2 --id.name person5 --id.secret person5pw --id.type client --tls.certfiles "${PWD}/organizations/fabric-ca/org2/tls-cert.pem" -fabric-ca-client enroll -u https://person5:person5pw@localhost:8054 --caname ca-org2 -M "${PWD}/organizations/peerOrganizations/org2.example.com/users/person5@org2.example.com/msp" --tls.certfiles "${PWD}/organizations/fabric-ca/org2/tls-cert.pem" -cp "${PWD}/organizations/peerOrganizations/org2.example.com/msp/config.yaml" "${PWD}/organizations/peerOrganizations/org2.example.com/users/person5@org2.example.com/msp/config.yaml" -``` - -## Initialize the contract -Once we created the identity of the minter we can now initialize the contract. -Note that we need to call the initialize function before being able to use any functions of the contract. Initialize() can be called only once. - -Shift back to the Org1 terminal, we'll set the following environment variables to operate the `peer` CLI as the minter identity from Org1. -```bash -export CORE_PEER_TLS_ENABLED=true -export CORE_PEER_LOCALMSPID=Org1MSP -export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/person1@org1.example.com/msp -export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt -export CORE_PEER_ADDRESS=localhost:7051 -export TARGET_TLS_OPTIONS=(-o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" --peerAddresses localhost:7051 --tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt" --peerAddresses localhost:9051 --tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt")``` - -We can then invoke the smart contract to initialize it: -```bash -peer chaincode invoke "${TARGET_TLS_OPTIONS[@]}" -C mychannel -n erc1155 -c '{"function":"Initialize","Args":["some name", "some symbol"]}' -``` - -### Get account ID - -Now, get client account ID for Person1. -```bash -peer chaincode query -C mychannel -n erc1155 -c '{"function":"ClientAccountID","Args":[]}' -``` - -``` -eDUwOTo6Q049cGVyc29uMSxPVT1jbGllbnQsTz1IeXBlcmxlZGdlcixTVD1Ob3J0aCBDYXJvbGluYSxDPVVTOjpDTj1jYS5vcmcxLmV4YW1wbGUuY29tLE89b3JnMS5leGFtcGxlLmNvbSxMPUR1cmhhbSxTVD1Ob3J0aCBDYXJvbGluYSxDPVVT -``` - -Client Account ID is a base64-encoded concatenation of the issuer and subject from the client identity's enrolment certificate. -You can decode it with the following command: - -```bash -echo "eDUwOTo6Q049cGVyc29uMSxPVT1jbGllbnQsTz1IeXBlcmxlZGdlcixTVD1Ob3J0aCBDYXJvbGluYSxDPVVTOjpDTj1jYS5vcmcxLmV4YW1wbGUuY29tLE89b3JnMS5leGFtcGxlLmNvbSxMPUR1cmhhbSxTVD1Ob3J0aCBDYXJvbGluYSxDPVVT" | base64 --decode -``` - -``` -x509::CN=person1,OU=client,O=Hyperledger,ST=North Carolina,C=US::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US -``` - -Set the client account IDs as environment variables on both of the terminals to make the subsequent commands more readable. -```bash -export P1="eDUwOTo6Q049cGVyc29uMSxPVT1jbGllbnQsTz1IeXBlcmxlZGdlcixTVD1Ob3J0aCBDYXJvbGluYSxDPVVTOjpDTj1jYS5vcmcxLmV4YW1wbGUuY29tLE89b3JnMS5leGFtcGxlLmNvbSxMPUR1cmhhbSxTVD1Ob3J0aCBDYXJvbGluYSxDPVVT" -export P2="eDUwOTo6Q049cGVyc29uMixPVT1jbGllbnQsTz1IeXBlcmxlZGdlcixTVD1Ob3J0aCBDYXJvbGluYSxDPVVTOjpDTj1jYS5vcmcyLmV4YW1wbGUuY29tLE89b3JnMi5leGFtcGxlLmNvbSxMPUh1cnNsZXksU1Q9SGFtcHNoaXJlLEM9VUs=" -export P3="eDUwOTo6Q049cGVyc29uMyxPVT1jbGllbnQsTz1IeXBlcmxlZGdlcixTVD1Ob3J0aCBDYXJvbGluYSxDPVVTOjpDTj1jYS5vcmcyLmV4YW1wbGUuY29tLE89b3JnMi5leGFtcGxlLmNvbSxMPUh1cnNsZXksU1Q9SGFtcHNoaXJlLEM9VUs=" -export P4="eDUwOTo6Q049cGVyc29uNCxPVT1jbGllbnQsTz1IeXBlcmxlZGdlcixTVD1Ob3J0aCBDYXJvbGluYSxDPVVTOjpDTj1jYS5vcmcyLmV4YW1wbGUuY29tLE89b3JnMi5leGFtcGxlLmNvbSxMPUh1cnNsZXksU1Q9SGFtcHNoaXJlLEM9VUs=" -export P5="eDUwOTo6Q049cGVyc29uNSxPVT1jbGllbnQsTz1IeXBlcmxlZGdlcixTVD1Ob3J0aCBDYXJvbGluYSxDPVVTOjpDTj1jYS5vcmcyLmV4YW1wbGUuY29tLE89b3JnMi5leGFtcGxlLmNvbSxMPUh1cnNsZXksU1Q9SGFtcHNoaXJlLEM9VUs=" -``` - -### Mint tokens - -Mint tokens by calling the MintBatch function in order to create 100 token1s, 200 token2s, 300 token3s, 150 token4s, 100 token5s, 100 token6s as Person P1 from organization 1. - -```bash -peer chaincode invoke "${TARGET_TLS_OPTIONS[@]}" -C mychannel -n erc1155 -c "{\"function\":\"MintBatch\",\"Args\":[\"$P1\",\"[1,2,3,4,5,6]\",\"[100,200,300,150,100,100]\"]}" --waitForEvent -``` - -Query the tokens of Person1. - -```bash -peer chaincode query -C mychannel -n erc1155 -c "{\"function\":\"BalanceOfBatch\",\"Args\":[\"[\\\"$P1\\\",\\\"$P1\\\",\\\"$P1\\\",\\\"$P1\\\",\\\"$P1\\\",\\\"$P1\\\"]\",\"[1,2,3,4,5,6]\"]}" -``` - -``` -[100,200,300,150,100,100] -``` - -Side note: There may seem too many slashes in the previous command. It double escapes the quotes. One escape is to be able to use quotes in the `-c` argument of the command. The second escape is necessary to pass the account IDs as an array. Quote is needed since the elements of the array are strings. - -### Transfer tokens - -#### TransferFrom - -Send Person P2 six token3s by calling TransferFrom as Person P1. -```bash -peer chaincode invoke "${TARGET_TLS_OPTIONS[@]}" -C mychannel -n erc1155 -c "{\"function\":\"TransferFrom\",\"Args\":[\"$P1\",\"$P2\",\"3\",\"6\"]}" --waitForEvent -``` - -Get the new Balance of Person1 for token3. -```bash -peer chaincode query -C mychannel -n erc1155 -c "{\"function\":\"BalanceOf\",\"Args\":[\"$P1\",\"3\"]}" -``` - -``` -294 -``` - -Switch to the Org2 terminal and set the following environment variables. -```bash -export FABRIC_CFG_PATH=$PWD/../config/ -export CORE_PEER_TLS_ENABLED=true -export CORE_PEER_LOCALMSPID=Org2MSP -export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/person2@org2.example.com/msp -export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -export CORE_PEER_ADDRESS=localhost:9051 -export TARGET_TLS_OPTIONS=(-o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" --peerAddresses localhost:7051 --tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt" --peerAddresses localhost:9051 --tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt") -``` - -Get the new balance of Person2 for token3. -```bash -peer chaincode query -C mychannel -n erc1155 -c "{\"function\":\"BalanceOf\",\"Args\":[\"$P2\",\"3\"]}" -``` - -``` -6 -``` - -#### BatchTransferFrom - -Switch to the Org1 terminal. - -Send Person P2 six token3s, three token4s, and one token2s by calling BatchTransferFrom as Person P1. - -```bash -peer chaincode invoke "${TARGET_TLS_OPTIONS[@]}" -C mychannel -n erc1155 -c "{\"function\":\"BatchTransferFrom\",\"Args\":[\"$P1\",\"$P2\",\"[3,4,2]\",\"[6,3,1]\"]}" --waitForEvent -``` - -#### BatchTransferFromMultiReceipent - -Call BatchTransferFromMultiReceipent as Person1 in order to send: -- six token5s to person P3, -- six token3s to person P4, -- three token4s to person P2, -- two token2s to person P5, -- and three token6s to person P2. - -```bash -peer chaincode invoke "${TARGET_TLS_OPTIONS[@]}" -C mychannel -n erc1155 -c "{\"function\":\"BatchTransferFromMultiRecipient\",\"Args\":[\"$P1\",\"[\\\"$P3\\\",\\\"$P4\\\",\\\"$P2\\\",\\\"$P5\\\",\\\"$P2\\\"]\",\"[5,3,4,2,6]\",\"[6,6,3,2,3]\"]}" --waitForEvent -``` - -### Clean up - -When you are finished, you can bring down the test network. This command will bring down the CAs, peers, and ordering node of the network that you created. - -```bash -./network.sh down -``` - -## Acknowledgement - -This work has been carried out at Boğaziçi University and has received funding from the European Union’s Horizon 2020 Research and Innovation programme under Grant Agreement No. 856632. diff --git a/token-erc-1155/chaincode-go/chaincode/contract.go b/token-erc-1155/chaincode-go/chaincode/contract.go deleted file mode 100644 index acd1fa9c..00000000 --- a/token-erc-1155/chaincode-go/chaincode/contract.go +++ /dev/null @@ -1,1161 +0,0 @@ -/* - 2021 Baran Kılıç - - SPDX-License-Identifier: Apache-2.0 -*/ - -package chaincode - -import ( - "encoding/json" - "fmt" - "sort" - "strconv" - "strings" - - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" -) - -const uriKey = "uri" - -const balancePrefix = "account~tokenId~sender" -const approvalPrefix = "account~operator" - -const minterMSPID = "Org1MSP" - -// Define key names for options -const nameKey = "name" -const symbolKey = "symbol" - -// SmartContract provides functions for transferring tokens between accounts -type SmartContract struct { - contractapi.Contract -} - -// TransferSingle MUST emit when a single token is transferred, including zero -// value transfers as well as minting or burning. -// The operator argument MUST be msg.sender. -// The from argument MUST be the address of the holder whose balance is decreased. -// The to argument MUST be the address of the recipient whose balance is increased. -// The id argument MUST be the token type being transferred. -// The value argument MUST be the number of tokens the holder balance is decreased -// by and match what the recipient balance is increased by. -// When minting/creating tokens, the from argument MUST be set to `0x0` (i.e. zero address). -// When burning/destroying tokens, the to argument MUST be set to `0x0` (i.e. zero address). -type TransferSingle struct { - Operator string `json:"operator"` - From string `json:"from"` - To string `json:"to"` - ID uint64 `json:"id"` - Value uint64 `json:"value"` -} - -// TransferBatch MUST emit when tokens are transferred, including zero value -// transfers as well as minting or burning. -// The operator argument MUST be msg.sender. -// The from argument MUST be the address of the holder whose balance is decreased. -// The to argument MUST be the address of the recipient whose balance is increased. -// The ids argument MUST be the list of tokens being transferred. -// The values argument MUST be the list of number of tokens (matching the list -// and order of tokens specified in _ids) the holder balance is decreased by -// and match what the recipient balance is increased by. -// When minting/creating tokens, the from argument MUST be set to `0x0` (i.e. zero address). -// When burning/destroying tokens, the to argument MUST be set to `0x0` (i.e. zero address). -type TransferBatch struct { - Operator string `json:"operator"` - From string `json:"from"` - To string `json:"to"` - IDs []uint64 `json:"ids"` - Values []uint64 `json:"values"` -} - -// TransferBatchMultiRecipient MUST emit when tokens are transferred, including zero value -// transfers as well as minting or burning. -// The operator argument MUST be msg.sender. -// The from argument MUST be the address of the holder whose balance is decreased. -// The to argument MUST be the list of the addresses of the recipients whose balance is increased. -// The ids argument MUST be the list of tokens being transferred. -// The values argument MUST be the list of number of tokens (matching the list -// and order of tokens specified in _ids) the holder balance is decreased by -// and match what the recipient balance is increased by. -// When minting/creating tokens, the from argument MUST be set to `0x0` (i.e. zero address). -// When burning/destroying tokens, the to argument MUST be set to `0x0` (i.e. zero address). -type TransferBatchMultiRecipient struct { - Operator string `json:"operator"` - From string `json:"from"` - To []string `json:"to"` - IDs []uint64 `json:"ids"` - Values []uint64 `json:"values"` -} - -// ApprovalForAll MUST emit when approval for a second party/operator address -// to manage all tokens for an owner address is enabled or disabled -// (absence of an event assumes disabled). -type ApprovalForAll struct { - Owner string `json:"owner"` - Operator string `json:"operator"` - Approved bool `json:"approved"` -} - -// URI MUST emit when the URI is updated for a token ID. -// Note: This event is not used in this contract implementation because in this implementation, -// only the programmatic way of setting URI is used. The URI should contain {id} as part of it -// and the clients MUST replace this with the actual token ID. -type URI struct { - Value string `json:"value"` - ID uint64 `json:"id"` -} - -// To represents recipient address -// ID represents token ID -type ToID struct { - To string - ID uint64 -} - -// Mint creates amount tokens of token type id and assigns them to account. -// This function emits a TransferSingle event. -func (s *SmartContract) Mint(ctx contractapi.TransactionContextInterface, account string, id uint64, amount uint64) error { - - // Check if contract has been intilized first - initialized, err := checkInitialized(ctx) - if err != nil { - return fmt.Errorf("failed to check if contract is already initialized: %v", err) - } - if !initialized { - return fmt.Errorf("Contract options need to be set before calling any function, call Initialize() to initialize contract") - } - - // Check minter authorization - this sample assumes Org1 is the central banker with privilege to mint new tokens - err = authorizationHelper(ctx) - if err != nil { - return err - } - - // Get ID of submitting client identity - operator, err := ctx.GetClientIdentity().GetID() - if err != nil { - return fmt.Errorf("failed to get client id: %v", err) - } - - // Mint tokens - err = mintHelper(ctx, operator, account, id, amount) - if err != nil { - return err - } - - // Emit TransferSingle event - transferSingleEvent := TransferSingle{operator, "0x0", account, id, amount} - return emitTransferSingle(ctx, transferSingleEvent) -} - -// MintBatch creates amount tokens for each token type id and assigns them to account. -// This function emits a TransferBatch event. -func (s *SmartContract) MintBatch(ctx contractapi.TransactionContextInterface, account string, ids []uint64, amounts []uint64) error { - - // Check if contract has been intilized first - initialized, err := checkInitialized(ctx) - if err != nil { - return fmt.Errorf("failed to check if contract is already initialized: %v", err) - } - if !initialized { - return fmt.Errorf("Contract options need to be set before calling any function, call Initialize() to initialize contract") - } - - if len(ids) != len(amounts) { - return fmt.Errorf("ids and amounts must have the same length") - } - - // Check minter authorization - this sample assumes Org1 is the central banker with privilege to mint new tokens - err = authorizationHelper(ctx) - if err != nil { - return err - } - - // Get ID of submitting client identity - operator, err := ctx.GetClientIdentity().GetID() - if err != nil { - return fmt.Errorf("failed to get client id: %v", err) - } - - // Group amount by token id because we can only send token to a recipient only one time in a block. This prevents key conflicts - amountToSend := make(map[uint64]uint64) // token id => amount - - for i := 0; i < len(amounts); i++ { - amountToSend[ids[i]], err = add(amountToSend[ids[i]], amounts[i]) - if err != nil { - return err - } - } - - // Copy the map keys and sort it. This is necessary because iterating maps in Go is not deterministic - amountToSendKeys := sortedKeys(amountToSend) - - // Mint tokens - for _, id := range amountToSendKeys { - amount := amountToSend[id] - err = mintHelper(ctx, operator, account, id, amount) - if err != nil { - return err - } - } - - // Emit TransferBatch event - transferBatchEvent := TransferBatch{operator, "0x0", account, ids, amounts} - return emitTransferBatch(ctx, transferBatchEvent) -} - -// Burn destroys amount tokens of token type id from account. -// This function triggers a TransferSingle event. -func (s *SmartContract) Burn(ctx contractapi.TransactionContextInterface, account string, id uint64, amount uint64) error { - - // Check if contract has been intilized first - initialized, err := checkInitialized(ctx) - if err != nil { - return fmt.Errorf("failed to check if contract is already initialized: %v", err) - } - if !initialized { - return fmt.Errorf("Contract options need to be set before calling any function, call Initialize() to initialize contract") - } - - if account == "0x0" { - return fmt.Errorf("burn to the zero address") - } - - // Check minter authorization - this sample assumes Org1 is the central banker with privilege to burn new tokens - err = authorizationHelper(ctx) - if err != nil { - return err - } - - // Get ID of submitting client identity - operator, err := ctx.GetClientIdentity().GetID() - if err != nil { - return fmt.Errorf("failed to get client id: %v", err) - } - - // Burn tokens - err = removeBalance(ctx, account, []uint64{id}, []uint64{amount}) - if err != nil { - return err - } - - transferSingleEvent := TransferSingle{operator, account, "0x0", id, amount} - return emitTransferSingle(ctx, transferSingleEvent) -} - -// BurnBatch destroys amount tokens of for each token type id from account. -// This function emits a TransferBatch event. -func (s *SmartContract) BurnBatch(ctx contractapi.TransactionContextInterface, account string, ids []uint64, amounts []uint64) error { - - // Check if contract has been intilized first - initialized, err := checkInitialized(ctx) - if err != nil { - return fmt.Errorf("failed to check if contract is already initialized: %v", err) - } - if !initialized { - return fmt.Errorf("Contract options need to be set before calling any function, call Initialize() to initialize contract") - } - - if account == "0x0" { - return fmt.Errorf("burn to the zero address") - } - - if len(ids) != len(amounts) { - return fmt.Errorf("ids and amounts must have the same length") - } - - // Check minter authorization - this sample assumes Org1 is the central banker with privilege to burn new tokens - err = authorizationHelper(ctx) - if err != nil { - return err - } - - // Get ID of submitting client identity - operator, err := ctx.GetClientIdentity().GetID() - if err != nil { - return fmt.Errorf("failed to get client id: %v", err) - } - - err = removeBalance(ctx, account, ids, amounts) - if err != nil { - return err - } - - transferBatchEvent := TransferBatch{operator, account, "0x0", ids, amounts} - return emitTransferBatch(ctx, transferBatchEvent) -} - -// TransferFrom transfers tokens from sender account to recipient account -// recipient account must be a valid clientID as returned by the ClientID() function -// This function triggers a TransferSingle event -func (s *SmartContract) TransferFrom(ctx contractapi.TransactionContextInterface, sender string, recipient string, id uint64, amount uint64) error { - - // Check if contract has been intilized first - initialized, err := checkInitialized(ctx) - if err != nil { - return fmt.Errorf("failed to check if contract is already initialized: %v", err) - } - if !initialized { - return fmt.Errorf("Contract options need to be set before calling any function, call Initialize() to initialize contract") - } - - if sender == recipient { - return fmt.Errorf("transfer to self") - } - - // Get ID of submitting client identity - operator, err := ctx.GetClientIdentity().GetID() - if err != nil { - return fmt.Errorf("failed to get client id: %v", err) - } - - // Check whether operator is owner or approved - if operator != sender { - approved, err := _isApprovedForAll(ctx, sender, operator) - if err != nil { - return err - } - if !approved { - return fmt.Errorf("caller is not owner nor is approved") - } - } - - // Withdraw the funds from the sender address - err = removeBalance(ctx, sender, []uint64{id}, []uint64{amount}) - if err != nil { - return err - } - - if recipient == "0x0" { - return fmt.Errorf("transfer to the zero address") - } - - // Deposit the fund to the recipient address - err = addBalance(ctx, sender, recipient, id, amount) - if err != nil { - return err - } - - // Emit TransferSingle event - transferSingleEvent := TransferSingle{operator, sender, recipient, id, amount} - return emitTransferSingle(ctx, transferSingleEvent) -} - -// BatchTransferFrom transfers multiple tokens from sender account to recipient account -// recipient account must be a valid clientID as returned by the ClientID() function -// This function triggers a TransferBatch event -func (s *SmartContract) BatchTransferFrom(ctx contractapi.TransactionContextInterface, sender string, recipient string, ids []uint64, amounts []uint64) error { - - // Check if contract has been intilized first - initialized, err := checkInitialized(ctx) - if err != nil { - return fmt.Errorf("failed to check if contract is already initialized: %v", err) - } - if !initialized { - return fmt.Errorf("Contract options need to be set before calling any function, call Initialize() to initialize contract") - } - - if sender == recipient { - return fmt.Errorf("transfer to self") - } - - if len(ids) != len(amounts) { - return fmt.Errorf("ids and amounts must have the same length") - } - - // Get ID of submitting client identity - operator, err := ctx.GetClientIdentity().GetID() - if err != nil { - return fmt.Errorf("failed to get client id: %v", err) - } - - // Check whether operator is owner or approved - if operator != sender { - approved, err := _isApprovedForAll(ctx, sender, operator) - if err != nil { - return err - } - if !approved { - return fmt.Errorf("caller is not owner nor is approved") - } - } - - // Withdraw the funds from the sender address - err = removeBalance(ctx, sender, ids, amounts) - if err != nil { - return err - } - - if recipient == "0x0" { - return fmt.Errorf("transfer to the zero address") - } - - // Group amount by token id because we can only send token to a recipient only one time in a block. This prevents key conflicts - amountToSend := make(map[uint64]uint64) // token id => amount - - for i := 0; i < len(amounts); i++ { - amountToSend[ids[i]], err = add(amountToSend[ids[i]], amounts[i]) - if err != nil { - return err - } - } - - // Copy the map keys and sort it. This is necessary because iterating maps in Go is not deterministic - amountToSendKeys := sortedKeys(amountToSend) - - // Deposit the funds to the recipient address - for _, id := range amountToSendKeys { - amount := amountToSend[id] - err = addBalance(ctx, sender, recipient, id, amount) - if err != nil { - return err - } - } - - transferBatchEvent := TransferBatch{operator, sender, recipient, ids, amounts} - return emitTransferBatch(ctx, transferBatchEvent) -} - -// BatchTransferFromMultiRecipient transfers multiple tokens from sender account to multiple recipient accounts -// recipient account must be a valid clientID as returned by the ClientID() function -// This function triggers a TransferBatchMultiRecipient event -func (s *SmartContract) BatchTransferFromMultiRecipient(ctx contractapi.TransactionContextInterface, sender string, recipients []string, ids []uint64, amounts []uint64) error { - - // Check if contract has been intilized first - initialized, err := checkInitialized(ctx) - if err != nil { - return fmt.Errorf("failed to check if contract is already initialized: %v", err) - } - if !initialized { - return fmt.Errorf("Contract options need to be set before calling any function, call Initialize() to initialize contract") - } - - if len(recipients) != len(ids) || len(ids) != len(amounts) { - return fmt.Errorf("recipients, ids, and amounts must have the same length") - } - - for _, recipient := range recipients { - if sender == recipient { - return fmt.Errorf("transfer to self") - } - } - - // Get ID of submitting client identity - operator, err := ctx.GetClientIdentity().GetID() - if err != nil { - return fmt.Errorf("failed to get client id: %v", err) - } - - // Check whether operator is owner or approved - if operator != sender { - approved, err := _isApprovedForAll(ctx, sender, operator) - if err != nil { - return err - } - if !approved { - return fmt.Errorf("caller is not owner nor is approved") - } - } - - // Withdraw the funds from the sender address - err = removeBalance(ctx, sender, ids, amounts) - if err != nil { - return err - } - - // Group amount by (recipient, id ) pair because we can only send token to a recipient only one time in a block. This prevents key conflicts - amountToSend := make(map[ToID]uint64) // (recipient, id ) => amount - - for i := 0; i < len(amounts); i++ { - amountToSend[ToID{recipients[i], ids[i]}], err = add(amountToSend[ToID{recipients[i], ids[i]}], amounts[i]) - if err != nil { - return err - } - } - - // Copy the map keys and sort it. This is necessary because iterating maps in Go is not deterministic - amountToSendKeys := sortedKeysToID(amountToSend) - - // Deposit the funds to the recipient addresses - for _, key := range amountToSendKeys { - if key.To == "0x0" { - return fmt.Errorf("transfer to the zero address") - } - - amount := amountToSend[key] - - err = addBalance(ctx, sender, key.To, key.ID, amount) - if err != nil { - return err - } - } - - // Emit TransferBatchMultiRecipient event - transferBatchMultiRecipientEvent := TransferBatchMultiRecipient{operator, sender, recipients, ids, amounts} - return emitTransferBatchMultiRecipient(ctx, transferBatchMultiRecipientEvent) -} - -// IsApprovedForAll returns true if operator is approved to transfer account's tokens. -func (s *SmartContract) IsApprovedForAll(ctx contractapi.TransactionContextInterface, account string, operator string) (bool, error) { - return _isApprovedForAll(ctx, account, operator) -} - -// _isApprovedForAll returns true if operator is approved to transfer account's tokens. -func _isApprovedForAll(ctx contractapi.TransactionContextInterface, account string, operator string) (bool, error) { - - // Check if contract has been intilized first - initialized, err := checkInitialized(ctx) - if err != nil { - return false, fmt.Errorf("failed to check if contract is already initialized: %v", err) - } - if !initialized { - return false, fmt.Errorf("Contract options need to be set before calling any function, call Initialize() to initialize contract") - } - - approvalKey, err := ctx.GetStub().CreateCompositeKey(approvalPrefix, []string{account, operator}) - if err != nil { - return false, fmt.Errorf("failed to create the composite key for prefix %s: %v", approvalPrefix, err) - } - - approvalBytes, err := ctx.GetStub().GetState(approvalKey) - if err != nil { - return false, fmt.Errorf("failed to read approval of operator %s for account %s from world state: %v", operator, account, err) - } - - if approvalBytes == nil { - return false, nil - } - - var approved bool - err = json.Unmarshal(approvalBytes, &approved) - if err != nil { - return false, fmt.Errorf("failed to decode approval JSON of operator %s for account %s: %v", operator, account, err) - } - - return approved, nil -} - -// SetApprovalForAll returns true if operator is approved to transfer account's tokens. -func (s *SmartContract) SetApprovalForAll(ctx contractapi.TransactionContextInterface, operator string, approved bool) error { - - // Check if contract has been intilized first - initialized, err := checkInitialized(ctx) - if err != nil { - return fmt.Errorf("failed to check if contract is already initialized: %v", err) - } - if !initialized { - return fmt.Errorf("Contract options need to be set before calling any function, call Initialize() to initialize contract") - } - - // Get ID of submitting client identity - account, err := ctx.GetClientIdentity().GetID() - if err != nil { - return fmt.Errorf("failed to get client id: %v", err) - } - - if account == operator { - return fmt.Errorf("setting approval status for self") - } - - approvalForAllEvent := ApprovalForAll{account, operator, approved} - approvalForAllEventJSON, err := json.Marshal(approvalForAllEvent) - if err != nil { - return fmt.Errorf("failed to obtain JSON encoding: %v", err) - } - err = ctx.GetStub().SetEvent("ApprovalForAll", approvalForAllEventJSON) - if err != nil { - return fmt.Errorf("failed to set event: %v", err) - } - - approvalKey, err := ctx.GetStub().CreateCompositeKey(approvalPrefix, []string{account, operator}) - if err != nil { - return fmt.Errorf("failed to create the composite key for prefix %s: %v", approvalPrefix, err) - } - - approvalJSON, err := json.Marshal(approved) - if err != nil { - return fmt.Errorf("failed to encode approval JSON of operator %s for account %s: %v", operator, account, err) - } - - err = ctx.GetStub().PutState(approvalKey, approvalJSON) - if err != nil { - return err - } - - return nil -} - -// BalanceOf returns the balance of the given account -func (s *SmartContract) BalanceOf(ctx contractapi.TransactionContextInterface, account string, id uint64) (uint64, error) { - - // Check if contract has been intilized first - initialized, err := checkInitialized(ctx) - if err != nil { - return 0, fmt.Errorf("failed to check if contract is already initialized: %v", err) - } - if !initialized { - return 0, fmt.Errorf("Contract options need to be set before calling any function, call Initialize() to initialize contract") - } - - return balanceOfHelper(ctx, account, id) -} - -// BalanceOfBatch returns the balance of multiple account/token pairs -func (s *SmartContract) BalanceOfBatch(ctx contractapi.TransactionContextInterface, accounts []string, ids []uint64) ([]uint64, error) { - - // Check if contract has been intilized first - initialized, err := checkInitialized(ctx) - if err != nil { - return nil, fmt.Errorf("failed to check if contract is already initialized: %v", err) - } - if !initialized { - return nil, fmt.Errorf("Contract options need to be set before calling any function, call Initialize() to initialize contract") - } - - if len(accounts) != len(ids) { - return nil, fmt.Errorf("accounts and ids must have the same length") - } - - balances := make([]uint64, len(accounts)) - - for i := 0; i < len(accounts); i++ { - var err error - balances[i], err = balanceOfHelper(ctx, accounts[i], ids[i]) - if err != nil { - return nil, err - } - } - - return balances, nil -} - -// ClientAccountBalance returns the balance of the requesting client's account -func (s *SmartContract) ClientAccountBalance(ctx contractapi.TransactionContextInterface, id uint64) (uint64, error) { - - // Check if contract has been intilized first - initialized, err := checkInitialized(ctx) - if err != nil { - return 0, fmt.Errorf("failed to check if contract is already initialized: %v", err) - } - if !initialized { - return 0, fmt.Errorf("Contract options need to be set before calling any function, call Initialize() to initialize contract") - } - - // Get ID of submitting client identity - clientID, err := ctx.GetClientIdentity().GetID() - if err != nil { - return 0, fmt.Errorf("failed to get client id: %v", err) - } - - return balanceOfHelper(ctx, clientID, id) -} - -// ClientAccountID returns the id of the requesting client's account -// In this implementation, the client account ID is the clientId itself -// Users can use this function to get their own account id, which they can then give to others as the payment address -func (s *SmartContract) ClientAccountID(ctx contractapi.TransactionContextInterface) (string, error) { - - // Check if contract has been intilized first - initialized, err := checkInitialized(ctx) - if err != nil { - return "", fmt.Errorf("failed to check if contract is already initialized: %v", err) - } - if !initialized { - return "", fmt.Errorf("Contract options need to be set before calling any function, call Initialize() to initialize contract") - } - - // Get ID of submitting client identity - clientAccountID, err := ctx.GetClientIdentity().GetID() - if err != nil { - return "", fmt.Errorf("failed to get client id: %v", err) - } - - return clientAccountID, nil -} - -// SetURI set the URI value -// This function triggers URI event for each token id -func (s *SmartContract) SetURI(ctx contractapi.TransactionContextInterface, uri string) error { - - // Check if contract has been intilized first - initialized, err := checkInitialized(ctx) - if err != nil { - return fmt.Errorf("failed to check if contract is already initialized: %v", err) - } - if !initialized { - return fmt.Errorf("Contract options need to be set before calling any function, call Initialize() to initialize contract") - } - - // Check minter authorization - this sample assumes Org1 is the central banker with privilege to mint new tokens - err = authorizationHelper(ctx) - if err != nil { - return err - } - - if !strings.Contains(uri, "{id}") { - return fmt.Errorf("failed to set uri, uri should contain '{id}'") - } - - err = ctx.GetStub().PutState(uriKey, []byte(uri)) - if err != nil { - return fmt.Errorf("failed to set uri: %v", err) - } - - return nil -} - -// URI returns the URI -func (s *SmartContract) URI(ctx contractapi.TransactionContextInterface, id uint64) (string, error) { - - // Check if contract has been intilized first - initialized, err := checkInitialized(ctx) - if err != nil { - return "", fmt.Errorf("failed to check if contract is already initialized: %v", err) - } - if !initialized { - return "", fmt.Errorf("Contract options need to be set before calling any function, call Initialize() to initialize contract") - } - - uriBytes, err := ctx.GetStub().GetState(uriKey) - if err != nil { - return "", fmt.Errorf("failed to get uri: %v", err) - } - - if uriBytes == nil { - return "", fmt.Errorf("no uri is set: %v", err) - } - - return string(uriBytes), nil -} - -func (s *SmartContract) BroadcastTokenExistance(ctx contractapi.TransactionContextInterface, id uint64) error { - - // Check if contract has been intilized first - initialized, err := checkInitialized(ctx) - if err != nil { - return fmt.Errorf("failed to check if contract is already initialized: %v", err) - } - if !initialized { - return fmt.Errorf("Contract options need to be set before calling any function, call Initialize() to initialize contract") - } - - // Check minter authorization - this sample assumes Org1 is the central banker with privilege to mint new tokens - err = authorizationHelper(ctx) - if err != nil { - return err - } - - // Get ID of submitting client identity - operator, err := ctx.GetClientIdentity().GetID() - if err != nil { - return fmt.Errorf("failed to get client id: %v", err) - } - - // Emit TransferSingle event - transferSingleEvent := TransferSingle{operator, "0x0", "0x0", id, 0} - return emitTransferSingle(ctx, transferSingleEvent) -} - -// Name returns a descriptive name for fungible tokens in this contract -// returns {String} Returns the name of the token - -func (s *SmartContract) Name(ctx contractapi.TransactionContextInterface) (string, error) { - - // Check if contract has been intilized first - initialized, err := checkInitialized(ctx) - if err != nil { - return "", fmt.Errorf("failed to check if contract is already initialized: %v", err) - } - if !initialized { - return "", fmt.Errorf("Contract options need to be set before calling any function, call Initialize() to initialize contract") - } - - bytes, err := ctx.GetStub().GetState(nameKey) - if err != nil { - return "", fmt.Errorf("failed to get Name bytes: %s", err) - } - - return string(bytes), nil -} - -// Symbol returns an abbreviated name for fungible tokens in this contract. -// returns {String} Returns the symbol of the token - -func (s *SmartContract) Symbol(ctx contractapi.TransactionContextInterface) (string, error) { - - // Check if contract has been intilized first - initialized, err := checkInitialized(ctx) - if err != nil { - return "", fmt.Errorf("failed to check if contract is already initialized: %v", err) - } - if !initialized { - return "", fmt.Errorf("Contract options need to be set before calling any function, call Initialize() to initialize contract") - } - - bytes, err := ctx.GetStub().GetState(symbolKey) - if err != nil { - return "", fmt.Errorf("failed to get Symbol: %v", err) - } - - return string(bytes), nil -} - -// Set information for a token and intialize contract. -// param {String} name The name of the token -// param {String} symbol The symbol of the token -func (s *SmartContract) Initialize(ctx contractapi.TransactionContextInterface, name string, symbol string) (bool, error) { - - // Check minter authorization - this sample assumes Org1 is the central banker with privilege to intitialize contract - clientMSPID, err := ctx.GetClientIdentity().GetMSPID() - if err != nil { - return false, fmt.Errorf("failed to get MSPID: %v", err) - } - if clientMSPID != minterMSPID { - return false, fmt.Errorf("client is not authorized to initialize contract") - } - - // Check contract options are not already set, client is not authorized to change them once intitialized - bytes, err := ctx.GetStub().GetState(nameKey) - if err != nil { - return false, fmt.Errorf("failed to get Name: %v", err) - } - if bytes != nil { - return false, fmt.Errorf("contract options are already set, client is not authorized to change them") - } - - err = ctx.GetStub().PutState(nameKey, []byte(name)) - if err != nil { - return false, fmt.Errorf("failed to set token name: %v", err) - } - - err = ctx.GetStub().PutState(symbolKey, []byte(symbol)) - if err != nil { - return false, fmt.Errorf("failed to set symbol: %v", err) - } - - return true, nil -} - -// Helper Functions - -// authorizationHelper checks minter authorization - this sample assumes Org1 is the central banker with privilege to mint new tokens -func authorizationHelper(ctx contractapi.TransactionContextInterface) error { - - clientMSPID, err := ctx.GetClientIdentity().GetMSPID() - if err != nil { - return fmt.Errorf("failed to get MSPID: %v", err) - } - if clientMSPID != minterMSPID { - return fmt.Errorf("client is not authorized to mint new tokens") - } - - return nil -} - -func mintHelper(ctx contractapi.TransactionContextInterface, operator string, account string, id uint64, amount uint64) error { - if account == "0x0" { - return fmt.Errorf("mint to the zero address") - } - - if amount <= 0 { - return fmt.Errorf("mint amount must be a positive integer") - } - - err := addBalance(ctx, operator, account, id, amount) - if err != nil { - return err - } - - return nil -} - -func addBalance(ctx contractapi.TransactionContextInterface, sender string, recipient string, id uint64, amount uint64) error { - // Convert id to string - idString := strconv.FormatUint(uint64(id), 10) - - balanceKey, err := ctx.GetStub().CreateCompositeKey(balancePrefix, []string{recipient, idString, sender}) - if err != nil { - return fmt.Errorf("failed to create the composite key for prefix %s: %v", balancePrefix, err) - } - - balanceBytes, err := ctx.GetStub().GetState(balanceKey) - if err != nil { - return fmt.Errorf("failed to read account %s from world state: %v", recipient, err) - } - - var balance uint64 = 0 - if balanceBytes != nil { - balance, _ = strconv.ParseUint(string(balanceBytes), 10, 64) - } - - balance, err = add(balance, amount) - if err != nil { - return err - } - - err = ctx.GetStub().PutState(balanceKey, []byte(strconv.FormatUint(uint64(balance), 10))) - if err != nil { - return err - } - - return nil -} - -func setBalance(ctx contractapi.TransactionContextInterface, sender string, recipient string, id uint64, amount uint64) error { - // Convert id to string - idString := strconv.FormatUint(uint64(id), 10) - - balanceKey, err := ctx.GetStub().CreateCompositeKey(balancePrefix, []string{recipient, idString, sender}) - if err != nil { - return fmt.Errorf("failed to create the composite key for prefix %s: %v", balancePrefix, err) - } - - err = ctx.GetStub().PutState(balanceKey, []byte(strconv.FormatUint(uint64(amount), 10))) - if err != nil { - return err - } - - return nil -} - -func removeBalance(ctx contractapi.TransactionContextInterface, sender string, ids []uint64, amounts []uint64) error { - // Calculate the total amount of each token to withdraw - necessaryFunds := make(map[uint64]uint64) // token id -> necessary amount - var err error - - for i := 0; i < len(amounts); i++ { - necessaryFunds[ids[i]], err = add(necessaryFunds[ids[i]], amounts[i]) - if err != nil { - return err - } - } - - // Copy the map keys and sort it. This is necessary because iterating maps in Go is not deterministic - necessaryFundsKeys := sortedKeys(necessaryFunds) - - // Check whether the sender has the necessary funds and withdraw them from the account - for _, tokenId := range necessaryFundsKeys { - neededAmount := necessaryFunds[tokenId] - idString := strconv.FormatUint(uint64(tokenId), 10) - - var partialBalance uint64 - var selfRecipientKeyNeedsToBeRemoved bool - var selfRecipientKey string - - balanceIterator, err := ctx.GetStub().GetStateByPartialCompositeKey(balancePrefix, []string{sender, idString}) - if err != nil { - return fmt.Errorf("failed to get state for prefix %v: %v", balancePrefix, err) - } - defer balanceIterator.Close() - - // Iterate over keys that store balances and add them to partialBalance until - // either the necessary amount is reached or the keys ended - for balanceIterator.HasNext() && partialBalance < neededAmount { - queryResponse, err := balanceIterator.Next() - if err != nil { - return fmt.Errorf("failed to get the next state for prefix %v: %v", balancePrefix, err) - } - - partBalAmount, _ := strconv.ParseUint(string(queryResponse.Value), 10, 64) - partialBalance, err = add(partialBalance, partBalAmount) - if err != nil { - return err - } - - _, compositeKeyParts, err := ctx.GetStub().SplitCompositeKey(queryResponse.Key) - if err != nil { - return err - } - - if compositeKeyParts[2] == sender { - selfRecipientKeyNeedsToBeRemoved = true - selfRecipientKey = queryResponse.Key - } else { - err = ctx.GetStub().DelState(queryResponse.Key) - if err != nil { - return fmt.Errorf("failed to delete the state of %v: %v", queryResponse.Key, err) - } - } - } - - if partialBalance < neededAmount { - return fmt.Errorf("sender has insufficient funds for token %v, needed funds: %v, available fund: %v", tokenId, neededAmount, partialBalance) - } else if partialBalance > neededAmount { - // Send the remainder back to the sender - remainder, err := sub(partialBalance, neededAmount) - if err != nil { - return err - } - - if selfRecipientKeyNeedsToBeRemoved { - // Set balance for the key that has the same address for sender and recipient - err = setBalance(ctx, sender, sender, tokenId, remainder) - if err != nil { - return err - } - } else { - err = addBalance(ctx, sender, sender, tokenId, remainder) - if err != nil { - return err - } - } - - } else { - // Delete self recipient key - err = ctx.GetStub().DelState(selfRecipientKey) - if err != nil { - return fmt.Errorf("failed to delete the state of %v: %v", selfRecipientKey, err) - } - } - } - - return nil -} - -func emitTransferSingle(ctx contractapi.TransactionContextInterface, transferSingleEvent TransferSingle) error { - transferSingleEventJSON, err := json.Marshal(transferSingleEvent) - if err != nil { - return fmt.Errorf("failed to obtain JSON encoding: %v", err) - } - - err = ctx.GetStub().SetEvent("TransferSingle", transferSingleEventJSON) - if err != nil { - return fmt.Errorf("failed to set event: %v", err) - } - - return nil -} - -func emitTransferBatch(ctx contractapi.TransactionContextInterface, transferBatchEvent TransferBatch) error { - transferBatchEventJSON, err := json.Marshal(transferBatchEvent) - if err != nil { - return fmt.Errorf("failed to obtain JSON encoding: %v", err) - } - err = ctx.GetStub().SetEvent("TransferBatch", transferBatchEventJSON) - if err != nil { - return fmt.Errorf("failed to set event: %v", err) - } - - return nil -} - -func emitTransferBatchMultiRecipient(ctx contractapi.TransactionContextInterface, transferBatchMultiRecipientEvent TransferBatchMultiRecipient) error { - transferBatchMultiRecipientEventJSON, err := json.Marshal(transferBatchMultiRecipientEvent) - if err != nil { - return fmt.Errorf("failed to obtain JSON encoding: %v", err) - } - err = ctx.GetStub().SetEvent("TransferBatchMultiRecipient", transferBatchMultiRecipientEventJSON) - if err != nil { - return fmt.Errorf("failed to set event: %v", err) - } - - return nil -} - -// balanceOfHelper returns the balance of the given account -func balanceOfHelper(ctx contractapi.TransactionContextInterface, account string, id uint64) (uint64, error) { - - if account == "0x0" { - return 0, fmt.Errorf("balance query for the zero address") - } - - // Convert id to string - idString := strconv.FormatUint(uint64(id), 10) - - var balance uint64 - - balanceIterator, err := ctx.GetStub().GetStateByPartialCompositeKey(balancePrefix, []string{account, idString}) - if err != nil { - return 0, fmt.Errorf("failed to get state for prefix %v: %v", balancePrefix, err) - } - defer balanceIterator.Close() - - for balanceIterator.HasNext() { - queryResponse, err := balanceIterator.Next() - if err != nil { - return 0, fmt.Errorf("failed to get the next state for prefix %v: %v", balancePrefix, err) - } - - balAmount, _ := strconv.ParseUint(string(queryResponse.Value), 10, 64) - balance, err = add(balance, balAmount) - if err != nil { - return 0, err - } - } - - return balance, nil -} - -// Returns the sorted slice ([]uint64) copied from the keys of map[uint64]uint64 -func sortedKeys(m map[uint64]uint64) []uint64 { - // Copy map keys to slice - keys := make([]uint64, len(m)) - i := 0 - for k := range m { - keys[i] = k - i++ - } - // Sort the slice - sort.Slice(keys, func(i, j int) bool { return keys[i] < keys[j] }) - return keys -} - -// Returns the sorted slice ([]ToID) copied from the keys of map[ToID]uint64 -func sortedKeysToID(m map[ToID]uint64) []ToID { - // Copy map keys to slice - keys := make([]ToID, len(m)) - i := 0 - for k := range m { - keys[i] = k - i++ - } - // Sort the slice first according to ID if equal then sort by recipient ("To" field) - sort.Slice(keys, func(i, j int) bool { - if keys[i].ID != keys[j].ID { - return keys[i].To < keys[j].To - } - return keys[i].ID < keys[j].ID - }) - return keys -} - -// Checks that contract options have been already initialized -func checkInitialized(ctx contractapi.TransactionContextInterface) (bool, error) { - tokenName, err := ctx.GetStub().GetState(nameKey) - if err != nil { - return false, fmt.Errorf("failed to get token name: %v", err) - } - if tokenName == nil { - return false, nil - } - return true, nil -} - -// add two number checking for overflow -func add(b uint64, q uint64) (uint64, error) { - - // Check overflow - var sum uint64 - sum = q + b - - if sum < q { - return 0, fmt.Errorf("Math: addition overflow occurred %d + %d", b, q) - } - - return sum, nil -} - -// sub two number checking for overflow -func sub(b uint64, q uint64) (uint64, error) { - - // Check overflow - var diff uint64 - diff = b - q - - if diff > b { - return 0, fmt.Errorf("Math: subtraction overflow occurred %d - %d", b, q) - } - - return diff, nil -} diff --git a/token-erc-1155/chaincode-go/erc1155.go b/token-erc-1155/chaincode-go/erc1155.go deleted file mode 100644 index 3321fa0c..00000000 --- a/token-erc-1155/chaincode-go/erc1155.go +++ /dev/null @@ -1,27 +0,0 @@ -/* - 2021 Baran Kılıç - - SPDX-License-Identifier: Apache-2.0 -*/ - -package main - -import ( - "erc1155/chaincode" - - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" -) - -func main() { - smartContract := new(chaincode.SmartContract) - - cc, err := contractapi.NewChaincode(smartContract) - - if err != nil { - panic(err.Error()) - } - - if err := cc.Start(); err != nil { - panic(err.Error()) - } -} diff --git a/token-erc-1155/chaincode-go/go.mod b/token-erc-1155/chaincode-go/go.mod deleted file mode 100644 index 50c29f67..00000000 --- a/token-erc-1155/chaincode-go/go.mod +++ /dev/null @@ -1,32 +0,0 @@ -module erc1155 - -go 1.21 - -require github.com/hyperledger/fabric-contract-api-go/v2 v2.0.0 - -require ( - github.com/go-openapi/jsonpointer v0.21.0 // indirect - github.com/go-openapi/jsonreference v0.21.0 // indirect - github.com/go-openapi/spec v0.21.0 // indirect - github.com/go-openapi/swag v0.23.0 // indirect - github.com/gobuffalo/envy v1.10.2 // indirect - github.com/gobuffalo/packd v1.0.2 // indirect - github.com/gobuffalo/packr v1.30.1 // indirect - github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0-20240618210511-f7903324a8af // indirect - github.com/hyperledger/fabric-protos-go-apiv2 v0.3.3 // indirect - github.com/joho/godotenv v1.5.1 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/mailru/easyjson v0.7.7 // indirect - github.com/rogpeppe/go-internal v1.12.0 // indirect - github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect - github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect - github.com/xeipuuv/gojsonschema v1.2.0 // indirect - golang.org/x/mod v0.17.0 // indirect - golang.org/x/net v0.24.0 // indirect - golang.org/x/sys v0.19.0 // indirect - golang.org/x/text v0.14.0 // indirect - google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect - google.golang.org/grpc v1.64.0 // indirect - google.golang.org/protobuf v1.34.2 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) diff --git a/token-erc-1155/chaincode-go/go.sum b/token-erc-1155/chaincode-go/go.sum deleted file mode 100644 index 7c5e414c..00000000 --- a/token-erc-1155/chaincode-go/go.sum +++ /dev/null @@ -1,132 +0,0 @@ -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= -github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= -github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= -github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= -github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= -github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= -github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= -github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= -github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= -github.com/gobuffalo/envy v1.10.2 h1:EIi03p9c3yeuRCFPOKcSfajzkLb3hrRjEpHGI8I2Wo4= -github.com/gobuffalo/envy v1.10.2/go.mod h1:qGAGwdvDsaEtPhfBzb3o0SfDea8ByGn9j8bKmVft9z8= -github.com/gobuffalo/logger v1.0.0/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs= -github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q= -github.com/gobuffalo/packd v1.0.2 h1:Yg523YqnOxGIWCp69W12yYBKsoChwI7mtu6ceM9Bwfw= -github.com/gobuffalo/packd v1.0.2/go.mod h1:sUc61tDqGMXON80zpKGp92lDb86Km28jfvX7IAyxFT8= -github.com/gobuffalo/packr v1.30.1 h1:hu1fuVR3fXEZR7rXNW3h8rqSML8EVAf6KNm0NKO/wKg= -github.com/gobuffalo/packr v1.30.1/go.mod h1:ljMyFO2EcrnzsHsN99cvbq055Y9OhRrIaviy289eRuk= -github.com/gobuffalo/packr/v2 v2.5.1/go.mod h1:8f9c96ITobJlPzI44jj+4tHnEKNt0xXWSVlXRN9X1Iw= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0-20240618210511-f7903324a8af h1:WT4NjX7Uk03GSeH++jF3a0wp4FhybTM86zDPCETvmSk= -github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0-20240618210511-f7903324a8af/go.mod h1:f/ER25FaBepxJugwpLhbD2hLAoZaZEVqkBjOcHjw72Y= -github.com/hyperledger/fabric-contract-api-go/v2 v2.0.0 h1:IDiCGVOBlRd6zpL0Y+f6V7IpBqa4/Z5JAK9SF7a5ea8= -github.com/hyperledger/fabric-contract-api-go/v2 v2.0.0/go.mod h1:pdqhe7ALf4lmXgQdprCyNWYdnCPxgj02Vhf8JF5w8po= -github.com/hyperledger/fabric-protos-go-apiv2 v0.3.3 h1:Xpd6fzG/KjAOHJsq7EQXY2l+qi/y8muxBaY7R6QWABk= -github.com/hyperledger/fabric-protos-go-apiv2 v0.3.3/go.mod h1:2pq0ui6ZWA0cC8J+eCErgnMDCS1kPOEYVY+06ZAK0qE= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= -github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= -github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= -github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= -golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= -google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/token-erc-20/README.md b/token-erc-20/README.md deleted file mode 100644 index 0bc5b0c3..00000000 --- a/token-erc-20/README.md +++ /dev/null @@ -1,466 +0,0 @@ -# ERC-20 token scenario - -The ERC-20 token smart contract demonstrates how to create and transfer fungible tokens using an account-based model. In an ERC-20 account-based model, there is an account for each participant that holds a balance of tokens. -A mint transaction creates tokens in an account, while a transfer transaction debits the caller's account and credits another account. - -In this sample it is assumed that only one organization (played by Org1) is in a central banker role and can mint new tokens into their account, while any organization can transfer tokens from their account to a recipient's account. -Accounts could be defined at the organization level or client identity level. In this sample accounts are defined at the client identity level, where every authorized client with an enrollment certificate from their organization implicitly has an account ID that matches their client ID. -The client ID is simply a base64-encoded concatenation of the issuer and subject from the client identity's enrollment certificate. The client ID can therefore be considered the account ID that is used as the payment address of a recipient. - -In this tutorial, you will mint and transfer tokens as follows: - -- A member of Org1 uses the `Mint` function to create new tokens into their account. The `Mint` smart contract function reads the certificate information of the client identity that submitted the transaction using the `GetClientIdentity.GetID()` API and credits the account associated with the client ID with the requested number of tokens. -- The same minter client will then use the `Transfer` function to transfer the requested number of tokens to the recipient's account. It is assumed that the recipient has provided their account ID to the transfer caller out of band. The recipient can then transfer tokens to other registered users in the same fashion. - -## Bring up the test network - -You can run the ERC-20 token transfer scenario using the Fabric test network. Open a command terminal and navigate to the test network directory in your local clone of the `fabric-samples`. We will operate from the `test-network` directory for the remainder of the tutorial. -``` -cd fabric-samples/test-network -``` - -Run the following command to start the test network: -``` -./network.sh up createChannel -ca -``` - -The test network is deployed with two peer organizations. The `createChannel` flag deploys the network with a single channel named `mychannel` with Org1 and Org2 as channel members. -The -ca flag is used to deploy the network using certificate authorities. This allows you to use each organization's CA to register and enroll new users for this tutorial. - -## Deploy the smart contract to the channel - -You can use the test network script to deploy the ERC-20 token contract to the channel that was just created. Deploy the smart contract to `mychannel` using the following command: - -**For a Go Contract:** -``` -./network.sh deployCC -ccn token_erc20 -ccp ../token-erc-20/chaincode-go/ -ccl go -``` - -**For a Java Contract:** -``` -./network.sh deployCC -ccn token_erc20 -ccp ../token-erc-20/chaincode-java/ -ccl java -``` - -**For a JavaScript Contract:** -``` -./network.sh deployCC -ccn token_erc20 -ccp ../token-erc-20/chaincode-javascript/ -ccl javascript -``` - -The above commands deploys the chaincode with short name `token_erc20`. The smart contract will use the default endorsement policy of majority of channel members. -Since the channel has two members, this implies that we'll need to get peer endorsements from 2 out of the 2 channel members. - -Now you are ready to call the deployed smart contract via peer CLI calls. But let's first create the client identities for our scenario. - -## Register identities - -The smart contract supports accounts owned by individual client identities from organizations that are members of the channel. In our scenario, the minter of the tokens will be a member of Org1, while the recipient will belong to Org2. To highlight the connection between the `GetClientIdentity().GetID()` API and the information within a user's certificate, we will register two new identities using the Org1 and Org2 Certificate Authorities (CA's), and then use the CA's to generate each identity's certificate and private key. - -First, we need to set the following environment variables to use the Fabric CA client (and subsequent commands). -``` -export PATH=${PWD}/../bin:${PWD}:$PATH -export FABRIC_CFG_PATH=$PWD/../config/ -``` - -The terminal we have been using will represent Org1. We will use the Org1 CA to create the minter identity. Set the Fabric CA client home to the MSP of the Org1 CA admin (this identity was generated by the test network script): -``` -export FABRIC_CA_CLIENT_HOME=${PWD}/organizations/peerOrganizations/org1.example.com/ -``` - -You can register a new minter client identity using the `fabric-ca-client` tool: -``` -fabric-ca-client register --caname ca-org1 --id.name minter --id.secret minterpw --id.type client --tls.certfiles "${PWD}/organizations/fabric-ca/org1/tls-cert.pem" -``` - -You can now generate the identity certificates and MSP folder by providing the minter's enroll name and secret to the enroll command: -``` -fabric-ca-client enroll -u https://minter:minterpw@localhost:7054 --caname ca-org1 -M "${PWD}/organizations/peerOrganizations/org1.example.com/users/minter@org1.example.com/msp" --tls.certfiles "${PWD}/organizations/fabric-ca/org1/tls-cert.pem" -``` - -Run the command below to copy the Node OU configuration file into the minter identity MSP folder. -``` -cp "${PWD}/organizations/peerOrganizations/org1.example.com/msp/config.yaml" "${PWD}/organizations/peerOrganizations/org1.example.com/users/minter@org1.example.com/msp/config.yaml" -``` - -Open a new terminal to represent Org2 and navigate to fabric-samples/test-network. We'll use the Org2 CA to create the Org2 recipient identity. Set the Fabric CA client home to the MSP of the Org2 CA admin: -``` -cd fabric-samples/test-network -export PATH=${PWD}/../bin:${PWD}:$PATH -export FABRIC_CA_CLIENT_HOME=${PWD}/organizations/peerOrganizations/org2.example.com/ -``` - -You can register a recipient client identity using the `fabric-ca-client` tool: -``` -fabric-ca-client register --caname ca-org2 --id.name recipient --id.secret recipientpw --id.type client --tls.certfiles "${PWD}/organizations/fabric-ca/org2/tls-cert.pem" -``` - -We can now enroll to generate the recipient's identity certificates and MSP folder: -``` -fabric-ca-client enroll -u https://recipient:recipientpw@localhost:8054 --caname ca-org2 -M "${PWD}/organizations/peerOrganizations/org2.example.com/users/recipient@org2.example.com/msp" --tls.certfiles "${PWD}/organizations/fabric-ca/org2/tls-cert.pem" -``` - -Run the command below to copy the Node OU configuration file into the recipient identity MSP folder. -``` -cp "${PWD}/organizations/peerOrganizations/org2.example.com/msp/config.yaml" "${PWD}/organizations/peerOrganizations/org2.example.com/users/recipient@org2.example.com/msp/config.yaml" -``` - -## Initialize the contract -Once we created the identity of the minter we can now initialize the contract. -Note that we need to call the initialize function before being able to use any functions of the contract. Initialize() can be called only once. - -Shift back to the Org1 terminal, we'll set the following environment variables to operate the `peer` CLI as the minter identity from Org1. -``` -export CORE_PEER_TLS_ENABLED=true -export CORE_PEER_LOCALMSPID=Org1MSP -export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/minter@org1.example.com/msp -export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt -export CORE_PEER_ADDRESS=localhost:7051 -export TARGET_TLS_OPTIONS=(-o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" --peerAddresses localhost:7051 --tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt" --peerAddresses localhost:9051 --tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt") -``` - -The last environment variable above will be utilized within the CLI invoke commands to set the target peers for endorsement, and the target ordering service endpoint and TLS options. - -We can then invoke the smart contract to initilize it -``` -peer chaincode invoke "${TARGET_TLS_OPTIONS[@]}" -C mychannel -n token_erc20 -c '{"function":"Initialize","Args":["some name", "some symbol", "2"]}' -``` - -## Mint some tokens - -Now that we have initialized the contract and created the identity of the minter, we can invoke the smart contract to mint some tokens. - -We can then invoke the smart contract to mint 5000 tokens: -``` -peer chaincode invoke "${TARGET_TLS_OPTIONS[@]}" -C mychannel -n token_erc20 -c '{"function":"Mint","Args":["5000"]}' -``` - -The mint function validated that the client is a member of the minter organization, and then credited the minter client's account with 5000 tokens. We can check the minter client's account balance by calling the `ClientAccountBalance` function. -``` -peer chaincode query -C mychannel -n token_erc20 -c '{"function":"ClientAccountBalance","Args":[]}' -``` - -The function queries the balance of the account associated with the minter client ID and returns: -``` -5000 -``` - -## Transfer tokens - -The minter intends to transfer 100 tokens to the Org2 recipient, but first the Org2 recipient needs to provide their own account ID as the payment address. -A client can derive their account ID from their own public certificate, but to be sure the account ID is accurate, the contract has a `ClientAccountID` utility function that simply looks at the callers certificate and returns the calling client's ID, which will be used as the account ID. -Let's prepare the Org2 terminal by setting the environment variables for the Org2 recipient user. -``` -export FABRIC_CFG_PATH=$PWD/../config/ -export CORE_PEER_TLS_ENABLED=true -export CORE_PEER_LOCALMSPID=Org2MSP -export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/recipient@org2.example.com/msp -export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -export CORE_PEER_ADDRESS=localhost:9051 -``` - -Using the Org2 terminal, the Org2 recipient user can retrieve their own account ID: -``` -peer chaincode query -C mychannel -n token_erc20 -c '{"function":"ClientAccountID","Args":[]}' -``` - -**For a Go Contract:** - -The function returns of recipient's account ID: -``` -eDUwOTo6Q049cmVjaXBpZW50LE9VPWNsaWVudCxPPUh5cGVybGVkZ2VyLFNUPU5vcnRoIENhcm9saW5hLEM9VVM6OkNOPWNhLm9yZzIuZXhhbXBsZS5jb20sTz1vcmcyLmV4YW1wbGUuY29tLEw9SHVyc2xleSxTVD1IYW1wc2hpcmUsQz1VSw== -``` - -Let's base64 decode the account ID to make sure it represents the Org2 recipient user: -``` -echo eDUwOTo6Q049cmVjaXBpZW50LE9VPWNsaWVudCxPPUh5cGVybGVkZ2VyLFNUPU5vcnRoIENhcm9saW5hLEM9VVM6OkNOPWNhLm9yZzIuZXhhbXBsZS5jb20sTz1vcmcyLmV4YW1wbGUuY29tLEw9SHVyc2xleSxTVD1IYW1wc2hpcmUsQz1VSw== | base64 --decode -``` - -The result shows that the subject and issuer is indeed the recipient user from Org2: -``` -x509::CN=recipient,OU=client,O=Hyperledger,ST=North Carolina,C=US::CN=ca.org2.example.com,O=org2.example.com,L=Hursley,ST=Hampshire,C=UK -``` - -**For a Java Contract** - -The function returns of recipient's client ID. -``` -x509::CN=recipient, OU=client, O=Hyperledger, ST=North Carolina, C=US::CN=ca.org2.example.com, O=org2.example.com, L=Hursley, ST=Hampshire, C=UK -``` - -**For a JavaScript Contract:** - -The function returns of recipient's client ID. -The result shows that the subject and issuer is indeed the recipient user from Org2: -``` -x509::/C=US/ST=North Carolina/O=Hyperledger/OU=client/CN=recipient::/C=UK/ST=Hampshire/L=Hursley/O=org2.example.com/CN=ca.org2.example.com -``` - -After the Org2 recipient provides their account ID to the minter, the minter can initiate a transfer from their account to the recipient's account. -Back in the Org1 terminal, request the transfer of 100 tokens to the recipient account: - -**For a Go Contract:** -``` -export RECIPIENT="eDUwOTo6Q049cmVjaXBpZW50LE9VPWNsaWVudCxPPUh5cGVybGVkZ2VyLFNUPU5vcnRoIENhcm9saW5hLEM9VVM6OkNOPWNhLm9yZzIuZXhhbXBsZS5jb20sTz1vcmcyLmV4YW1wbGUuY29tLEw9SHVyc2xleSxTVD1IYW1wc2hpcmUsQz1VSw==" -peer chaincode invoke "${TARGET_TLS_OPTIONS[@]}" -C mychannel -n token_erc20 -c '{"function":"Transfer","Args":[ "'"$RECIPIENT"'","100"]}' -``` -***For a Java Contract** -``` -export RECIPIENT="x509::CN=recipient, OU=client, O=Hyperledger, ST=North Carolina, C=US::CN=ca.org2.example.com, O=org2.example.com, L=Hursley, ST=Hampshire, C=UK" -peer chaincode invoke "${TARGET_TLS_OPTIONS[@]}" -C mychannel -n token_erc20 -c '{"function":"Transfer","Args":[ "'"$RECIPIENT"'","100"]}' -``` - -**For a JavaScript Contract:** -``` -export RECIPIENT="x509::/C=US/ST=North Carolina/O=Hyperledger/OU=client/CN=recipient::/C=UK/ST=Hampshire/L=Hursley/O=org2.example.com/CN=ca.org2.example.com" -peer chaincode invoke "${TARGET_TLS_OPTIONS[@]}" -C mychannel -n token_erc20 -c '{"function":"Transfer","Args":[ "'"$RECIPIENT"'","100"]}' -``` - -The `Transfer` function validates that the account associated with the calling client ID has sufficient funds for the transfer. -It will then debit the caller's account and credit the recipient's account. Note that the sample contract will automatically create an account with zero balance for the recipient, if one does not yet exist. - -While still in the Org1 terminal, let's request the minter's account balance again: -``` -peer chaincode query -C mychannel -n token_erc20 -c '{"function":"ClientAccountBalance","Args":[]}' -``` - -The function queries the balance of the account associated with the minter client ID and returns: -``` -4900 -``` - -And then using the Org2 terminal, let's request the recipient's balance: -``` -peer chaincode query -C mychannel -n token_erc20 -c '{"function":"ClientAccountBalance","Args":[]}' -``` - -The function queries the balance of the account associated with the recipient client ID and returns: -``` -100 -``` - -Congratulations, you've transferred 100 tokens! The Org2 recipient can now transfer tokens to other registered users in the same manner. - -## 3rd party transfers (TransferFrom) - -This sample has another ERC-20 transfer method called `TransferFrom`, which allows an approved 3rd party spender to transfer fungible tokens on behalf of the account owner. This scenario demonstrates how to approve the spender and transfer fungible tokens. - -In this scenario, you will approve the spender and transfer tokens as follows: - -- A minter has already created tokens according to the scenario above. -- The same minter client uses the `Approve` function to set the allowance of tokens a spender client can transfer on behalf of the minter. It is assumed that the spender has provided their client ID to the `Approve` caller out of band. -- The spender client will then use the `TransferFrom` function to transfer the requested number of tokens to the recipient's account on behalf of the minter. It is assumed that the recipient has provided their client ID to the `TransferFrom` caller out of band. - -## Register identity for 3rd party spender - -You have already brought up the network and deployed the smart contract to the channel. We will use the same network and smart contract. - -We will use the Org1 CA to create the spender identity. -Back in the Org1 terminal, you can register a new spender client identity using the `fabric-ca-client` tool: -``` -fabric-ca-client register --caname ca-org1 --id.name spender --id.secret spenderpw --id.type client --tls.certfiles "${PWD}/organizations/fabric-ca/org1/tls-cert.pem" -``` - -You can now generate the identity certificates and MSP folder by providing the spender's enroll name and secret to the enroll command: -``` -fabric-ca-client enroll -u https://spender:spenderpw@localhost:7054 --caname ca-org1 -M "${PWD}/organizations/peerOrganizations/org1.example.com/users/spender@org1.example.com/msp" --tls.certfiles "${PWD}/organizations/fabric-ca/org1/tls-cert.pem" -``` - -Run the command below to copy the Node OU configuration file into the spender identity MSP folder. -``` -cp "${PWD}/organizations/peerOrganizations/org1.example.com/msp/config.yaml" "${PWD}/organizations/peerOrganizations/org1.example.com/users/spender@org1.example.com/msp/config.yaml" -``` - -## Approve a spender - -The minter intends to approve 500 tokens to be transferred by the spender, but first the spender needs to provide their own client ID as the payment address. - -Open a 3rd terminal to represent the spender in Org1 and navigate to fabric-samples/test-network. Set the the environment variables for the Org1 spender user. - -``` -export PATH=${PWD}/../bin:${PWD}:$PATH -export FABRIC_CFG_PATH=$PWD/../config/ -export CORE_PEER_TLS_ENABLED=true -export CORE_PEER_LOCALMSPID=Org1MSP -export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/spender@org1.example.com/msp -export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt -export CORE_PEER_ADDRESS=localhost:7051 -export TARGET_TLS_OPTIONS=(-o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" --peerAddresses localhost:7051 --tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt" --peerAddresses localhost:9051 --tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt") -``` - -Now the Org1 spender can retrieve their own client ID: -``` -peer chaincode query -C mychannel -n token_erc20 -c '{"function":"ClientAccountID","Args":[]}' -``` - -**For a Go Contract:** - -The function returns of spender's account ID: -``` -eDUwOTo6Q049c3BlbmRlcixPVT1jbGllbnQsTz1IeXBlcmxlZGdlcixTVD1Ob3J0aCBDYXJvbGluYSxDPVVTOjpDTj1jYS5vcmcxLmV4YW1wbGUuY29tLE89b3JnMS5leGFtcGxlLmNvbSxMPUR1cmhhbSxTVD1Ob3J0aCBDYXJvbGluYSxDPVVT -``` - -**For a Java Contract** - -The function returns of spenders's client ID. -``` -x509::CN=spender, OU=client, O=Hyperledger, ST=North Carolina, C=US::CN=ca.org1.example.com, O=org1.example.com, L=Durham, ST=North Carolina, C=US -``` - -**For a JavaScript Contract:** - -The function returns of spender's client ID. -The result shows that the subject and issuer is indeed the recipient user from Org2: -``` -x509::/C=US/ST=North Carolina/O=Hyperledger/OU=client/CN=spender::/C=US/ST=North Carolina/L=Durham/O=org1.example.com/CN=ca.org1.example.com -``` - -After the Org1 spender provides their client ID to the minter, the minter can approve a spender. -Back in the Org1 minter terminal, request the approval of 500 tokens to be withdrawn by the spender. - -**For a Go Contract:** - -``` -export SPENDER="eDUwOTo6Q049c3BlbmRlcixPVT1jbGllbnQsTz1IeXBlcmxlZGdlcixTVD1Ob3J0aCBDYXJvbGluYSxDPVVTOjpDTj1jYS5vcmcxLmV4YW1wbGUuY29tLE89b3JnMS5leGFtcGxlLmNvbSxMPUR1cmhhbSxTVD1Ob3J0aCBDYXJvbGluYSxDPVVT" -peer chaincode invoke "${TARGET_TLS_OPTIONS[@]}" -C mychannel -n token_erc20 -c '{"function":"Approve","Args":[ "'"$SPENDER"'","500"]}' -``` - -**For a Java Contract:** - -``` -export SPENDER="x509::CN=spender, OU=client, O=Hyperledger, ST=North Carolina, C=US::CN=ca.org1.example.com, O=org1.example.com, L=Durham, ST=North Carolina, C=US" -peer chaincode invoke "${TARGET_TLS_OPTIONS[@]}" -C mychannel -n token_erc20 -c '{"function":"Approve","Args":["'"$SPENDER"'", "500"]}' -``` - -**For a JavaScript Contract:** - -``` -export SPENDER="x509::/C=US/ST=North Carolina/O=Hyperledger/OU=client/CN=spender::/C=US/ST=North Carolina/L=Durham/O=org1.example.com/CN=ca.org1.example.com" -peer chaincode invoke "${TARGET_TLS_OPTIONS[@]}" -C mychannel -n token_erc20 -c '{"function":"Approve","Args":["'"$SPENDER"'", "500"]}' -``` - -The approve function specified that the spender client can transfer 500 tokens on behalf of the minter. We can check the spender client's allowance from the minter by calling the `allowance` function. - -Let's request the spender's allowance from the Org1 minter terminal. - -**For a Go Contract:** - -``` -export MINTER="eDUwOTo6Q049bWludGVyLE9VPWNsaWVudCxPPUh5cGVybGVkZ2VyLFNUPU5vcnRoIENhcm9saW5hLEM9VVM6OkNOPWNhLm9yZzEuZXhhbXBsZS5jb20sTz1vcmcxLmV4YW1wbGUuY29tLEw9RHVyaGFtLFNUPU5vcnRoIENhcm9saW5hLEM9VVM=" -peer chaincode query -C mychannel -n token_erc20 -c '{"function":"Allowance","Args":["'"$MINTER"'", "'"$SPENDER"'"]}' -``` - -**For a Java Contract:** - -``` -export MINTER="x509::CN=minter, OU=client, O=Hyperledger, ST=North Carolina, C=US::CN=ca.org1.example.com, O=org1.example.com, L=Durham, ST=North Carolina, C=US" -peer chaincode query -C mychannel -n token_erc20 -c '{"function":"Allowance","Args":["'"$MINTER"'", "'"$SPENDER"'"]}' -``` - -**For a JavaScript Contract:** - -``` -export MINTER="x509::/C=US/ST=North Carolina/O=Hyperledger/OU=client/CN=minter::/C=US/ST=North Carolina/L=Durham/O=org1.example.com/CN=ca.org1.example.com" -peer chaincode query -C mychannel -n token_erc20 -c '{"function":"Allowance","Args":["'"$MINTER"'", "'"$SPENDER"'"]}' -``` - -The function queries the allowance associated with the spender client ID and returns: -``` -500 -``` - -## TransferFrom tokens - -The spender intends to transfer 100 tokens to the Org2 recipient on behalf of the minter. The spender has already got the minter client Id and the recipient client ID. - -Back in the 3rd terminal, request the transfer of 100 tokens to the recipient account. - -**For a Go Contract:** - -``` -export MINTER="eDUwOTo6Q049bWludGVyLE9VPWNsaWVudCxPPUh5cGVybGVkZ2VyLFNUPU5vcnRoIENhcm9saW5hLEM9VVM6OkNOPWNhLm9yZzEuZXhhbXBsZS5jb20sTz1vcmcxLmV4YW1wbGUuY29tLEw9RHVyaGFtLFNUPU5vcnRoIENhcm9saW5hLEM9VVM=" -export RECIPIENT="eDUwOTo6Q049cmVjaXBpZW50LE9VPWNsaWVudCxPPUh5cGVybGVkZ2VyLFNUPU5vcnRoIENhcm9saW5hLEM9VVM6OkNOPWNhLm9yZzIuZXhhbXBsZS5jb20sTz1vcmcyLmV4YW1wbGUuY29tLEw9SHVyc2xleSxTVD1IYW1wc2hpcmUsQz1VSw==" -peer chaincode invoke "${TARGET_TLS_OPTIONS[@]}" -C mychannel -n token_erc20 -c '{"function":"TransferFrom","Args":[ "'"$MINTER"'", "'"$RECIPIENT"'", "100"]}' -``` - -**For a Java Contract:** - -``` -export MINTER="x509::CN=minter, OU=client, O=Hyperledger, ST=North Carolina, C=US::CN=ca.org1.example.com, O=org1.example.com, L=Durham, ST=North Carolina, C=US" -export RECIPIENT="x509::CN=recipient, OU=client, O=Hyperledger, ST=North Carolina, C=US::CN=ca.org2.example.com, O=org2.example.com, L=Hursley, ST=Hampshire, C=UK" -peer chaincode invoke "${TARGET_TLS_OPTIONS[@]}" -C mychannel -n token_erc20 -c '{"function":"TransferFrom","Args":[ "'"$MINTER"'", "'"$RECIPIENT"'", "100"]}' -``` - -**For a JavaScript Contract:** - -``` -export MINTER="x509::/C=US/ST=North Carolina/O=Hyperledger/OU=client/CN=minter::/C=US/ST=North Carolina/L=Durham/O=org1.example.com/CN=ca.org1.example.com" -export RECIPIENT="x509::/C=US/ST=North Carolina/O=Hyperledger/OU=client/CN=recipient::/C=UK/ST=Hampshire/L=Hursley/O=org2.example.com/CN=ca.org2.example.com" -peer chaincode invoke "${TARGET_TLS_OPTIONS[@]}" -C mychannel -n token_erc20 -c '{"function":"TransferFrom","Args":[ "'"$MINTER"'", "'"$RECIPIENT"'", "100"]}' -``` - -The `TransferFrom` function has three args: sender, recipient, amount. The function validates that the account associated with the sender has sufficient funds for the transfer. The function also validates if the allowance associated with the calling client ID exceeds funds to be transferred. -It will then debit the sender's account and credit the recipient's account. It will also decrease the spender's allowance approved by the minter. Note that the sample contract will automatically create an account with zero balance for the recipient, if one does not yet exist. - -While still in the 3rd terminal for the spender, let's request the minter's account balance again: -``` -peer chaincode query -C mychannel -n token_erc20 -c '{"function":"BalanceOf","Args":["'"$MINTER"'"]}' -``` - -The function queries the balance of the account associated with the minter client ID and returns: -``` -4800 -``` - -While still in the 3rd terminal for the spender, let's request the spender's allowance from the minter again. - -**For a Go Contract:** - -``` -export SPENDER="eDUwOTo6Q049c3BlbmRlcixPVT1jbGllbnQsTz1IeXBlcmxlZGdlcixTVD1Ob3J0aCBDYXJvbGluYSxDPVVTOjpDTj1jYS5vcmcxLmV4YW1wbGUuY29tLE89b3JnMS5leGFtcGxlLmNvbSxMPUR1cmhhbSxTVD1Ob3J0aCBDYXJvbGluYSxDPVVT" -peer chaincode query -C mychannel -n token_erc20 -c '{"function":"Allowance","Args":["'"$MINTER"'", "'"$SPENDER"'"]}' -``` - -**For a Java Contract:** - -``` -export SPENDER="x509::CN=spender, OU=client, O=Hyperledger, ST=North Carolina, C=US::CN=ca.org1.example.com, O=org1.example.com, L=Durham, ST=North Carolina, C=US" -peer chaincode query -C mychannel -n token_erc20 -c '{"function":"Allowance","Args":["'"$MINTER"'", "'"$SPENDER"'"]}' -``` - -**For a JavaScript Contract:** - -``` -export SPENDER="x509::/C=US/ST=North Carolina/O=Hyperledger/OU=client/CN=spender::/C=US/ST=North Carolina/L=Durham/O=org1.example.com/CN=ca.org1.example.com" -peer chaincode query -C mychannel -n token_erc20 -c '{"function":"Allowance","Args":["'"$MINTER"'", "'"$SPENDER"'"]}' -``` - -The function queries the allowance associated with the spender client ID and returns: -``` -400 -``` - -And then using the Org2 terminal, let's request the recipient's balance: -``` -peer chaincode query -C mychannel -n token_erc20 -c '{"function":"ClientAccountBalance","Args":[]}' -``` - -The function queries the balance of the account associated with the recipient client ID and returns: -``` -200 -``` - -Congratulations, you've transferred 100 tokens! The Org2 recipient can now transfer tokens to other registered users in the same manner. - -## Clean up - -When you are finished, you can bring down the test network. The command will remove all the nodes of the test network, and delete any ledger data that you created: -``` -./network.sh down -``` - -## Contract extension ideas - -You can extend the basic ERC-20 account-based token sample to meet other requirements. For example: - -* Rather than using the default 'majority' endorsement policy, you could set the endorsement policy to a subset of organizations that represent trust anchors for the contract execution. -* You could also require that accounts get setup before use, and apply state-based endorsement for each account key that has been created. For example on an Org1 account, set state-based endorsement policy to be Org1 and the central banker (or some other trust anchor). And on an Org2 account, set state-based endorsement policy to be Org2 and the central banker (or some other trust anchor). Then to transfer tokens from an Org1 account to an Org2 account, you would require endorsements from Org1, Org2, and the central banker (or some other trust anchor). -* You could utilize anonymous addresses for accounts based on private-public key pairs, instead of accounts keyed by the client ID. In order to spend the tokens, the client would have to sign the transfer input as proof that they own the address private key, which the contract would then validate, similar to the Ethereum model in the permissionless blockchain space. However, in a permissioned blockchain such as Fabric, only registered clients are authorized to participate. Furthermore, if you don't want to leak the registered client identity associated with each account, the clients could be registered using an Identity Mixer MSP, so that the client itself is also anonymous in each of the token transactions. diff --git a/token-erc-20/chaincode-go/chaincode/token_contract.go b/token-erc-20/chaincode-go/chaincode/token_contract.go deleted file mode 100644 index 388da934..00000000 --- a/token-erc-20/chaincode-go/chaincode/token_contract.go +++ /dev/null @@ -1,733 +0,0 @@ -package chaincode - -import ( - "encoding/json" - "errors" - "fmt" - "log" - "strconv" - - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" -) - -// Define key names for options -const nameKey = "name" -const symbolKey = "symbol" -const decimalsKey = "decimals" -const totalSupplyKey = "totalSupply" - -// Define objectType names for prefix -const allowancePrefix = "allowance" - -// Define key names for options - -// SmartContract provides functions for transferring tokens between accounts -type SmartContract struct { - contractapi.Contract -} - -// event provides an organized struct for emitting events -type event struct { - From string `json:"from"` - To string `json:"to"` - Value int `json:"value"` -} - -// Mint creates new tokens and adds them to minter's account balance -// This function triggers a Transfer event -func (s *SmartContract) Mint(ctx contractapi.TransactionContextInterface, amount int) error { - - // Check if contract has been intilized first - initialized, err := checkInitialized(ctx) - if err != nil { - return fmt.Errorf("failed to check if contract is already initialized: %v", err) - } - if !initialized { - return fmt.Errorf("Contract options need to be set before calling any function, call Initialize() to initialize contract") - } - - // Check minter authorization - this sample assumes Org1 is the central banker with privilege to mint new tokens - clientMSPID, err := ctx.GetClientIdentity().GetMSPID() - if err != nil { - return fmt.Errorf("failed to get MSPID: %v", err) - } - if clientMSPID != "Org1MSP" { - return fmt.Errorf("client is not authorized to mint new tokens") - } - - // Get ID of submitting client identity - minter, err := ctx.GetClientIdentity().GetID() - if err != nil { - return fmt.Errorf("failed to get client id: %v", err) - } - - if amount <= 0 { - return fmt.Errorf("mint amount must be a positive integer") - } - - currentBalanceBytes, err := ctx.GetStub().GetState(minter) - if err != nil { - return fmt.Errorf("failed to read minter account %s from world state: %v", minter, err) - } - - var currentBalance int - - // If minter current balance doesn't yet exist, we'll create it with a current balance of 0 - if currentBalanceBytes == nil { - currentBalance = 0 - } else { - currentBalance, _ = strconv.Atoi(string(currentBalanceBytes)) // Error handling not needed since Itoa() was used when setting the account balance, guaranteeing it was an integer. - } - - updatedBalance, err := add(currentBalance, amount) - if err != nil { - return err - } - - err = ctx.GetStub().PutState(minter, []byte(strconv.Itoa(updatedBalance))) - if err != nil { - return err - } - - // Update the totalSupply - totalSupplyBytes, err := ctx.GetStub().GetState(totalSupplyKey) - if err != nil { - return fmt.Errorf("failed to retrieve total token supply: %v", err) - } - - var totalSupply int - - // If no tokens have been minted, initialize the totalSupply - if totalSupplyBytes == nil { - totalSupply = 0 - } else { - totalSupply, _ = strconv.Atoi(string(totalSupplyBytes)) // Error handling not needed since Itoa() was used when setting the totalSupply, guaranteeing it was an integer. - } - - // Add the mint amount to the total supply and update the state - totalSupply, err = add(totalSupply, amount) - if err != nil { - return err - } - - err = ctx.GetStub().PutState(totalSupplyKey, []byte(strconv.Itoa(totalSupply))) - if err != nil { - return err - } - - // Emit the Transfer event - transferEvent := event{"0x0", minter, amount} - transferEventJSON, err := json.Marshal(transferEvent) - if err != nil { - return fmt.Errorf("failed to obtain JSON encoding: %v", err) - } - err = ctx.GetStub().SetEvent("Transfer", transferEventJSON) - if err != nil { - return fmt.Errorf("failed to set event: %v", err) - } - - log.Printf("minter account %s balance updated from %d to %d", minter, currentBalance, updatedBalance) - - return nil -} - -// Burn redeems tokens the minter's account balance -// This function triggers a Transfer event -func (s *SmartContract) Burn(ctx contractapi.TransactionContextInterface, amount int) error { - - // Check if contract has been intilized first - initialized, err := checkInitialized(ctx) - if err != nil { - return fmt.Errorf("failed to check if contract is already initialized: %v", err) - } - if !initialized { - return fmt.Errorf("Contract options need to be set before calling any function, call Initialize() to initialize contract") - } - // Check minter authorization - this sample assumes Org1 is the central banker with privilege to burn new tokens - clientMSPID, err := ctx.GetClientIdentity().GetMSPID() - if err != nil { - return fmt.Errorf("failed to get MSPID: %v", err) - } - if clientMSPID != "Org1MSP" { - return fmt.Errorf("client is not authorized to mint new tokens") - } - - // Get ID of submitting client identity - minter, err := ctx.GetClientIdentity().GetID() - if err != nil { - return fmt.Errorf("failed to get client id: %v", err) - } - - if amount <= 0 { - return errors.New("burn amount must be a positive integer") - } - - currentBalanceBytes, err := ctx.GetStub().GetState(minter) - if err != nil { - return fmt.Errorf("failed to read minter account %s from world state: %v", minter, err) - } - - var currentBalance int - - // Check if minter current balance exists - if currentBalanceBytes == nil { - return errors.New("The balance does not exist") - } - - currentBalance, _ = strconv.Atoi(string(currentBalanceBytes)) // Error handling not needed since Itoa() was used when setting the account balance, guaranteeing it was an integer. - - updatedBalance, err := sub(currentBalance, amount) - if err != nil { - return err - } - - err = ctx.GetStub().PutState(minter, []byte(strconv.Itoa(updatedBalance))) - if err != nil { - return err - } - - // Update the totalSupply - totalSupplyBytes, err := ctx.GetStub().GetState(totalSupplyKey) - if err != nil { - return fmt.Errorf("failed to retrieve total token supply: %v", err) - } - - // If no tokens have been minted, throw error - if totalSupplyBytes == nil { - return errors.New("totalSupply does not exist") - } - - totalSupply, _ := strconv.Atoi(string(totalSupplyBytes)) // Error handling not needed since Itoa() was used when setting the totalSupply, guaranteeing it was an integer. - - // Subtract the burn amount to the total supply and update the state - totalSupply, err = sub(totalSupply, amount) - if err != nil { - return err - } - - err = ctx.GetStub().PutState(totalSupplyKey, []byte(strconv.Itoa(totalSupply))) - if err != nil { - return err - } - - // Emit the Transfer event - transferEvent := event{minter, "0x0", amount} - transferEventJSON, err := json.Marshal(transferEvent) - if err != nil { - return fmt.Errorf("failed to obtain JSON encoding: %v", err) - } - err = ctx.GetStub().SetEvent("Transfer", transferEventJSON) - if err != nil { - return fmt.Errorf("failed to set event: %v", err) - } - - log.Printf("minter account %s balance updated from %d to %d", minter, currentBalance, updatedBalance) - - return nil -} - -// Transfer transfers tokens from client account to recipient account -// recipient account must be a valid clientID as returned by the ClientID() function -// This function triggers a Transfer event -func (s *SmartContract) Transfer(ctx contractapi.TransactionContextInterface, recipient string, amount int) error { - - // Check if contract has been intilized first - initialized, err := checkInitialized(ctx) - if err != nil { - return fmt.Errorf("failed to check if contract is already initialized: %v", err) - } - if !initialized { - return fmt.Errorf("Contract options need to be set before calling any function, call Initialize() to initialize contract") - } - - // Get ID of submitting client identity - clientID, err := ctx.GetClientIdentity().GetID() - if err != nil { - return fmt.Errorf("failed to get client id: %v", err) - } - - err = transferHelper(ctx, clientID, recipient, amount) - if err != nil { - return fmt.Errorf("failed to transfer: %v", err) - } - - // Emit the Transfer event - transferEvent := event{clientID, recipient, amount} - transferEventJSON, err := json.Marshal(transferEvent) - if err != nil { - return fmt.Errorf("failed to obtain JSON encoding: %v", err) - } - err = ctx.GetStub().SetEvent("Transfer", transferEventJSON) - if err != nil { - return fmt.Errorf("failed to set event: %v", err) - } - - return nil -} - -// BalanceOf returns the balance of the given account -func (s *SmartContract) BalanceOf(ctx contractapi.TransactionContextInterface, account string) (int, error) { - - // Check if contract has been intilized first - initialized, err := checkInitialized(ctx) - if err != nil { - return 0, fmt.Errorf("failed to check if contract is already initialized: %v", err) - } - if !initialized { - return 0, fmt.Errorf("Contract options need to be set before calling any function, call Initialize() to initialize contract") - } - - balanceBytes, err := ctx.GetStub().GetState(account) - if err != nil { - return 0, fmt.Errorf("failed to read from world state: %v", err) - } - if balanceBytes == nil { - return 0, fmt.Errorf("the account %s does not exist", account) - } - - balance, _ := strconv.Atoi(string(balanceBytes)) // Error handling not needed since Itoa() was used when setting the account balance, guaranteeing it was an integer. - - return balance, nil -} - -// ClientAccountBalance returns the balance of the requesting client's account -func (s *SmartContract) ClientAccountBalance(ctx contractapi.TransactionContextInterface) (int, error) { - - // Check if contract has been intilized first - initialized, err := checkInitialized(ctx) - if err != nil { - return 0, fmt.Errorf("failed to check if contract is already initialized: %v", err) - } - if !initialized { - return 0, fmt.Errorf("Contract options need to be set before calling any function, call Initialize() to initialize contract") - } - - // Get ID of submitting client identity - clientID, err := ctx.GetClientIdentity().GetID() - if err != nil { - return 0, fmt.Errorf("failed to get client id: %v", err) - } - - balanceBytes, err := ctx.GetStub().GetState(clientID) - if err != nil { - return 0, fmt.Errorf("failed to read from world state: %v", err) - } - if balanceBytes == nil { - return 0, fmt.Errorf("the account %s does not exist", clientID) - } - - balance, _ := strconv.Atoi(string(balanceBytes)) // Error handling not needed since Itoa() was used when setting the account balance, guaranteeing it was an integer. - - return balance, nil -} - -// ClientAccountID returns the id of the requesting client's account -// In this implementation, the client account ID is the clientId itself -// Users can use this function to get their own account id, which they can then give to others as the payment address -func (s *SmartContract) ClientAccountID(ctx contractapi.TransactionContextInterface) (string, error) { - - // Check if contract has been intilized first - initialized, err := checkInitialized(ctx) - if err != nil { - return "", fmt.Errorf("failed to check if contract is already initialized: %v", err) - } - if !initialized { - return "", fmt.Errorf("Contract options need to be set before calling any function, call Initialize() to initialize contract") - } - - // Get ID of submitting client identity - clientAccountID, err := ctx.GetClientIdentity().GetID() - if err != nil { - return "", fmt.Errorf("failed to get client id: %v", err) - } - - return clientAccountID, nil -} - -// TotalSupply returns the total token supply -func (s *SmartContract) TotalSupply(ctx contractapi.TransactionContextInterface) (int, error) { - - // Check if contract has been intilized first - initialized, err := checkInitialized(ctx) - if err != nil { - return 0, fmt.Errorf("failed to check if contract is already initialized: %v", err) - } - if !initialized { - return 0, fmt.Errorf("Contract options need to be set before calling any function, call Initialize() to initialize contract") - } - - // Retrieve total supply of tokens from state of smart contract - totalSupplyBytes, err := ctx.GetStub().GetState(totalSupplyKey) - if err != nil { - return 0, fmt.Errorf("failed to retrieve total token supply: %v", err) - } - - var totalSupply int - - // If no tokens have been minted, return 0 - if totalSupplyBytes == nil { - totalSupply = 0 - } else { - totalSupply, _ = strconv.Atoi(string(totalSupplyBytes)) // Error handling not needed since Itoa() was used when setting the totalSupply, guaranteeing it was an integer. - } - - log.Printf("TotalSupply: %d tokens", totalSupply) - - return totalSupply, nil -} - -// Approve allows the spender to withdraw from the calling client's token account -// The spender can withdraw multiple times if necessary, up to the value amount -// This function triggers an Approval event -func (s *SmartContract) Approve(ctx contractapi.TransactionContextInterface, spender string, value int) error { - - // Check if contract has been intilized first - initialized, err := checkInitialized(ctx) - if err != nil { - return fmt.Errorf("failed to check if contract is already initialized: %v", err) - } - if !initialized { - return fmt.Errorf("Contract options need to be set before calling any function, call Initialize() to initialize contract") - } - - // Get ID of submitting client identity - owner, err := ctx.GetClientIdentity().GetID() - if err != nil { - return fmt.Errorf("failed to get client id: %v", err) - } - - // Create allowanceKey - allowanceKey, err := ctx.GetStub().CreateCompositeKey(allowancePrefix, []string{owner, spender}) - if err != nil { - return fmt.Errorf("failed to create the composite key for prefix %s: %v", allowancePrefix, err) - } - - // Update the state of the smart contract by adding the allowanceKey and value - err = ctx.GetStub().PutState(allowanceKey, []byte(strconv.Itoa(value))) - if err != nil { - return fmt.Errorf("failed to update state of smart contract for key %s: %v", allowanceKey, err) - } - - // Emit the Approval event - approvalEvent := event{owner, spender, value} - approvalEventJSON, err := json.Marshal(approvalEvent) - if err != nil { - return fmt.Errorf("failed to obtain JSON encoding: %v", err) - } - err = ctx.GetStub().SetEvent("Approval", approvalEventJSON) - if err != nil { - return fmt.Errorf("failed to set event: %v", err) - } - - log.Printf("client %s approved a withdrawal allowance of %d for spender %s", owner, value, spender) - - return nil -} - -// Allowance returns the amount still available for the spender to withdraw from the owner -func (s *SmartContract) Allowance(ctx contractapi.TransactionContextInterface, owner string, spender string) (int, error) { - - // Check if contract has been intilized first - initialized, err := checkInitialized(ctx) - if err != nil { - return 0, fmt.Errorf("failed to check if contract is already initialized: %v", err) - } - if !initialized { - return 0, fmt.Errorf("Contract options need to be set before calling any function, call Initialize() to initialize contract") - } - - // Create allowanceKey - allowanceKey, err := ctx.GetStub().CreateCompositeKey(allowancePrefix, []string{owner, spender}) - if err != nil { - return 0, fmt.Errorf("failed to create the composite key for prefix %s: %v", allowancePrefix, err) - } - - // Read the allowance amount from the world state - allowanceBytes, err := ctx.GetStub().GetState(allowanceKey) - if err != nil { - return 0, fmt.Errorf("failed to read allowance for %s from world state: %v", allowanceKey, err) - } - - var allowance int - - // If no current allowance, set allowance to 0 - if allowanceBytes == nil { - allowance = 0 - } else { - allowance, err = strconv.Atoi(string(allowanceBytes)) // Error handling not needed since Itoa() was used when setting the totalSupply, guaranteeing it was an integer. - } - - log.Printf("The allowance left for spender %s to withdraw from owner %s: %d", spender, owner, allowance) - - return allowance, nil -} - -// TransferFrom transfers the value amount from the "from" address to the "to" address -// This function triggers a Transfer event -func (s *SmartContract) TransferFrom(ctx contractapi.TransactionContextInterface, from string, to string, value int) error { - - // Check if contract has been intilized first - initialized, err := checkInitialized(ctx) - if err != nil { - return fmt.Errorf("failed to check if contract is already initialized: %v", err) - } - if !initialized { - return fmt.Errorf("Contract options need to be set before calling any function, call Initialize() to initialize contract") - } - - // Get ID of submitting client identity - spender, err := ctx.GetClientIdentity().GetID() - if err != nil { - return fmt.Errorf("failed to get client id: %v", err) - } - - // Create allowanceKey - allowanceKey, err := ctx.GetStub().CreateCompositeKey(allowancePrefix, []string{from, spender}) - if err != nil { - return fmt.Errorf("failed to create the composite key for prefix %s: %v", allowancePrefix, err) - } - - // Retrieve the allowance of the spender - currentAllowanceBytes, err := ctx.GetStub().GetState(allowanceKey) - if err != nil { - return fmt.Errorf("failed to retrieve the allowance for %s from world state: %v", allowanceKey, err) - } - - var currentAllowance int - currentAllowance, _ = strconv.Atoi(string(currentAllowanceBytes)) // Error handling not needed since Itoa() was used when setting the totalSupply, guaranteeing it was an integer. - - // Check if transferred value is less than allowance - if currentAllowance < value { - return fmt.Errorf("spender does not have enough allowance for transfer") - } - - // Initiate the transfer - err = transferHelper(ctx, from, to, value) - if err != nil { - return fmt.Errorf("failed to transfer: %v", err) - } - - // Decrease the allowance - updatedAllowance, err := sub(currentAllowance, value) - if err != nil { - return err - } - - err = ctx.GetStub().PutState(allowanceKey, []byte(strconv.Itoa(updatedAllowance))) - if err != nil { - return err - } - - // Emit the Transfer event - transferEvent := event{from, to, value} - transferEventJSON, err := json.Marshal(transferEvent) - if err != nil { - return fmt.Errorf("failed to obtain JSON encoding: %v", err) - } - err = ctx.GetStub().SetEvent("Transfer", transferEventJSON) - if err != nil { - return fmt.Errorf("failed to set event: %v", err) - } - - log.Printf("spender %s allowance updated from %d to %d", spender, currentAllowance, updatedAllowance) - - return nil -} - -// Name returns a descriptive name for fungible tokens in this contract -// returns {String} Returns the name of the token - -func (s *SmartContract) Name(ctx contractapi.TransactionContextInterface) (string, error) { - - // Check if contract has been intilized first - initialized, err := checkInitialized(ctx) - if err != nil { - return "", fmt.Errorf("failed to check if contract is already initialized: %v", err) - } - if !initialized { - return "", fmt.Errorf("Contract options need to be set before calling any function, call Initialize() to initialize contract") - } - - bytes, err := ctx.GetStub().GetState(nameKey) - if err != nil { - return "", fmt.Errorf("failed to get Name bytes: %s", err) - } - - return string(bytes), nil -} - -// Symbol returns an abbreviated name for fungible tokens in this contract. -// returns {String} Returns the symbol of the token - -func (s *SmartContract) Symbol(ctx contractapi.TransactionContextInterface) (string, error) { - - // Check if contract has been intilized first - initialized, err := checkInitialized(ctx) - if err != nil { - return "", fmt.Errorf("failed to check if contract is already initialized: %v", err) - } - if !initialized { - return "", fmt.Errorf("Contract options need to be set before calling any function, call Initialize() to initialize contract") - } - - bytes, err := ctx.GetStub().GetState(symbolKey) - if err != nil { - return "", fmt.Errorf("failed to get Symbol: %v", err) - } - - return string(bytes), nil -} - -// Set information for a token and intialize contract. -// param {String} name The name of the token -// param {String} symbol The symbol of the token -// param {String} decimals The decimals used for the token operations -func (s *SmartContract) Initialize(ctx contractapi.TransactionContextInterface, name string, symbol string, decimals string) (bool, error) { - - // Check minter authorization - this sample assumes Org1 is the central banker with privilege to intitialize contract - clientMSPID, err := ctx.GetClientIdentity().GetMSPID() - if err != nil { - return false, fmt.Errorf("failed to get MSPID: %v", err) - } - if clientMSPID != "Org1MSP" { - return false, fmt.Errorf("client is not authorized to initialize contract") - } - - // Check contract options are not already set, client is not authorized to change them once intitialized - bytes, err := ctx.GetStub().GetState(nameKey) - if err != nil { - return false, fmt.Errorf("failed to get Name: %v", err) - } - if bytes != nil { - return false, fmt.Errorf("contract options are already set, client is not authorized to change them") - } - - err = ctx.GetStub().PutState(nameKey, []byte(name)) - if err != nil { - return false, fmt.Errorf("failed to set token name: %v", err) - } - - err = ctx.GetStub().PutState(symbolKey, []byte(symbol)) - if err != nil { - return false, fmt.Errorf("failed to set symbol: %v", err) - } - - err = ctx.GetStub().PutState(decimalsKey, []byte(decimals)) - if err != nil { - return false, fmt.Errorf("failed to set token name: %v", err) - } - - return true, nil -} - -// Helper Functions - -// transferHelper is a helper function that transfers tokens from the "from" address to the "to" address -// Dependant functions include Transfer and TransferFrom -func transferHelper(ctx contractapi.TransactionContextInterface, from string, to string, value int) error { - - if from == to { - return fmt.Errorf("cannot transfer to and from same client account") - } - - if value < 0 { // transfer of 0 is allowed in ERC-20, so just validate against negative amounts - return fmt.Errorf("transfer amount cannot be negative") - } - - fromCurrentBalanceBytes, err := ctx.GetStub().GetState(from) - if err != nil { - return fmt.Errorf("failed to read client account %s from world state: %v", from, err) - } - - if fromCurrentBalanceBytes == nil { - return fmt.Errorf("client account %s has no balance", from) - } - - fromCurrentBalance, _ := strconv.Atoi(string(fromCurrentBalanceBytes)) // Error handling not needed since Itoa() was used when setting the account balance, guaranteeing it was an integer. - - if fromCurrentBalance < value { - return fmt.Errorf("client account %s has insufficient funds", from) - } - - toCurrentBalanceBytes, err := ctx.GetStub().GetState(to) - if err != nil { - return fmt.Errorf("failed to read recipient account %s from world state: %v", to, err) - } - - var toCurrentBalance int - // If recipient current balance doesn't yet exist, we'll create it with a current balance of 0 - if toCurrentBalanceBytes == nil { - toCurrentBalance = 0 - } else { - toCurrentBalance, _ = strconv.Atoi(string(toCurrentBalanceBytes)) // Error handling not needed since Itoa() was used when setting the account balance, guaranteeing it was an integer. - } - - fromUpdatedBalance, err := sub(fromCurrentBalance, value) - if err != nil { - return err - } - - toUpdatedBalance, err := add(toCurrentBalance, value) - if err != nil { - return err - } - - err = ctx.GetStub().PutState(from, []byte(strconv.Itoa(fromUpdatedBalance))) - if err != nil { - return err - } - - err = ctx.GetStub().PutState(to, []byte(strconv.Itoa(toUpdatedBalance))) - if err != nil { - return err - } - - log.Printf("client %s balance updated from %d to %d", from, fromCurrentBalance, fromUpdatedBalance) - log.Printf("recipient %s balance updated from %d to %d", to, toCurrentBalance, toUpdatedBalance) - - return nil -} - -// add two number checking for overflow -func add(b int, q int) (int, error) { - - // Check overflow - var sum int - sum = q + b - - if (sum < q || sum < b) == (b >= 0 && q >= 0) { - return 0, fmt.Errorf("Math: addition overflow occurred %d + %d", b, q) - } - - return sum, nil -} - -// Checks that contract options have been already initialized -func checkInitialized(ctx contractapi.TransactionContextInterface) (bool, error) { - tokenName, err := ctx.GetStub().GetState(nameKey) - if err != nil { - return false, fmt.Errorf("failed to get token name: %v", err) - } - - if tokenName == nil { - return false, nil - } - - return true, nil -} - -// sub two number checking for overflow -func sub(b int, q int) (int, error) { - - // sub two number checking - if q <= 0 { - return 0, fmt.Errorf("Error: the subtraction number is %d, it should be greater than 0", q) - } - if b < q { - return 0, fmt.Errorf("Error: the number %d is not enough to be subtracted by %d", b, q) - } - var diff int - diff = b - q - - return diff, nil -} diff --git a/token-erc-20/chaincode-go/go.mod b/token-erc-20/chaincode-go/go.mod deleted file mode 100644 index c027e71b..00000000 --- a/token-erc-20/chaincode-go/go.mod +++ /dev/null @@ -1,32 +0,0 @@ -module github.com/hyperledger/fabric-samples/token-erc-20/chaincode-go - -go 1.21 - -require github.com/hyperledger/fabric-contract-api-go/v2 v2.0.0 - -require ( - github.com/go-openapi/jsonpointer v0.21.0 // indirect - github.com/go-openapi/jsonreference v0.21.0 // indirect - github.com/go-openapi/spec v0.21.0 // indirect - github.com/go-openapi/swag v0.23.0 // indirect - github.com/gobuffalo/envy v1.10.2 // indirect - github.com/gobuffalo/packd v1.0.2 // indirect - github.com/gobuffalo/packr v1.30.1 // indirect - github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0-20240618210511-f7903324a8af // indirect - github.com/hyperledger/fabric-protos-go-apiv2 v0.3.3 // indirect - github.com/joho/godotenv v1.5.1 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/mailru/easyjson v0.7.7 // indirect - github.com/rogpeppe/go-internal v1.12.0 // indirect - github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect - github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect - github.com/xeipuuv/gojsonschema v1.2.0 // indirect - golang.org/x/mod v0.17.0 // indirect - golang.org/x/net v0.24.0 // indirect - golang.org/x/sys v0.19.0 // indirect - golang.org/x/text v0.14.0 // indirect - google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect - google.golang.org/grpc v1.64.0 // indirect - google.golang.org/protobuf v1.34.2 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) diff --git a/token-erc-20/chaincode-go/go.sum b/token-erc-20/chaincode-go/go.sum deleted file mode 100644 index 7c5e414c..00000000 --- a/token-erc-20/chaincode-go/go.sum +++ /dev/null @@ -1,132 +0,0 @@ -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= -github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= -github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= -github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= -github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= -github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= -github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= -github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= -github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= -github.com/gobuffalo/envy v1.10.2 h1:EIi03p9c3yeuRCFPOKcSfajzkLb3hrRjEpHGI8I2Wo4= -github.com/gobuffalo/envy v1.10.2/go.mod h1:qGAGwdvDsaEtPhfBzb3o0SfDea8ByGn9j8bKmVft9z8= -github.com/gobuffalo/logger v1.0.0/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs= -github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q= -github.com/gobuffalo/packd v1.0.2 h1:Yg523YqnOxGIWCp69W12yYBKsoChwI7mtu6ceM9Bwfw= -github.com/gobuffalo/packd v1.0.2/go.mod h1:sUc61tDqGMXON80zpKGp92lDb86Km28jfvX7IAyxFT8= -github.com/gobuffalo/packr v1.30.1 h1:hu1fuVR3fXEZR7rXNW3h8rqSML8EVAf6KNm0NKO/wKg= -github.com/gobuffalo/packr v1.30.1/go.mod h1:ljMyFO2EcrnzsHsN99cvbq055Y9OhRrIaviy289eRuk= -github.com/gobuffalo/packr/v2 v2.5.1/go.mod h1:8f9c96ITobJlPzI44jj+4tHnEKNt0xXWSVlXRN9X1Iw= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0-20240618210511-f7903324a8af h1:WT4NjX7Uk03GSeH++jF3a0wp4FhybTM86zDPCETvmSk= -github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0-20240618210511-f7903324a8af/go.mod h1:f/ER25FaBepxJugwpLhbD2hLAoZaZEVqkBjOcHjw72Y= -github.com/hyperledger/fabric-contract-api-go/v2 v2.0.0 h1:IDiCGVOBlRd6zpL0Y+f6V7IpBqa4/Z5JAK9SF7a5ea8= -github.com/hyperledger/fabric-contract-api-go/v2 v2.0.0/go.mod h1:pdqhe7ALf4lmXgQdprCyNWYdnCPxgj02Vhf8JF5w8po= -github.com/hyperledger/fabric-protos-go-apiv2 v0.3.3 h1:Xpd6fzG/KjAOHJsq7EQXY2l+qi/y8muxBaY7R6QWABk= -github.com/hyperledger/fabric-protos-go-apiv2 v0.3.3/go.mod h1:2pq0ui6ZWA0cC8J+eCErgnMDCS1kPOEYVY+06ZAK0qE= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= -github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= -github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= -github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= -golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= -google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/token-erc-20/chaincode-go/token_erc_20.go b/token-erc-20/chaincode-go/token_erc_20.go deleted file mode 100644 index 14cfc54f..00000000 --- a/token-erc-20/chaincode-go/token_erc_20.go +++ /dev/null @@ -1,23 +0,0 @@ -/* -SPDX-License-Identifier: Apache-2.0 -*/ - -package main - -import ( - "log" - - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" - "github.com/hyperledger/fabric-samples/token-erc-20/chaincode-go/chaincode" -) - -func main() { - tokenChaincode, err := contractapi.NewChaincode(&chaincode.SmartContract{}) - if err != nil { - log.Panicf("Error creating token-erc-20 chaincode: %v", err) - } - - if err := tokenChaincode.Start(); err != nil { - log.Panicf("Error starting token-erc-20 chaincode: %v", err) - } -} diff --git a/token-erc-20/chaincode-java/Dockerfile b/token-erc-20/chaincode-java/Dockerfile deleted file mode 100755 index 55aa22ba..00000000 --- a/token-erc-20/chaincode-java/Dockerfile +++ /dev/null @@ -1,32 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 -# the first stage -FROM gradle:jdk11 AS GRADLE_BUILD - -# copy the build.gradle and src code to the container -COPY src/ src/ -COPY build.gradle ./ - -# Build and package our code -RUN gradle --no-daemon build shadowJar -x checkstyleMain -x checkstyleTest - - -# the second stage of our build just needs the compiled files -FROM openjdk:11-jre -ARG CC_SERVER_PORT=9999 - -# Setup tini to work better handle signals -ENV TINI_VERSION v0.19.0 -ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini -RUN chmod +x /tini - -RUN addgroup --system javauser && useradd -g javauser javauser - -# copy only the artifacts we need from the first stage and discard the rest -COPY --chown=javauser:javauser --from=GRADLE_BUILD /home/gradle/build/libs/chaincode.jar /chaincode.jar -COPY --chown=javauser:javauser docker/docker-entrypoint.sh /docker-entrypoint.sh -RUN chmod +x /docker-entrypoint.sh -ENV PORT $CC_SERVER_PORT -EXPOSE $CC_SERVER_PORT - -USER javauser -ENTRYPOINT [ "/tini", "--", "/docker-entrypoint.sh" ] diff --git a/token-erc-20/chaincode-java/build.gradle b/token-erc-20/chaincode-java/build.gradle deleted file mode 100755 index 7a0e1995..00000000 --- a/token-erc-20/chaincode-java/build.gradle +++ /dev/null @@ -1,94 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ - -plugins { - id 'com.github.johnrengelman.shadow' version '8.1.1' - id 'application' - id 'checkstyle' - id 'jacoco' -} - -group 'org.hyperledger.fabric.samples' -version '1.0-SNAPSHOT' - -dependencies { - - implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.+' - implementation 'org.json:json:+' - implementation 'com.owlike:genson:1.5' - testImplementation 'org.junit.jupiter:junit-jupiter:5.10.2' - testImplementation 'org.assertj:assertj-core:3.25.3' - testImplementation 'org.mockito:mockito-core:5.12.0' - testRuntimeOnly("net.bytebuddy:byte-buddy:1.10.6") - -} - -repositories { - mavenCentral() - maven { - url 'https://jitpack.io' - } -} - -java { - toolchain { - languageVersion = JavaLanguageVersion.of(11) - } -} - -application { - mainClass = 'org.hyperledger.fabric.contract.ContractRouter' -} - -checkstyle { - toolVersion '8.21' - configFile file("config/checkstyle/checkstyle.xml") -} - -checkstyleMain { - source ='src/main/java' -} - -checkstyleTest { - source ='src/test/java' -} - -jacocoTestReport { - dependsOn test -} - -jacocoTestCoverageVerification { - violationRules { - rule { - limit { - minimum = 0.8 - } - } - } - - finalizedBy jacocoTestReport -} - -test { - useJUnitPlatform() - testLogging { - events "passed", "skipped", "failed" - } -} - -mainClassName = 'org.hyperledger.fabric.contract.ContractRouter' - -shadowJar { - archiveBaseName = 'chaincode' - archiveVersion = '' - archiveClassifier = '' - mergeServiceFiles() - - manifest { - attributes 'Main-Class': 'org.hyperledger.fabric.contract.ContractRouter' - } -} - -check.dependsOn jacocoTestCoverageVerification -installDist.dependsOn check diff --git a/token-erc-20/chaincode-java/config/checkstyle/checkstyle.xml b/token-erc-20/chaincode-java/config/checkstyle/checkstyle.xml deleted file mode 100755 index acd5df44..00000000 --- a/token-erc-20/chaincode-java/config/checkstyle/checkstyle.xml +++ /dev/null @@ -1,171 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/token-erc-20/chaincode-java/config/checkstyle/suppressions.xml b/token-erc-20/chaincode-java/config/checkstyle/suppressions.xml deleted file mode 100755 index 6a7dbbc2..00000000 --- a/token-erc-20/chaincode-java/config/checkstyle/suppressions.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - diff --git a/token-erc-20/chaincode-java/docker/docker-entrypoint.sh b/token-erc-20/chaincode-java/docker/docker-entrypoint.sh deleted file mode 100755 index 179818db..00000000 --- a/token-erc-20/chaincode-java/docker/docker-entrypoint.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env bash -# -# SPDX-License-Identifier: Apache-2.0 -# -set -euo pipefail -: ${CORE_PEER_TLS_ENABLED:="false"} -: ${DEBUG:="false"} - -if [ "${DEBUG,,}" = "true" ]; then - exec java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=0.0.0.0:8000 -jar /chaincode.jar -elif [ "${CORE_PEER_TLS_ENABLED,,}" = "true" ]; then - exec java -jar /chaincode.jar # todo -else - exec java -jar /chaincode.jar -fi - diff --git a/token-erc-20/chaincode-java/gradle/wrapper/gradle-wrapper.jar b/token-erc-20/chaincode-java/gradle/wrapper/gradle-wrapper.jar deleted file mode 100755 index 7f93135c49b765f8051ef9d0a6055ff8e46073d8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 63721 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鯊%1Et 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⁢ zv5o9#E7!G0XmdzfsS{efPNi`1b44~SZ4Z8fuX!I}#8g+(wxzQwUT#Xb2(tbY1+EUhGKoT@KEU9Ktl>_0 z%bjDJg;#*gtJZv!-Zs`?^}v5eKmnbjqlvnSzE@_SP|LG_PJ6CYU+6zY6>92%E+ z=j@TZf-iW4(%U{lnYxQA;7Q!b;^brF8n0D>)`q5>|WDDXLrqYU_tKN2>=#@~OE7grMnNh?UOz-O~6 z6%rHy{#h9K0AT+lDC7q4{hw^|q6*Ry;;L%Q@)Ga}$60_q%D)rv(CtS$CQbpq9|y1e zRSrN4;$Jyl{m5bZw`$8TGvb}(LpY{-cQ)fcyJv7l3S52TLXVDsphtv&aPuDk1OzCA z4A^QtC(!11`IsNx_HnSy?>EKpHJWT^wmS~hc^p^zIIh@9f6U@I2 zC=Mve{j2^)mS#U$e{@Q?SO6%LDsXz@SY+=cK_QMmXBIU)j!$ajc-zLx3V60EXJ!qC zi<%2x8Q24YN+&8U@CIlN zrZkcT9yh%LrlGS9`G)KdP(@9Eo-AQz@8GEFWcb7U=a0H^ZVbLmz{+&M7W(nXJ4sN8 zJLR7eeK(K8`2-}j(T7JsO`L!+CvbueT%izanm-^A1Dn{`1Nw`9P?cq;7no+XfC`K(GO9?O^5zNIt4M+M8LM0=7Gz8UA@Z0N+lg+cX)NfazRu z5D)~HA^(u%w^cz+@2@_#S|u>GpB+j4KzQ^&Wcl9f z&hG#bCA(Yk0D&t&aJE^xME^&E-&xGHhXn%}psEIj641H+Nl-}boj;)Zt*t(4wZ5DN z@GXF$bL=&pBq-#vkTkh>7hl%K5|3 z{`Vn9b$iR-SoGENp}bn4;fR3>9sA%X2@1L3aE9yTra;Wb#_`xWwLSLdfu+PAu+o3| zGVnpzPr=ch{uuoHjtw7+_!L_2;knQ!DuDl0R`|%jr+}jFzXtrHIKc323?JO{l&;VF z*L1+}JU7%QJOg|5|Tc|D8fN zJORAg=_vsy{ak|o);@)Yh8Lkcg@$FG3k@ep36BRa^>~UmnRPziS>Z=`Jb2x*Q#`%A zU*i3&Vg?TluO@X0O;r2Jl6LKLUOVhSqg1*qOt^|8*c7 zo(298@+r$k_wQNGHv{|$tW(T8L+4_`FQ{kEW5Jgg{yf7ey4ss_(SNKfz(N9lx&a;< je(UuV8hP?p&}TPdm1I$XmG#(RzlD&B2izSj9sl%y5~4qc diff --git a/token-erc-20/chaincode-java/gradle/wrapper/gradle-wrapper.properties b/token-erc-20/chaincode-java/gradle/wrapper/gradle-wrapper.properties deleted file mode 100755 index a80b22ce..00000000 --- a/token-erc-20/chaincode-java/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,7 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip -networkTimeout=10000 -validateDistributionUrl=true -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/token-erc-20/chaincode-java/gradlew b/token-erc-20/chaincode-java/gradlew deleted file mode 100755 index 0adc8e1a..00000000 --- a/token-erc-20/chaincode-java/gradlew +++ /dev/null @@ -1,249 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -# This is normally unused -# shellcheck disable=SC2034 -APP_BASE_NAME=${0##*/} -# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - if ! command -v java >/dev/null 2>&1 - then - die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/token-erc-20/chaincode-java/gradlew.bat b/token-erc-20/chaincode-java/gradlew.bat deleted file mode 100755 index 6689b85b..00000000 --- a/token-erc-20/chaincode-java/gradlew.bat +++ /dev/null @@ -1,92 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/token-erc-20/chaincode-java/settings.gradle b/token-erc-20/chaincode-java/settings.gradle deleted file mode 100755 index 87ea1830..00000000 --- a/token-erc-20/chaincode-java/settings.gradle +++ /dev/null @@ -1,5 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ - -rootProject.name = 'token_erc20' diff --git a/token-erc-20/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc20/ContractConstants.java b/token-erc-20/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc20/ContractConstants.java deleted file mode 100644 index 9877021f..00000000 --- a/token-erc-20/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc20/ContractConstants.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ - -package org.hyperledger.fabric.samples.erc20; - -/** ERC20 constants for KEYS ,EVENTS and MSP */ -public enum ContractConstants { - BALANCE_PREFIX("balance"), - ALLOWANCE_PREFIX("allowance"), - NAME_KEY("name"), - SYMBOL_KEY("symbolKey"), - DECIMALS_KEY("decimals"), - TOTAL_SUPPLY_KEY("totalSupply"), - TRANSFER_EVENT("Transfer"), - MINTER_ORG_MSPID("Org1MSP"), - APPROVAL("Approval"); - - private final String prefix; - - ContractConstants(final String value) { - this.prefix = value; - } - - public String getValue() { - return prefix; - } -} diff --git a/token-erc-20/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc20/ContractErrors.java b/token-erc-20/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc20/ContractErrors.java deleted file mode 100644 index 4a0a5959..00000000 --- a/token-erc-20/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc20/ContractErrors.java +++ /dev/null @@ -1,19 +0,0 @@ - -/* - * SPDX-License-Identifier: Apache-2.0 -*/ -package org.hyperledger.fabric.samples.erc20; -/** - * @author Renjith - * ERC20 constants for exceptions. - */ - -public enum ContractErrors { - BALANCE_NOT_FOUND, - UNAUTHORIZED_SENDER, - INVALID_AMOUNT, - NOT_FOUND, - INVALID_TRANSFER, - INSUFFICIENT_FUND, - NO_ALLOWANCE_FOUND -} diff --git a/token-erc-20/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc20/ERC20TokenContract.java b/token-erc-20/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc20/ERC20TokenContract.java deleted file mode 100644 index 54652762..00000000 --- a/token-erc-20/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc20/ERC20TokenContract.java +++ /dev/null @@ -1,526 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.fabric.samples.erc20; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.hyperledger.fabric.samples.erc20.ContractConstants.ALLOWANCE_PREFIX; -import static org.hyperledger.fabric.samples.erc20.ContractConstants.APPROVAL; -import static org.hyperledger.fabric.samples.erc20.ContractConstants.BALANCE_PREFIX; -import static org.hyperledger.fabric.samples.erc20.ContractConstants.DECIMALS_KEY; -import static org.hyperledger.fabric.samples.erc20.ContractConstants.NAME_KEY; -import static org.hyperledger.fabric.samples.erc20.ContractConstants.SYMBOL_KEY; -import static org.hyperledger.fabric.samples.erc20.ContractConstants.TOTAL_SUPPLY_KEY; -import static org.hyperledger.fabric.samples.erc20.ContractConstants.TRANSFER_EVENT; -import static org.hyperledger.fabric.samples.erc20.ContractErrors.BALANCE_NOT_FOUND; -import static org.hyperledger.fabric.samples.erc20.ContractErrors.INSUFFICIENT_FUND; -import static org.hyperledger.fabric.samples.erc20.ContractErrors.INVALID_AMOUNT; -import static org.hyperledger.fabric.samples.erc20.ContractErrors.INVALID_TRANSFER; -import static org.hyperledger.fabric.samples.erc20.ContractErrors.NOT_FOUND; -import static org.hyperledger.fabric.samples.erc20.ContractErrors.NO_ALLOWANCE_FOUND; -import static org.hyperledger.fabric.samples.erc20.ContractErrors.UNAUTHORIZED_SENDER; -import static org.hyperledger.fabric.samples.erc20.utils.ContractUtility.stringIsNullOrEmpty; - -import com.owlike.genson.Genson; -import org.hyperledger.fabric.Logger; -import org.hyperledger.fabric.contract.Context; -import org.hyperledger.fabric.contract.ContractInterface; -import org.hyperledger.fabric.contract.annotation.Contact; -import org.hyperledger.fabric.contract.annotation.Contract; -import org.hyperledger.fabric.contract.annotation.Default; -import org.hyperledger.fabric.contract.annotation.Info; -import org.hyperledger.fabric.contract.annotation.License; -import org.hyperledger.fabric.contract.annotation.Transaction; -import org.hyperledger.fabric.samples.erc20.model.Approval; -import org.hyperledger.fabric.samples.erc20.model.Transfer; -import org.hyperledger.fabric.shim.ChaincodeException; -import org.hyperledger.fabric.shim.ChaincodeStub; -import org.hyperledger.fabric.shim.ledger.CompositeKey; - -@Contract( - name = "erc20token", - info = - @Info( - title = "ERC20Token Contract", - description = "The erc20 fungible token implementation.", - version = "0.0.1-SNAPSHOT", - license = - @License( - name = "Apache 2.0 License", - url = "http://www.apache.org/licenses/LICENSE-2.0.html"), - contact = - @Contact( - email = "renjithkn@gmail.com", - name = "Renjith Narayanan", - url = "https://hyperledger.example.com"))) -@Default -public final class ERC20TokenContract implements ContractInterface { - - final Logger logger = Logger.getLogger(ERC20TokenContract.class); - - /** - * Mint creates new tokens and adds them to minter's account balance. This function triggers a - * Transfer event. - * - * @param ctx the transaction context - * @param amount of tokens to be minted - */ - @Transaction(intent = Transaction.TYPE.SUBMIT) - public void Mint(final Context ctx, final long amount) { - - // Check minter authorization - this sample assumes Org1 is the central banker with privilege to - // mint new tokens - String clientMSPID = ctx.getClientIdentity().getMSPID(); - ChaincodeStub stub = ctx.getStub(); - if (!clientMSPID.equalsIgnoreCase(ContractConstants.MINTER_ORG_MSPID.getValue())) { - throw new ChaincodeException( - "Client is not authorized to mint new tokens", UNAUTHORIZED_SENDER.toString()); - } - - // Check contract options are already set first to execute the function - this.checkInitialized(ctx); - - // Get ID of submitting client identity - String minter = ctx.getClientIdentity().getId(); - if (amount <= 0) { - throw new ChaincodeException( - "Mint amount must be a positive integer", INVALID_AMOUNT.toString()); - } - CompositeKey balanceKey = stub.createCompositeKey(BALANCE_PREFIX.getValue(), minter); - String currentBalanceStr = stub.getStringState(balanceKey.toString()); - // If minter current balance doesn't yet exist, we'll create it with a current balance of 0 - long currentBalance = 0; - if (!stringIsNullOrEmpty(currentBalanceStr)) { - currentBalance = Long.parseLong(currentBalanceStr); - } - // Used safe math . - long updatedBalance = Math.addExact(currentBalance, amount); - stub.putStringState(balanceKey.toString(), String.valueOf(updatedBalance)); - // Increase totalSupply - String totalSupplyStr = stub.getStringState(TOTAL_SUPPLY_KEY.getValue()); - long totalSupply = 0; - if (!stringIsNullOrEmpty(totalSupplyStr)) { - totalSupply = Long.parseLong(totalSupplyStr); - } - // Used safe math . - totalSupply = Math.addExact(totalSupply, amount); - stub.putStringState(TOTAL_SUPPLY_KEY.getValue(), String.valueOf(totalSupply)); - Transfer transferEvent = new Transfer("0x0", minter, amount); - stub.setEvent(TRANSFER_EVENT.getValue(), this.marshal(transferEvent)); - logger.info( - String.format( - "minter account %s balance updated from %d to %d", - minter, currentBalance, updatedBalance)); - } - - /** - * Burn redeems tokens the minter's account balance. This function triggers a Transfer event. - * - * @param ctx the transaction context - * @param amount amount of tokens to be burned - */ - @Transaction(intent = Transaction.TYPE.SUBMIT) - public void Burn(final Context ctx, final long amount) { - - // Check minter authorization - this sample assumes Org1 is the central banker with privilege to - // burn tokens - - String clientMSPID = ctx.getClientIdentity().getMSPID(); - ChaincodeStub stub = ctx.getStub(); - if (!clientMSPID.equalsIgnoreCase(ContractConstants.MINTER_ORG_MSPID.getValue())) { - throw new ChaincodeException( - "Client is not authorized to burn tokens", UNAUTHORIZED_SENDER.toString()); - } - - // Check contract options are already set first to execute the function - this.checkInitialized(ctx); - - String minter = ctx.getClientIdentity().getId(); - if (amount <= 0) { - throw new ChaincodeException( - "Burn amount must be a positive integer", INVALID_AMOUNT.toString()); - } - CompositeKey balanceKey = stub.createCompositeKey(BALANCE_PREFIX.getValue(), minter); - String currentBalanceStr = stub.getStringState(balanceKey.toString()); - if (stringIsNullOrEmpty(currentBalanceStr)) { - throw new ChaincodeException("The balance does not exist", BALANCE_NOT_FOUND.toString()); - } - long currentBalance = Long.parseLong(currentBalanceStr); - // Check if the sender has enough tokens to burn. - - if (currentBalance < amount) { - String errorMessage = String.format("Client account %s has insufficient funds", minter); - throw new ChaincodeException(errorMessage, INSUFFICIENT_FUND.toString()); - } - long updatedBalance = Math.subtractExact(currentBalance, amount); - stub.putStringState(balanceKey.toString(), String.valueOf(updatedBalance)); - // Decrease totalSupply - String totalSupplyBytes = stub.getStringState(TOTAL_SUPPLY_KEY.getValue()); - if (stringIsNullOrEmpty(totalSupplyBytes)) { - throw new ChaincodeException("TotalSupply does not exist", NOT_FOUND.toString()); - } - long totalSupply = Math.subtractExact(Long.parseLong(totalSupplyBytes), amount); - stub.putStringState(TOTAL_SUPPLY_KEY.getValue(), String.valueOf(totalSupply)); - // Emit the Transfer event - final Transfer transferEvent = new Transfer(minter, "0x0", amount); - stub.setEvent(TRANSFER_EVENT.getValue(), this.marshal(transferEvent)); - logger.info( - String.format( - "minter account %s balance updated from %d to %d", - minter, currentBalance, updatedBalance)); - } - - /** - * Transfer transfers tokens from client account to recipient account. Recipient account must be a - * valid client Id as returned by the ClientID() function must be a valid clientID as returned by - * the ClientAccountID() function. This function triggers a Transfer event. - * - * @param ctx the transaction context - * @param to the recipient - * @param value the amount of token to be transferred - */ - @Transaction(intent = Transaction.TYPE.SUBMIT) - public void Transfer(final Context ctx, final String to, final long value) { - // Check contract options are already set first to execute the function - this.checkInitialized(ctx); - String from = ctx.getClientIdentity().getId(); - this.transferHelper(ctx, from, to, value); - final Transfer transferEvent = new Transfer(from, to, value); - ctx.getStub().setEvent(TRANSFER_EVENT.getValue(), this.marshal(transferEvent)); - } - - /** - * BalanceOf returns the balance of the given account. - * - * @param ctx the transaction context - * @param owner the owner from which the balance will be retrieved - * @return the account balance - */ - @Transaction(intent = Transaction.TYPE.EVALUATE) - public long BalanceOf(final Context ctx, final String owner) { - // Check contract options are already set first to execute the function - this.checkInitialized(ctx); - ChaincodeStub stub = ctx.getStub(); - CompositeKey balanceKey = stub.createCompositeKey(BALANCE_PREFIX.getValue(), owner); - String balance = stub.getStringState(balanceKey.toString()); - if (stringIsNullOrEmpty(balance)) { - String errorMessage = String.format("Balance of the owner %s not exists", owner); - throw new ChaincodeException(errorMessage, NOT_FOUND.toString()); - } - logger.info(String.format("%s has balance of %s tokens", owner, balance)); - return Long.parseLong(balance); - } - - /** - * ClientAccountBalance returns the balance of the requesting client's account. - * - * @param ctx the transaction context - * @return client the account balance - */ - @Transaction(intent = Transaction.TYPE.EVALUATE) - public long ClientAccountBalance(final Context ctx) { - // Check contract options are already set first to execute the function - this.checkInitialized(ctx); - // Get ID of submitting client identity - ChaincodeStub stub = ctx.getStub(); - String clientAccountID = ctx.getClientIdentity().getId(); - CompositeKey balanceKey = stub.createCompositeKey(BALANCE_PREFIX.getValue(), clientAccountID); - String balanceBytes = stub.getStringState(balanceKey.toString()); - if (stringIsNullOrEmpty(balanceBytes)) { - String errorMessage = String.format("The account %s does not exist", clientAccountID); - throw new ChaincodeException(errorMessage, NOT_FOUND.toString()); - } - long balance = Long.parseLong(balanceBytes); - logger.info(String.format("%s has balance of %d tokens", clientAccountID, balance)); - return balance; - } - - /** - * ClientAccountID returns the id of the requesting client's account. In this implementation, the - * client account ID is the clientId itself. Users can use this function to get their own account - * id, which they can then give to others as the payment address. - * - * @return client account id . - */ - @Transaction(intent = Transaction.TYPE.EVALUATE) - public String ClientAccountID(final Context ctx) { - // Check contract options are already set first to execute the function - this.checkInitialized(ctx); - // Get ID of submitting client identity - return ctx.getClientIdentity().getId(); - } - - /** - * Return the total token supply. - * - * @param ctx the transaction context - * @return the total token supply - */ - @Transaction(intent = Transaction.TYPE.EVALUATE) - public long TotalSupply(final Context ctx) { - // Check contract options are already set first to execute the function - this.checkInitialized(ctx); - String totalSupply = ctx.getStub().getStringState(TOTAL_SUPPLY_KEY.getValue()); - if (stringIsNullOrEmpty(totalSupply)) { - throw new ChaincodeException("Total Supply not found", NOT_FOUND.toString()); - } - logger.info(String.format("TotalSupply: %s tokens", totalSupply)); - return Long.parseLong(totalSupply); - } - - /** - * Allows `spender` to spend `value` amount of tokens from the owner. - * - * @param ctx the transaction context - * @param spender The spender - * @param value The amount of tokens to be approved for transfer - */ - @Transaction(intent = Transaction.TYPE.SUBMIT) - public void Approve(final Context ctx, final String spender, final long value) { - // Check contract options are already set first to execute the function - this.checkInitialized(ctx); - ChaincodeStub stub = ctx.getStub(); - String owner = ctx.getClientIdentity().getId(); - CompositeKey allowanceKey = - stub.createCompositeKey(ALLOWANCE_PREFIX.getValue(), owner, spender); - stub.putStringState(allowanceKey.toString(), String.valueOf(value)); - Approval approval = new Approval(owner, spender, value); - stub.setEvent(APPROVAL.getValue(), this.marshal(approval)); - logger.info( - String.format( - "client %s approved a withdrawal allowance of %d for spender %s", - owner, value, spender)); - } - - /** - * Returns the amount of tokens which `spender` is allowed to withdraw from `owner`. - * - * @param ctx the transaction context - * @param owner The owner of tokens - * @param spender The spender who are able to transfer the tokens - * @return the amount of remaining tokens allowed to spent - */ - @Transaction(intent = Transaction.TYPE.SUBMIT) - public long Allowance(final Context ctx, final String owner, final String spender) { - // Check contract options are already set first to execute the function - this.checkInitialized(ctx); - ChaincodeStub stub = ctx.getStub(); - CompositeKey allowanceKey = - stub.createCompositeKey(ALLOWANCE_PREFIX.getValue(), owner, spender); - String allowanceBytes = stub.getStringState(allowanceKey.toString()); - long allowance = 0; - if (!stringIsNullOrEmpty(allowanceBytes)) { - allowance = Long.parseLong(allowanceBytes); - } - logger.info( - String.format( - "The allowance left for spender %s to withdraw from owner %s: %d", - spender, owner, allowance)); - return allowance; - } - - /** - * Transfer `value` amount of tokens from `from` to `to`. - * - * @param ctx the transaction context - * @param from The sender - * @param to The recipient - * @param value The amount of token to be transferred - */ - @Transaction(intent = Transaction.TYPE.SUBMIT) - public void TransferFrom( - final Context ctx, final String from, final String to, final long value) { - // Check contract options are already set first to execute the function - this.checkInitialized(ctx); - String spender = ctx.getClientIdentity().getId(); - ChaincodeStub stub = ctx.getStub(); - // Retrieve the allowance of the spender - CompositeKey allowanceKey = stub.createCompositeKey(ALLOWANCE_PREFIX.getValue(), from, spender); - String currentAllowanceStr = stub.getStringState(allowanceKey.toString()); - if (stringIsNullOrEmpty(currentAllowanceStr)) { - String errorMessage = String.format("Spender %s has no allowance from %s", spender, from); - throw new ChaincodeException(errorMessage, NO_ALLOWANCE_FOUND.toString()); - } - long currentAllowance = Long.parseLong(currentAllowanceStr); - // Check if the transferred value is less than the allowance - if (currentAllowance < value) { - String errorMessage = - String.format("Spender %s does not have enough allowance to spend", spender); - throw new ChaincodeException(errorMessage, INSUFFICIENT_FUND.toString()); - } - this.transferHelper(ctx, from, to, value); - // Decrease the allowance - long updatedAllowance = currentAllowance - value; - stub.putStringState(allowanceKey.toString(), String.valueOf(updatedAllowance)); - final Transfer transferEvent = new Transfer(from, to, value); - stub.setEvent(TRANSFER_EVENT.getValue(), marshal(transferEvent)); - logger.info( - String.format( - "spender %s allowance updated from %d to %d", - spender, currentAllowance, updatedAllowance)); - } - - /** - * This is a helper function function that transfers tokens from the "from" address to the "to" - * address. Dependent functions include Transfer and TransferFrom - * - * @param ctx the transaction context - * @param from the sender - * @param to the receiver - * @param value the amount. - */ - private void transferHelper( - final Context ctx, final String from, final String to, final long value) { - - if (from.equalsIgnoreCase(to)) { - throw new ChaincodeException( - "Cannot transfer to and from same client account", INVALID_TRANSFER.toString()); - } - // transfer of 0 is allowed in ERC20, so just validate against negative amounts - if (value < 0) { - throw new ChaincodeException("Transfer amount cannot be negative", INVALID_AMOUNT.toString()); - } - ChaincodeStub stub = ctx.getStub(); - // Retrieve the current balance of the sender - CompositeKey fromBalanceKey = stub.createCompositeKey(BALANCE_PREFIX.getValue(), from); - String fromCurrentBalanceStr = stub.getStringState(fromBalanceKey.toString()); - if (stringIsNullOrEmpty(fromCurrentBalanceStr)) { - String errorMessage = String.format("Client account %s has no balance", from); - throw new ChaincodeException(errorMessage, INSUFFICIENT_FUND.toString()); - } - long fromCurrentBalance = Long.parseLong(fromCurrentBalanceStr); - // Check if the sender has enough tokens to spend. - if (fromCurrentBalance < value) { - String errorMessage = String.format("Client account %s has insufficient funds", from); - throw new ChaincodeException(errorMessage, INSUFFICIENT_FUND.toString()); - } - // Retrieve the current balance of the recipient - CompositeKey toBalanceKey = stub.createCompositeKey(BALANCE_PREFIX.getValue(), to); - String toCurrentBalanceStr = stub.getStringState(toBalanceKey.toString()); - long toCurrentBalance = 0; - // If recipient current balance doesn't yet exist, we'll create it with a - // current balance of 0 - if (!stringIsNullOrEmpty(toCurrentBalanceStr)) { - toCurrentBalance = Long.parseLong(toCurrentBalanceStr.trim()); - } - // Update the balance - long fromUpdatedBalance = Math.subtractExact(fromCurrentBalance, value); - long toUpdatedBalance = Math.addExact(toCurrentBalance, value); - stub.putStringState(fromBalanceKey.toString(), String.valueOf(fromUpdatedBalance)); - stub.putStringState(toBalanceKey.toString(), String.valueOf(toUpdatedBalance)); - logger.info( - String.format( - "client %s balance updated from %d to %d", - from, fromCurrentBalance, fromUpdatedBalance)); - logger.info( - String.format( - "recipient %s balance updated from %d to %d", to, toCurrentBalance, toUpdatedBalance)); - } - - /** - * Set optional information for a token. - * - * @param ctx the transaction context - * @param name The name of the token - * @param symbol The symbol of the token - * @param decimals The decimals of the token - */ - @Transaction(intent = Transaction.TYPE.SUBMIT) - public void Initialize( - final Context ctx, final String name, final String symbol, final String decimals) { - ChaincodeStub stub = ctx.getStub(); - - // Check minter authorization - this sample assumes Org1 is the central banker with privilege to set Options for these tokens - String clientMSPID = ctx.getClientIdentity().getMSPID(); - if (!clientMSPID.equalsIgnoreCase(ContractConstants.MINTER_ORG_MSPID.getValue())) { - throw new ChaincodeException( - "Client is not authorized to initialize contract", UNAUTHORIZED_SENDER.toString()); - } - - // Check contract options are not already set, client is not authorized to change them once intitialized - String tokenName = stub.getStringState(ContractConstants.NAME_KEY.getValue()); - if (!stringIsNullOrEmpty(tokenName)) { - throw new ChaincodeException("contract options are already set, client is not authorized to change them"); - } - - stub.putStringState(NAME_KEY.getValue(), name); - stub.putStringState(SYMBOL_KEY.getValue(), symbol); - stub.putStringState(DECIMALS_KEY.getValue(), decimals); - } - - /** - * Return the name of the token - e.g. "MyToken". The original function name is `name` in ERC20 - * specification. However, 'name' conflicts with a parameter `name` in `Contract` class. As a work - * around, we use `TokenName` as an alternative function name. - * - * @param ctx the transaction context - * @return the name of the token - */ - @Transaction(intent = Transaction.TYPE.EVALUATE) - public String TokenName(final Context ctx) { - // Check contract options are already set first to execute the function - this.checkInitialized(ctx); - String tokenName = ctx.getStub().getStringState(ContractConstants.NAME_KEY.getValue()); - if (stringIsNullOrEmpty(tokenName)) { - throw new ChaincodeException("Token name not found", NOT_FOUND.toString()); - } - return tokenName; - } - - /** - * Return the symbol of the token. - * - * @param ctx the transaction context - * @return the symbol of the token - */ - @Transaction(intent = Transaction.TYPE.EVALUATE) - public String TokenSymbol(final Context ctx) { - // Check contract options are already set first to execute the function - this.checkInitialized(ctx); - String tokenSymbol = ctx.getStub().getStringState(SYMBOL_KEY.getValue()); - if (stringIsNullOrEmpty(tokenSymbol)) { - throw new ChaincodeException("Token symbol not found", NOT_FOUND.toString()); - } - return tokenSymbol; - } - - /** - * Return the number of decimals the token uses e.g. 8, means to divide the token amount by - * 100000000 to get its user representation. - * - * @param ctx the transaction context - * @return the number of decimals - */ - @Transaction(intent = Transaction.TYPE.EVALUATE) - public int Decimals(final Context ctx) { - // Check contract options are already set first to execute the function - this.checkInitialized(ctx); - String decimals = ctx.getStub().getStringState(DECIMALS_KEY.getValue()); - if (stringIsNullOrEmpty(decimals)) { - throw new ChaincodeException("Decimal not found", NOT_FOUND.toString()); - } - return Integer.parseInt(decimals); - } - /** - * marshal the event data - * - * @param obj the object to marshal. - * @return marshalled object. - */ - private byte[] marshal(final Object obj) { - return new Genson().serialize(obj).getBytes(UTF_8); - } - - /** - * Checks that contract options have been already initialized - * - * @param ctx the transaction context - * @return the number of decimals - */ - private void checkInitialized(final Context ctx) { - String tokenName = ctx.getStub().getStringState(ContractConstants.NAME_KEY.getValue()); - if (stringIsNullOrEmpty(tokenName)) { - throw new ChaincodeException("Contract options need to be set before calling any function, call Initialize() to initialize contract", NOT_FOUND.toString()); - } - } -} diff --git a/token-erc-20/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc20/model/Approval.java b/token-erc-20/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc20/model/Approval.java deleted file mode 100644 index c8226475..00000000 --- a/token-erc-20/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc20/model/Approval.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.fabric.samples.erc20.model; - -import com.owlike.genson.annotation.JsonProperty; -import org.hyperledger.fabric.contract.annotation.DataType; -import org.hyperledger.fabric.contract.annotation.Property; - -@DataType() -public final class Approval { - - @Property() - @JsonProperty("owner") - private String owner; - - @Property() - @JsonProperty("spender") - private String spender; - - @Property() - @JsonProperty("value") - private long value; - - /** Default constructor */ - public Approval() { - super(); - } - - /** - * Constructor of the class - * - * @param owner token owner - * @param spender approved spender of the token - * @param value amount approved as allowance - */ - public Approval( - @JsonProperty("owner") final String owner, - @JsonProperty("spender") final String spender, - @JsonProperty("value") final long value) { - super(); - this.owner = owner; - this.spender = spender; - this.value = value; - } - - public String getOwner() { - return owner; - } - - public String getSpender() { - return spender; - } - - public long getValue() { - return value; - } -} diff --git a/token-erc-20/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc20/model/Transfer.java b/token-erc-20/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc20/model/Transfer.java deleted file mode 100644 index 0e7275c6..00000000 --- a/token-erc-20/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc20/model/Transfer.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.fabric.samples.erc20.model; - -import com.owlike.genson.annotation.JsonProperty; -import org.hyperledger.fabric.contract.annotation.DataType; -import org.hyperledger.fabric.contract.annotation.Property; - -@DataType() -public final class Transfer { - - @Property() - @JsonProperty("from") - private String from; - - @Property() - @JsonProperty("to") - private String to; - - @Property() - @JsonProperty("value") - private long value; - - /** Default constructor */ - public Transfer() { - super(); - } - - /** - * Constructor of the class - * - * @param from owner of the token - * @param to token receiver - * @param value amount to be transferred - */ - public Transfer( - @JsonProperty("from") final String from, - @JsonProperty("to") final String to, - @JsonProperty("value") final long value) { - super(); - this.from = from; - this.to = to; - this.value = value; - } - - public String getFrom() { - return from; - } - - public String getTo() { - return to; - } - - public long getValue() { - return value; - } -} diff --git a/token-erc-20/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc20/utils/ContractUtility.java b/token-erc-20/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc20/utils/ContractUtility.java deleted file mode 100644 index bf952314..00000000 --- a/token-erc-20/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc20/utils/ContractUtility.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.fabric.samples.erc20.utils; -/** - * @author Renjith - * @Desc Utility class - */ - -public final class ContractUtility { - - private ContractUtility() { - } - - - public static boolean stringIsNullOrEmpty(final String string) { - return string == null || string.isEmpty(); - } -} diff --git a/token-erc-20/chaincode-java/src/test/java/org/hyperledger/fabric/samples/erc20/TokenERC20ContractTest.java b/token-erc-20/chaincode-java/src/test/java/org/hyperledger/fabric/samples/erc20/TokenERC20ContractTest.java deleted file mode 100644 index 716a8513..00000000 --- a/token-erc-20/chaincode-java/src/test/java/org/hyperledger/fabric/samples/erc20/TokenERC20ContractTest.java +++ /dev/null @@ -1,590 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.fabric.samples.erc20; - -import org.hyperledger.fabric.contract.ClientIdentity; -import org.hyperledger.fabric.contract.Context; -import org.hyperledger.fabric.shim.ChaincodeException; -import org.hyperledger.fabric.shim.ChaincodeStub; -import org.hyperledger.fabric.shim.ledger.CompositeKey; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.catchThrowable; -import static org.hyperledger.fabric.samples.erc20.ContractConstants.ALLOWANCE_PREFIX; -import static org.hyperledger.fabric.samples.erc20.ContractConstants.BALANCE_PREFIX; -import static org.hyperledger.fabric.samples.erc20.ContractConstants.DECIMALS_KEY; -import static org.hyperledger.fabric.samples.erc20.ContractConstants.MINTER_ORG_MSPID; -import static org.hyperledger.fabric.samples.erc20.ContractConstants.NAME_KEY; -import static org.hyperledger.fabric.samples.erc20.ContractConstants.SYMBOL_KEY; -import static org.hyperledger.fabric.samples.erc20.ContractConstants.TOTAL_SUPPLY_KEY; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -public class TokenERC20ContractTest { - - private final String org1UserId = - "x509::CN=User0@org1.example.com, L=San Francisco, ST=California," - + " C=US::CN=ca.org2.example.com, O=org2.example.com, L=San Francisco, ST=California, C=US"; - private final String spender = - "x509::CN=User1@org2.example.com, L=San Francisco, ST=California," - + " C=US::CN=ca.org2.example.com, O=org2.example.com, L=San Francisco, ST=California, C=US"; - - @Nested - class InvokeQueryERC20TokenOptionsTransaction { - - @Test - public void whenTokenNameExists() { - ERC20TokenContract contract = new ERC20TokenContract(); - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - when(ctx.getStub()).thenReturn(stub); - when(stub.getStringState(NAME_KEY.getValue())).thenReturn("ARBTToken"); - String tokenName = contract.TokenName(ctx); - assertThat(tokenName).isEqualTo("ARBTToken"); - } - - @Test - public void whenTokenNameDoesNotExist() { - ERC20TokenContract contract = new ERC20TokenContract(); - final Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - when(ctx.getStub()).thenReturn(stub); - when(stub.getStringState(NAME_KEY.getValue())).thenReturn(""); - Throwable thrown = catchThrowable(() -> contract.TokenName(ctx)); - assertThat(thrown) - .isInstanceOf(ChaincodeException.class) - .hasNoCause() - .hasMessage("Contract options need to be set before calling any function, call Initialize() to initialize contract"); - } - - @Test - public void whenTokenSymbolExists() { - ERC20TokenContract contract = new ERC20TokenContract(); - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - when(ctx.getStub()).thenReturn(stub); - when(stub.getStringState(NAME_KEY.getValue())).thenReturn("ARBTToken"); - when(stub.getStringState(SYMBOL_KEY.getValue())).thenReturn("ARBT"); - String toknName = contract.TokenSymbol(ctx); - assertThat(toknName).isEqualTo("ARBT"); - } - - @Test - public void whenTokenSymbolDoesNotExist() { - ERC20TokenContract contract = new ERC20TokenContract(); - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - when(ctx.getStub()).thenReturn(stub); - when(stub.getStringState(NAME_KEY.getValue())).thenReturn("ARBTToken"); - when(stub.getStringState(SYMBOL_KEY.getValue())).thenReturn(""); - Throwable thrown = catchThrowable(() -> contract.TokenSymbol(ctx)); - assertThat(thrown) - .isInstanceOf(ChaincodeException.class) - .hasNoCause() - .hasMessage("Token symbol not found"); - } - - @Test - public void whenTokenDecimalExists() { - ERC20TokenContract contract = new ERC20TokenContract(); - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - when(ctx.getStub()).thenReturn(stub); - when(stub.getStringState(NAME_KEY.getValue())).thenReturn("ARBTToken"); - when(stub.getStringState(DECIMALS_KEY.getValue())).thenReturn("18"); - long decimal = contract.Decimals(ctx); - assertThat(decimal).isEqualTo(18); - } - - @Test - public void whenTokenDecimalNotExists() { - ERC20TokenContract contract = new ERC20TokenContract(); - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - when(ctx.getStub()).thenReturn(stub); - when(stub.getStringState(NAME_KEY.getValue())).thenReturn("ARBTToken"); - when(stub.getStringState(DECIMALS_KEY.getValue())).thenReturn(""); - Throwable thrown = catchThrowable(() -> contract.Decimals(ctx)); - assertThat(thrown) - .isInstanceOf(ChaincodeException.class) - .hasNoCause() - .hasMessage("Decimal not found"); - } - - @Test - public void whenTokenTotalSupplyExists() { - ERC20TokenContract contract = new ERC20TokenContract(); - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - when(ctx.getStub()).thenReturn(stub); - when(stub.getStringState(NAME_KEY.getValue())).thenReturn("ARBTToken"); - when(stub.getStringState(TOTAL_SUPPLY_KEY.getValue())).thenReturn("222222222222"); - long totalSupply = contract.TotalSupply(ctx); - assertThat(totalSupply).isEqualTo(222222222222L); - } - - @Test - public void whenTokenTotalSupplyNotExists() { - ERC20TokenContract contract = new ERC20TokenContract(); - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - when(ctx.getStub()).thenReturn(stub); - when(stub.getStringState(NAME_KEY.getValue())).thenReturn("ARBTToken"); - when(stub.getStringState(TOTAL_SUPPLY_KEY.getValue())).thenReturn(""); - Throwable thrown = catchThrowable(() -> contract.TotalSupply(ctx)); - assertThat(thrown) - .isInstanceOf(ChaincodeException.class) - .hasNoCause() - .hasMessage("Total Supply not found"); - } - - @Test - public void ClientAccountIDTest() { - ERC20TokenContract contract = new ERC20TokenContract(); - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - ClientIdentity ci = mock(ClientIdentity.class); - when(ctx.getClientIdentity()).thenReturn(ci); - when(stub.getStringState(NAME_KEY.getValue())).thenReturn("ARBTToken"); - when(ci.getMSPID()).thenReturn(MINTER_ORG_MSPID.getValue()); - when(ci.getId()).thenReturn(org1UserId); - when(ctx.getStub()).thenReturn(stub); - assertThat(ci.getMSPID()).isEqualTo(MINTER_ORG_MSPID.getValue()); - String id = contract.ClientAccountID(ctx); - assertThat(id).isEqualTo(org1UserId); - } - } - - @Nested - class TokenOperationsInvoke { - - @Test - public void invokeInitializeTest() { - ERC20TokenContract contract = new ERC20TokenContract(); - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - when(ctx.getStub()).thenReturn(stub); - ClientIdentity ci = mock(ClientIdentity.class); - when(ctx.getClientIdentity()).thenReturn(ci); - when(ci.getMSPID()).thenReturn(MINTER_ORG_MSPID.getValue()); - contract.Initialize(ctx, "ARBTToken", "ARBT", "18"); - verify(stub).putStringState(NAME_KEY.getValue(), "ARBTToken"); - verify(stub).putStringState(SYMBOL_KEY.getValue(), "ARBT"); - verify(stub).putStringState(DECIMALS_KEY.getValue(), "18"); - } - - @Test - public void invokeBalanceOfTest() { - ERC20TokenContract contract = new ERC20TokenContract(); - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - when(ctx.getStub()).thenReturn(stub); - when(stub.getStringState(NAME_KEY.getValue())).thenReturn("ARBTToken"); - ClientIdentity ci = mock(ClientIdentity.class); - when(ctx.getClientIdentity()).thenReturn(ci); - when(ci.getMSPID()).thenReturn(MINTER_ORG_MSPID.getValue()); - when(ci.getId()).thenReturn(org1UserId); - when(ctx.getStub()).thenReturn(stub); - CompositeKey ck = mock(CompositeKey.class); - when(stub.createCompositeKey(BALANCE_PREFIX.getValue(), org1UserId)).thenReturn(ck); - when(ck.toString()).thenReturn(BALANCE_PREFIX.getValue() + org1UserId); - when(stub.getStringState(ck.toString())).thenReturn("1000"); - long balance = contract.BalanceOf(ctx, org1UserId); - assertThat(balance).isEqualTo(1000); - } - - @Test - public void invokeClientAccountBalanceTest() { - ERC20TokenContract contract = new ERC20TokenContract(); - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - when(ctx.getStub()).thenReturn(stub); - when(stub.getStringState(NAME_KEY.getValue())).thenReturn("ARBTToken"); - ClientIdentity ci = mock(ClientIdentity.class); - when(ctx.getClientIdentity()).thenReturn(ci); - when(ci.getMSPID()).thenReturn(MINTER_ORG_MSPID.getValue()); - when(ci.getId()).thenReturn(org1UserId); - when(ctx.getStub()).thenReturn(stub); - CompositeKey ck = mock(CompositeKey.class); - when(stub.createCompositeKey(BALANCE_PREFIX.getValue(), org1UserId)).thenReturn(ck); - when(ck.toString()).thenReturn(BALANCE_PREFIX.getValue() + org1UserId); - when(stub.getStringState(ck.toString())).thenReturn("1000"); - long balance = contract.ClientAccountBalance(ctx); - assertThat(balance).isEqualTo(1000); - } - - @Test - public void invokeMintTokenTest() { - - ERC20TokenContract contract = new ERC20TokenContract(); - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - ClientIdentity ci = mock(ClientIdentity.class); - when(ctx.getClientIdentity()).thenReturn(ci); - when(stub.getStringState(NAME_KEY.getValue())).thenReturn("ARBTToken"); - when(ci.getMSPID()).thenReturn(MINTER_ORG_MSPID.getValue()); - when(ci.getId()).thenReturn(org1UserId); - when(ctx.getStub()).thenReturn(stub); - CompositeKey ck = mock(CompositeKey.class); - when(stub.createCompositeKey(BALANCE_PREFIX.getValue(), org1UserId)).thenReturn(ck); - when(ck.toString()).thenReturn(BALANCE_PREFIX.getValue() + org1UserId); - when(stub.getStringState(ck.toString())).thenReturn(null); - when(ctx.getStub()).thenReturn(stub); - contract.Mint(ctx, 1000); - verify(stub).putStringState(TOTAL_SUPPLY_KEY.getValue(), "1000"); - verify(stub).putStringState(ck.toString(), "1000"); - } - - @Test - public void whenMintTokenUnAuthorized() { - - ERC20TokenContract contract = new ERC20TokenContract(); - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - ClientIdentity ci = mock(ClientIdentity.class); - when(ctx.getClientIdentity()).thenReturn(ci); - when(stub.getStringState(NAME_KEY.getValue())).thenReturn("ARBTToken"); - when(ci.getMSPID()).thenReturn("Org2MSP"); - when(ci.getId()).thenReturn(org1UserId); - when(ctx.getStub()).thenReturn(stub); - CompositeKey ck = mock(CompositeKey.class); - when(stub.createCompositeKey(BALANCE_PREFIX.getValue(), org1UserId)).thenReturn(ck); - when(ck.toString()).thenReturn(BALANCE_PREFIX.getValue() + org1UserId); - when(stub.getStringState(ck.toString())).thenReturn(null); - when(ctx.getStub()).thenReturn(stub); - Throwable thrown = catchThrowable(() -> contract.Mint(ctx, 1000)); - assertThat(thrown) - .isInstanceOf(ChaincodeException.class) - .hasNoCause() - .hasMessage("Client is not authorized to mint new tokens"); - } - - @Test - public void invokeTokenTransferTest() { - - ERC20TokenContract contract = new ERC20TokenContract(); - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - ClientIdentity ci = mock(ClientIdentity.class); - when(stub.getStringState(NAME_KEY.getValue())).thenReturn("ARBTToken"); - when(ctx.getClientIdentity()).thenReturn(ci); - when(ci.getMSPID()).thenReturn(MINTER_ORG_MSPID.getValue()); - when(ci.getId()).thenReturn(org1UserId); - when(ctx.getStub()).thenReturn(stub); - String to = - "x509::CN=User2@org2.example.com, L=San Francisco, ST=California," - + " C=US::CN=ca.org2.example.com, O=org2.example.com, L=San Francisco, ST=California, C=US"; - - CompositeKey ckFrom = mock(CompositeKey.class); - when(stub.createCompositeKey(BALANCE_PREFIX.getValue(), org1UserId)).thenReturn(ckFrom); - when(ckFrom.toString()).thenReturn(BALANCE_PREFIX.getValue() + org1UserId); - when(stub.getStringState(ckFrom.toString())).thenReturn("1000"); - CompositeKey ckTo = mock(CompositeKey.class); - when(stub.createCompositeKey(BALANCE_PREFIX.getValue(), to)).thenReturn(ckTo); - when(ckTo.toString()).thenReturn(BALANCE_PREFIX.getValue() + to); - when(stub.getStringState(ckTo.toString())).thenReturn(null); - contract.Transfer(ctx, to, 100); - verify(stub).putStringState(ckTo.toString(), "100"); - verify(stub).putStringState(ckFrom.toString(), "900"); - } - - @Test - public void whenZeroAmountTokenTransferTest() { - - ERC20TokenContract contract = new ERC20TokenContract(); - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - ClientIdentity ci = mock(ClientIdentity.class); - when(stub.getStringState(NAME_KEY.getValue())).thenReturn("ARBTToken"); - when(ctx.getClientIdentity()).thenReturn(ci); - when(ci.getMSPID()).thenReturn(MINTER_ORG_MSPID.getValue()); - when(ci.getId()).thenReturn(org1UserId); - when(ctx.getStub()).thenReturn(stub); - String to = - "x509::CN=User2@org2.example.com, L=San Francisco, ST=California," - + " C=US::CN=ca.org2.example.com, O=org2.example.com, L=San Francisco, ST=California, C=US"; - - CompositeKey ckFrom = mock(CompositeKey.class); - when(stub.createCompositeKey(BALANCE_PREFIX.getValue(), org1UserId)).thenReturn(ckFrom); - when(ckFrom.toString()).thenReturn(BALANCE_PREFIX.getValue() + org1UserId); - when(stub.getStringState(ckFrom.toString())).thenReturn("1000"); - CompositeKey ckTo = mock(CompositeKey.class); - when(stub.createCompositeKey(BALANCE_PREFIX.getValue(), to)).thenReturn(ckTo); - when(ckTo.toString()).thenReturn(BALANCE_PREFIX.getValue() + to); - when(stub.getStringState(ckTo.toString())).thenReturn(null); - contract.Transfer(ctx, to, 0); - verify(stub).putStringState(ckTo.toString(), "0"); - verify(stub).putStringState(ckFrom.toString(), "1000"); - } - - @Test - public void whenTokenTransferNegativeAmount() { - - ERC20TokenContract contract = new ERC20TokenContract(); - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - ClientIdentity ci = mock(ClientIdentity.class); - when(stub.getStringState(NAME_KEY.getValue())).thenReturn("ARBTToken"); - when(ctx.getClientIdentity()).thenReturn(ci); - when(ci.getMSPID()).thenReturn(MINTER_ORG_MSPID.getValue()); - when(ci.getId()).thenReturn(org1UserId); - when(ctx.getStub()).thenReturn(stub); - String to = - "x509::CN=User2@org2.example.com, L=San Francisco, ST=California," - + " C=US::CN=ca.org2.example.com, O=org2.example.com, L=San Francisco, ST=California, C=US"; - - CompositeKey ckFrom = mock(CompositeKey.class); - when(stub.createCompositeKey(BALANCE_PREFIX.getValue(), org1UserId)).thenReturn(ckFrom); - when(ckFrom.toString()).thenReturn(BALANCE_PREFIX.getValue() + org1UserId); - when(stub.getStringState(ckFrom.toString())).thenReturn("1000"); - CompositeKey ckTo = mock(CompositeKey.class); - when(stub.createCompositeKey(BALANCE_PREFIX.getValue(), to)).thenReturn(ckTo); - when(ckTo.toString()).thenReturn(BALANCE_PREFIX.getValue() + to); - when(stub.getStringState(ckTo.toString())).thenReturn(null); - - Throwable thrown = catchThrowable(() -> contract.Transfer(ctx, to, -1)); - assertThat(thrown) - .isInstanceOf(ChaincodeException.class) - .hasNoCause() - .hasMessage("Transfer amount cannot be negative"); - } - - @Test - public void whenTokenTransferSameId() { - - ERC20TokenContract contract = new ERC20TokenContract(); - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - ClientIdentity ci = mock(ClientIdentity.class); - when(stub.getStringState(NAME_KEY.getValue())).thenReturn("ARBTToken"); - when(ctx.getClientIdentity()).thenReturn(ci); - when(ci.getMSPID()).thenReturn(MINTER_ORG_MSPID.getValue()); - when(ci.getId()).thenReturn(org1UserId); - when(ctx.getStub()).thenReturn(stub); - String to = - "x509::CN=User2@org2.example.com, L=San Francisco, ST=California," - + " C=US::CN=ca.org2.example.com, O=org2.example.com, L=San Francisco, ST=California, C=US"; - - CompositeKey ckFrom = mock(CompositeKey.class); - when(stub.createCompositeKey(BALANCE_PREFIX.getValue(), org1UserId)).thenReturn(ckFrom); - when(ckFrom.toString()).thenReturn(BALANCE_PREFIX.getValue() + org1UserId); - when(stub.getStringState(ckFrom.toString())).thenReturn("1000"); - CompositeKey ckTo = mock(CompositeKey.class); - when(stub.createCompositeKey(BALANCE_PREFIX.getValue(), to)).thenReturn(ckTo); - when(ckTo.toString()).thenReturn(BALANCE_PREFIX.getValue() + to); - when(stub.getStringState(ckTo.toString())).thenReturn(null); - - Throwable thrown = catchThrowable(() -> contract.Transfer(ctx, org1UserId, 10)); - assertThat(thrown) - .isInstanceOf(ChaincodeException.class) - .hasNoCause() - .hasMessage("Cannot transfer to and from same client account"); - } - - @Test - public void invokeTokenBurnTest() { - - ERC20TokenContract contract = new ERC20TokenContract(); - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - ClientIdentity ci = mock(ClientIdentity.class); - when(stub.getStringState(NAME_KEY.getValue())).thenReturn("ARBTToken"); - when(ctx.getClientIdentity()).thenReturn(ci); - when(ci.getMSPID()).thenReturn(MINTER_ORG_MSPID.getValue()); - when(ci.getId()).thenReturn(org1UserId); - CompositeKey ck = mock(CompositeKey.class); - when(stub.createCompositeKey(BALANCE_PREFIX.getValue(), org1UserId)).thenReturn(ck); - when(ck.toString()).thenReturn(BALANCE_PREFIX.getValue() + org1UserId); - when(stub.getStringState(ck.toString())).thenReturn(null); - when(ctx.getStub()).thenReturn(stub); - when(stub.getStringState(TOTAL_SUPPLY_KEY.getValue())).thenReturn("1000"); - when(stub.getStringState(ck.toString())).thenReturn("1000"); - contract.Burn(ctx, 100); - verify(stub).putStringState(TOTAL_SUPPLY_KEY.getValue(), "900"); - } - - @Test - public void whenTokenBurnUnAuthorizedTest() { - ERC20TokenContract contract = new ERC20TokenContract(); - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - ClientIdentity ci = mock(ClientIdentity.class); - when(stub.getStringState(NAME_KEY.getValue())).thenReturn("ARBTToken"); - when(ctx.getClientIdentity()).thenReturn(ci); - when(ci.getMSPID()).thenReturn("Org2MSP"); - when(ci.getId()).thenReturn(spender); - CompositeKey ck = mock(CompositeKey.class); - when(stub.createCompositeKey(BALANCE_PREFIX.getValue(), spender)).thenReturn(ck); - when(ck.toString()).thenReturn(BALANCE_PREFIX.getValue() + spender); - when(stub.getStringState(ck.toString())).thenReturn(null); - when(ctx.getStub()).thenReturn(stub); - when(stub.getStringState(TOTAL_SUPPLY_KEY.getValue())).thenReturn("1000"); - when(stub.getStringState(ck.toString())).thenReturn("1000"); - - Throwable thrown = catchThrowable(() -> contract.Burn(ctx, 100)); - assertThat(thrown) - .isInstanceOf(ChaincodeException.class) - .hasNoCause() - .hasMessage("Client is not authorized to burn tokens"); - } - - @Test - public void whenTokenBurnNegativeAmountTest() { - ERC20TokenContract contract = new ERC20TokenContract(); - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - ClientIdentity ci = mock(ClientIdentity.class); - when(stub.getStringState(NAME_KEY.getValue())).thenReturn("ARBTToken"); - when(ctx.getClientIdentity()).thenReturn(ci); - when(ci.getMSPID()).thenReturn("Org1MSP"); - when(ci.getId()).thenReturn(org1UserId); - CompositeKey ck = mock(CompositeKey.class); - when(stub.createCompositeKey(BALANCE_PREFIX.getValue(), org1UserId)).thenReturn(ck); - when(ck.toString()).thenReturn(BALANCE_PREFIX.getValue() + org1UserId); - when(stub.getStringState(ck.toString())).thenReturn(null); - when(ctx.getStub()).thenReturn(stub); - when(stub.getStringState(TOTAL_SUPPLY_KEY.getValue())).thenReturn("1000"); - when(stub.getStringState(ck.toString())).thenReturn("1000"); - - Throwable thrown = catchThrowable(() -> contract.Burn(ctx, -100)); - assertThat(thrown) - .isInstanceOf(ChaincodeException.class) - .hasNoCause() - .hasMessage("Burn amount must be a positive integer"); - } - } - - @Nested - class InvokeERC20AllowanceTransactions { - - @Test - public void invokeAllowanceTest() { - ERC20TokenContract contract = new ERC20TokenContract(); - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - ClientIdentity ci = mock(ClientIdentity.class); - when(stub.getStringState(NAME_KEY.getValue())).thenReturn("ARBTToken"); - when(ctx.getClientIdentity()).thenReturn(ci); - when(ci.getMSPID()).thenReturn(MINTER_ORG_MSPID.getValue()); - when(ci.getId()).thenReturn(org1UserId); - when(ctx.getStub()).thenReturn(stub); - CompositeKey ck = mock(CompositeKey.class); - when(stub.createCompositeKey(ALLOWANCE_PREFIX.getValue(), org1UserId, spender)) - .thenReturn(ck); - when(ck.toString()).thenReturn(ALLOWANCE_PREFIX.getValue() + org1UserId + spender); - when(stub.getStringState(ck.toString())).thenReturn("100"); - long allowance = contract.Allowance(ctx, org1UserId, spender); - assertThat(allowance).isEqualTo(100); - } - - @Test - public void invokeApproveForTokenAllowanceTest() { - ERC20TokenContract contract = new ERC20TokenContract(); - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - ClientIdentity ci = mock(ClientIdentity.class); - when(stub.getStringState(NAME_KEY.getValue())).thenReturn("ARBTToken"); - when(ctx.getClientIdentity()).thenReturn(ci); - when(ci.getMSPID()).thenReturn(MINTER_ORG_MSPID.getValue()); - when(ci.getId()).thenReturn(org1UserId); - when(ctx.getStub()).thenReturn(stub); - CompositeKey ck = mock(CompositeKey.class); - when(stub.createCompositeKey(ALLOWANCE_PREFIX.getValue(), org1UserId, spender)) - .thenReturn(ck); - when(ck.toString()).thenReturn(ALLOWANCE_PREFIX.getValue() + org1UserId + spender); - contract.Approve(ctx, spender, 200); - verify(stub).putStringState(ck.toString(), String.valueOf(200)); - } - - @Test - public void invokeAllowanceTransferFromTest() { - ERC20TokenContract contract = new ERC20TokenContract(); - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - ClientIdentity ci; - - String to = - "x509::CN=User3@org2.example.com, L=San Francisco, ST=California," - + " C=US::CN=ca.org2.example.com, O=org2.example.com, L=San Francisco, ST=California, C=US"; - - CompositeKey ckFromBalance = mock(CompositeKey.class); - when(stub.getStringState(NAME_KEY.getValue())).thenReturn("ARBTToken"); - when(stub.createCompositeKey(BALANCE_PREFIX.toString(), org1UserId)) - .thenReturn(ckFromBalance); - when(ckFromBalance.toString()).thenReturn(BALANCE_PREFIX.getValue() + org1UserId); - CompositeKey ckTOBalance = mock(CompositeKey.class); - when(stub.createCompositeKey(BALANCE_PREFIX.toString(), to)).thenReturn(ckTOBalance); - when(ckFromBalance.toString()).thenReturn(BALANCE_PREFIX.getValue() + to); - when(ctx.getStub()).thenReturn(stub); - ci = mock(ClientIdentity.class); - when(ctx.getClientIdentity()).thenReturn(ci); - when(ci.getMSPID()).thenReturn("Org2MSP"); - when(ci.getId()).thenReturn(spender); - CompositeKey ckAllowance = mock(CompositeKey.class); - when(stub.createCompositeKey(ALLOWANCE_PREFIX.getValue(), org1UserId, spender)) - .thenReturn(ckAllowance); - when(ckAllowance.toString()).thenReturn(ALLOWANCE_PREFIX.getValue() + org1UserId + spender); - when(stub.getStringState(ckAllowance.toString())).thenReturn("200"); - CompositeKey ckFrom = mock(CompositeKey.class); - when(stub.createCompositeKey(BALANCE_PREFIX.getValue(), org1UserId)).thenReturn(ckFrom); - when(ckFrom.toString()).thenReturn(BALANCE_PREFIX.getValue() + org1UserId); - when(stub.getStringState(ckFrom.toString())).thenReturn("1000"); - CompositeKey ckTo = mock(CompositeKey.class); - when(stub.createCompositeKey(BALANCE_PREFIX.getValue(), to)).thenReturn(ckTo); - when(ckTo.toString()).thenReturn(BALANCE_PREFIX.getValue() + to); - when(stub.getStringState(ckTo.toString())).thenReturn(null); - contract.TransferFrom(ctx, org1UserId, to, 100); - verify(stub).putStringState(ckTo.toString(), String.valueOf(100)); - verify(stub).putStringState(ckFrom.toString(), String.valueOf(900)); - } - - @Test - public void whenClientSameAllowanceTransferFrom() { - ERC20TokenContract contract = new ERC20TokenContract(); - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - ClientIdentity ci; - String to = - "x509::CN=User3@org2.example.com, L=San Francisco, ST=California," - + " C=US::CN=ca.org2.example.com, O=org2.example.com, L=San Francisco, ST=California, C=US"; - - CompositeKey ckFromBalance = mock(CompositeKey.class); - when(stub.getStringState(NAME_KEY.getValue())).thenReturn("ARBTToken"); - when(stub.createCompositeKey(BALANCE_PREFIX.getValue(), org1UserId)) - .thenReturn(ckFromBalance); - when(ckFromBalance.toString()).thenReturn(BALANCE_PREFIX.getValue() + org1UserId); - CompositeKey ckTOBalance = mock(CompositeKey.class); - when(stub.createCompositeKey(BALANCE_PREFIX.getValue(), to)).thenReturn(ckTOBalance); - when(ckFromBalance.toString()).thenReturn(BALANCE_PREFIX.getValue() + to); - when(ctx.getStub()).thenReturn(stub); - ci = mock(ClientIdentity.class); - when(ctx.getClientIdentity()).thenReturn(ci); - when(ci.getMSPID()).thenReturn("Org2MSP"); - when(ci.getId()).thenReturn(spender); - CompositeKey ckAllowance = mock(CompositeKey.class); - when(stub.createCompositeKey(ALLOWANCE_PREFIX.getValue(), org1UserId, spender)) - .thenReturn(ckAllowance); - when(ckAllowance.toString()).thenReturn(ALLOWANCE_PREFIX.getValue() + org1UserId + spender); - when(stub.getStringState(ckAllowance.toString())).thenReturn("200"); - CompositeKey ckFrom = mock(CompositeKey.class); - when(stub.createCompositeKey(BALANCE_PREFIX.getValue(), org1UserId)).thenReturn(ckFrom); - when(ckFrom.toString()).thenReturn(BALANCE_PREFIX.getValue() + org1UserId); - when(stub.getStringState(ckFrom.toString())).thenReturn("1000"); - CompositeKey ckTo = mock(CompositeKey.class); - when(stub.createCompositeKey(BALANCE_PREFIX.getValue(), to)).thenReturn(ckTo); - when(ckTo.toString()).thenReturn(BALANCE_PREFIX.getValue() + to); - when(stub.getStringState(ckTo.toString())).thenReturn(null); - - Throwable thrown = - catchThrowable(() -> contract.TransferFrom(ctx, org1UserId, org1UserId, 100)); - assertThat(thrown) - .isInstanceOf(ChaincodeException.class) - .hasNoCause() - .hasMessage("Cannot transfer to and from same client account"); - } - } -} diff --git a/token-erc-20/chaincode-java/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/token-erc-20/chaincode-java/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker deleted file mode 100644 index ca6ee9ce..00000000 --- a/token-erc-20/chaincode-java/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker +++ /dev/null @@ -1 +0,0 @@ -mock-maker-inline \ No newline at end of file diff --git a/token-erc-20/chaincode-javascript/.editorconfig b/token-erc-20/chaincode-javascript/.editorconfig deleted file mode 100755 index 75a13be2..00000000 --- a/token-erc-20/chaincode-javascript/.editorconfig +++ /dev/null @@ -1,16 +0,0 @@ -# -# SPDX-License-Identifier: Apache-2.0 -# - -root = true - -[*] -indent_style = space -indent_size = 4 -end_of_line = lf -charset = utf-8 -trim_trailing_whitespace = true -insert_final_newline = true - -[*.md] -trim_trailing_whitespace = false diff --git a/token-erc-20/chaincode-javascript/.eslintignore b/token-erc-20/chaincode-javascript/.eslintignore deleted file mode 100644 index 15958470..00000000 --- a/token-erc-20/chaincode-javascript/.eslintignore +++ /dev/null @@ -1,5 +0,0 @@ -# -# SPDX-License-Identifier: Apache-2.0 -# - -coverage diff --git a/token-erc-20/chaincode-javascript/.eslintrc.js b/token-erc-20/chaincode-javascript/.eslintrc.js deleted file mode 100644 index 8d99762d..00000000 --- a/token-erc-20/chaincode-javascript/.eslintrc.js +++ /dev/null @@ -1,39 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ - -module.exports = { - env: { - node: true, - es6: true, - mocha: true - }, - parserOptions: { - ecmaVersion: 8, - sourceType: 'script' - }, - extends: "eslint:recommended", - rules: { - indent: ['error', 4], - 'linebreak-style': ['error', 'unix'], - quotes: ['error', 'single'], - semi: ['error', 'always'], - 'no-unused-vars': ['error', { args: 'none' }], - 'no-console': 'off', - curly: 'error', - eqeqeq: 'error', - 'no-throw-literal': 'error', - strict: 'error', - 'no-var': 'error', - 'dot-notation': 'error', - 'no-tabs': 'error', - 'no-trailing-spaces': 'error', - 'no-use-before-define': 'error', - 'no-useless-call': 'error', - 'no-with': 'error', - 'operator-linebreak': 'error', - yoda: 'error', - 'quote-props': ['error', 'as-needed'], - 'no-constant-condition': ["error", { "checkLoops": false }] - } -}; diff --git a/token-erc-20/chaincode-javascript/.gitignore b/token-erc-20/chaincode-javascript/.gitignore deleted file mode 100644 index c84ff1db..00000000 --- a/token-erc-20/chaincode-javascript/.gitignore +++ /dev/null @@ -1,78 +0,0 @@ -# -# SPDX-License-Identifier: Apache-2.0 -# - -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (https://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules/ -jspm_packages/ -package-lock.json - -# TypeScript v1 declaration files -typings/ - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variables file -.env - -# parcel-bundler cache (https://parceljs.org/) -.cache - -# next.js build output -.next - -# nuxt.js build output -.nuxt - -# vuepress build output -.vuepress/dist - -# Serverless directories -.serverless diff --git a/token-erc-20/chaincode-javascript/index.js b/token-erc-20/chaincode-javascript/index.js deleted file mode 100644 index 6509d17e..00000000 --- a/token-erc-20/chaincode-javascript/index.js +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 -*/ - -'use strict'; - -const tokenERC20Contract = require('./lib/tokenERC20.js'); - -module.exports.TokenERC20Contract = tokenERC20Contract; -module.exports.contracts = [tokenERC20Contract]; diff --git a/token-erc-20/chaincode-javascript/lib/tokenERC20.js b/token-erc-20/chaincode-javascript/lib/tokenERC20.js deleted file mode 100644 index cb4ef244..00000000 --- a/token-erc-20/chaincode-javascript/lib/tokenERC20.js +++ /dev/null @@ -1,503 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 -*/ - -'use strict'; - -const { Contract } = require('fabric-contract-api'); - -// Define objectType names for prefix -const balancePrefix = 'balance'; -const allowancePrefix = 'allowance'; - -// Define key names for options -const nameKey = 'name'; -const symbolKey = 'symbol'; -const decimalsKey = 'decimals'; -const totalSupplyKey = 'totalSupply'; - -class TokenERC20Contract extends Contract { - - /** - * Return the name of the token - e.g. "MyToken". - * The original function name is `name` in ERC20 specification. - * However, 'name' conflicts with a parameter `name` in `Contract` class. - * As a work around, we use `TokenName` as an alternative function name. - * - * @param {Context} ctx the transaction context - * @returns {String} Returns the name of the token - */ - async TokenName(ctx) { - - // Check contract options are already set first to execute the function - await this.CheckInitialized(ctx); - - const nameBytes = await ctx.stub.getState(nameKey); - - return nameBytes.toString(); - } - - /** - * Return the symbol of the token. E.g. “HIX”. - * - * @param {Context} ctx the transaction context - * @returns {String} Returns the symbol of the token - */ - async Symbol(ctx) { - - // Check contract options are already set first to execute the function - await this.CheckInitialized(ctx); - - const symbolBytes = await ctx.stub.getState(symbolKey); - return symbolBytes.toString(); - } - - /** - * Return the number of decimals the token uses - * e.g. 8, means to divide the token amount by 100000000 to get its user representation. - * - * @param {Context} ctx the transaction context - * @returns {Number} Returns the number of decimals - */ - async Decimals(ctx) { - - // Check contract options are already set first to execute the function - await this.CheckInitialized(ctx); - - const decimalsBytes = await ctx.stub.getState(decimalsKey); - const decimals = parseInt(decimalsBytes.toString()); - return decimals; - } - - /** - * Return the total token supply. - * - * @param {Context} ctx the transaction context - * @returns {Number} Returns the total token supply - */ - async TotalSupply(ctx) { - - // Check contract options are already set first to execute the function - await this.CheckInitialized(ctx); - - const totalSupplyBytes = await ctx.stub.getState(totalSupplyKey); - const totalSupply = parseInt(totalSupplyBytes.toString()); - return totalSupply; - } - - /** - * BalanceOf returns the balance of the given account. - * - * @param {Context} ctx the transaction context - * @param {String} owner The owner from which the balance will be retrieved - * @returns {Number} Returns the account balance - */ - async BalanceOf(ctx, owner) { - - // Check contract options are already set first to execute the function - await this.CheckInitialized(ctx); - - const balanceKey = ctx.stub.createCompositeKey(balancePrefix, [owner]); - - const balanceBytes = await ctx.stub.getState(balanceKey); - if (!balanceBytes || balanceBytes.length === 0) { - throw new Error(`the account ${owner} does not exist`); - } - const balance = parseInt(balanceBytes.toString()); - - return balance; - } - - /** - * Transfer transfers tokens from client account to recipient account. - * recipient account must be a valid clientID as returned by the ClientAccountID() function. - * - * @param {Context} ctx the transaction context - * @param {String} to The recipient - * @param {Integer} value The amount of token to be transferred - * @returns {Boolean} Return whether the transfer was successful or not - */ - async Transfer(ctx, to, value) { - - // Check contract options are already set first to execute the function - await this.CheckInitialized(ctx); - - const from = ctx.clientIdentity.getID(); - - const transferResp = await this._transfer(ctx, from, to, value); - if (!transferResp) { - throw new Error('Failed to transfer'); - } - - // Emit the Transfer event - const transferEvent = { from, to, value: parseInt(value) }; - ctx.stub.setEvent('Transfer', Buffer.from(JSON.stringify(transferEvent))); - - return true; - } - - /** - * Transfer `value` amount of tokens from `from` to `to`. - * - * @param {Context} ctx the transaction context - * @param {String} from The sender - * @param {String} to The recipient - * @param {Integer} value The amount of token to be transferred - * @returns {Boolean} Return whether the transfer was successful or not - */ - async TransferFrom(ctx, from, to, value) { - - // Check contract options are already set first to execute the function - await this.CheckInitialized(ctx); - - const spender = ctx.clientIdentity.getID(); - - // Retrieve the allowance of the spender - const allowanceKey = ctx.stub.createCompositeKey(allowancePrefix, [from, spender]); - const currentAllowanceBytes = await ctx.stub.getState(allowanceKey); - - if (!currentAllowanceBytes || currentAllowanceBytes.length === 0) { - throw new Error(`spender ${spender} has no allowance from ${from}`); - } - - const currentAllowance = parseInt(currentAllowanceBytes.toString()); - - // Convert value from string to int - const valueInt = parseInt(value); - - // Check if the transferred value is less than the allowance - if (currentAllowance < valueInt) { - throw new Error('The spender does not have enough allowance to spend.'); - } - - const transferResp = await this._transfer(ctx, from, to, value); - if (!transferResp) { - throw new Error('Failed to transfer'); - } - - // Decrease the allowance - const updatedAllowance = this.sub(currentAllowance, valueInt); - await ctx.stub.putState(allowanceKey, Buffer.from(updatedAllowance.toString())); - console.log(`spender ${spender} allowance updated from ${currentAllowance} to ${updatedAllowance}`); - - // Emit the Transfer event - const transferEvent = { from, to, value: valueInt }; - ctx.stub.setEvent('Transfer', Buffer.from(JSON.stringify(transferEvent))); - - console.log('transferFrom ended successfully'); - return true; - } - - async _transfer(ctx, from, to, value) { - - if (from === to) { - throw new Error('cannot transfer to and from same client account'); - } - - // Convert value from string to int - const valueInt = parseInt(value); - - if (valueInt < 0) { // transfer of 0 is allowed in ERC20, so just validate against negative amounts - throw new Error('transfer amount cannot be negative'); - } - - // Retrieve the current balance of the sender - const fromBalanceKey = ctx.stub.createCompositeKey(balancePrefix, [from]); - const fromCurrentBalanceBytes = await ctx.stub.getState(fromBalanceKey); - - if (!fromCurrentBalanceBytes || fromCurrentBalanceBytes.length === 0) { - throw new Error(`client account ${from} has no balance`); - } - - const fromCurrentBalance = parseInt(fromCurrentBalanceBytes.toString()); - - // Check if the sender has enough tokens to spend. - if (fromCurrentBalance < valueInt) { - throw new Error(`client account ${from} has insufficient funds.`); - } - - // Retrieve the current balance of the recepient - const toBalanceKey = ctx.stub.createCompositeKey(balancePrefix, [to]); - const toCurrentBalanceBytes = await ctx.stub.getState(toBalanceKey); - - let toCurrentBalance; - // If recipient current balance doesn't yet exist, we'll create it with a current balance of 0 - if (!toCurrentBalanceBytes || toCurrentBalanceBytes.length === 0) { - toCurrentBalance = 0; - } else { - toCurrentBalance = parseInt(toCurrentBalanceBytes.toString()); - } - - // Update the balance - const fromUpdatedBalance = this.sub(fromCurrentBalance, valueInt); - const toUpdatedBalance = this.add(toCurrentBalance, valueInt); - - await ctx.stub.putState(fromBalanceKey, Buffer.from(fromUpdatedBalance.toString())); - await ctx.stub.putState(toBalanceKey, Buffer.from(toUpdatedBalance.toString())); - - console.log(`client ${from} balance updated from ${fromCurrentBalance} to ${fromUpdatedBalance}`); - console.log(`recipient ${to} balance updated from ${toCurrentBalance} to ${toUpdatedBalance}`); - - return true; - } - - /** - * Allows `spender` to spend `value` amount of tokens from the owner. - * - * @param {Context} ctx the transaction context - * @param {String} spender The spender - * @param {Integer} value The amount of tokens to be approved for transfer - * @returns {Boolean} Return whether the approval was successful or not - */ - async Approve(ctx, spender, value) { - - // Check contract options are already set first to execute the function - await this.CheckInitialized(ctx); - - const owner = ctx.clientIdentity.getID(); - - const allowanceKey = ctx.stub.createCompositeKey(allowancePrefix, [owner, spender]); - - let valueInt = parseInt(value); - await ctx.stub.putState(allowanceKey, Buffer.from(valueInt.toString())); - - // Emit the Approval event - const approvalEvent = { owner, spender, value: valueInt }; - ctx.stub.setEvent('Approval', Buffer.from(JSON.stringify(approvalEvent))); - - console.log('approve ended successfully'); - return true; - } - - /** - * Returns the amount of tokens which `spender` is allowed to withdraw from `owner`. - * - * @param {Context} ctx the transaction context - * @param {String} owner The owner of tokens - * @param {String} spender The spender who are able to transfer the tokens - * @returns {Number} Return the amount of remaining tokens allowed to spent - */ - async Allowance(ctx, owner, spender) { - - // Check contract options are already set first to execute the function - await this.CheckInitialized(ctx); - - const allowanceKey = ctx.stub.createCompositeKey(allowancePrefix, [owner, spender]); - - const allowanceBytes = await ctx.stub.getState(allowanceKey); - if (!allowanceBytes || allowanceBytes.length === 0) { - throw new Error(`spender ${spender} has no allowance from ${owner}`); - } - - const allowance = parseInt(allowanceBytes.toString()); - return allowance; - } - - // ================== Extended Functions ========================== - - /** - * Set optional infomation for a token. - * - * @param {Context} ctx the transaction context - * @param {String} name The name of the token - * @param {String} symbol The symbol of the token - * @param {String} decimals The decimals of the token - * @param {String} totalSupply The totalSupply of the token - */ - async Initialize(ctx, name, symbol, decimals) { - // Check minter authorization - this sample assumes Org1 is the central banker with privilege to set Options for these tokens - const clientMSPID = ctx.clientIdentity.getMSPID(); - if (clientMSPID !== 'Org1MSP') { - throw new Error('client is not authorized to initialize contract'); - } - - // Check contract options are not already set, client is not authorized to change them once intitialized - const nameBytes = await ctx.stub.getState(nameKey); - if (nameBytes && nameBytes.length > 0) { - throw new Error('contract options are already set, client is not authorized to change them'); - } - - await ctx.stub.putState(nameKey, Buffer.from(name)); - await ctx.stub.putState(symbolKey, Buffer.from(symbol)); - await ctx.stub.putState(decimalsKey, Buffer.from(decimals)); - - console.log(`name: ${name}, symbol: ${symbol}, decimals: ${decimals}`); - return true; - } - - /** - * Mint creates new tokens and adds them to minter's account balance - * - * @param {Context} ctx the transaction context - * @param {Integer} amount amount of tokens to be minted - * @returns {Object} The balance - */ - async Mint(ctx, amount) { - - // Check contract options are already set first to execute the function - await this.CheckInitialized(ctx); - - // Check minter authorization - this sample assumes Org1 is the central banker with privilege to mint new tokens - const clientMSPID = ctx.clientIdentity.getMSPID(); - if (clientMSPID !== 'Org1MSP') { - throw new Error('client is not authorized to mint new tokens'); - } - - // Get ID of submitting client identity - const minter = ctx.clientIdentity.getID(); - - const amountInt = parseInt(amount); - if (amountInt <= 0) { - throw new Error('mint amount must be a positive integer'); - } - - const balanceKey = ctx.stub.createCompositeKey(balancePrefix, [minter]); - - const currentBalanceBytes = await ctx.stub.getState(balanceKey); - // If minter current balance doesn't yet exist, we'll create it with a current balance of 0 - let currentBalance; - if (!currentBalanceBytes || currentBalanceBytes.length === 0) { - currentBalance = 0; - } else { - currentBalance = parseInt(currentBalanceBytes.toString()); - } - const updatedBalance = this.add(currentBalance, amountInt); - - await ctx.stub.putState(balanceKey, Buffer.from(updatedBalance.toString())); - - // Increase totalSupply - const totalSupplyBytes = await ctx.stub.getState(totalSupplyKey); - let totalSupply; - if (!totalSupplyBytes || totalSupplyBytes.length === 0) { - console.log('Initialize the tokenSupply'); - totalSupply = 0; - } else { - totalSupply = parseInt(totalSupplyBytes.toString()); - } - totalSupply = this.add(totalSupply, amountInt); - await ctx.stub.putState(totalSupplyKey, Buffer.from(totalSupply.toString())); - - // Emit the Transfer event - const transferEvent = { from: '0x0', to: minter, value: amountInt }; - ctx.stub.setEvent('Transfer', Buffer.from(JSON.stringify(transferEvent))); - - console.log(`minter account ${minter} balance updated from ${currentBalance} to ${updatedBalance}`); - return true; - } - - /** - * Burn redeem tokens from minter's account balance - * - * @param {Context} ctx the transaction context - * @param {Integer} amount amount of tokens to be burned - * @returns {Object} The balance - */ - async Burn(ctx, amount) { - - // Check contract options are already set first to execute the function - await this.CheckInitialized(ctx); - - // Check minter authorization - this sample assumes Org1 is the central banker with privilege to burn tokens - const clientMSPID = ctx.clientIdentity.getMSPID(); - if (clientMSPID !== 'Org1MSP') { - throw new Error('client is not authorized to mint new tokens'); - } - - const minter = ctx.clientIdentity.getID(); - - const amountInt = parseInt(amount); - - const balanceKey = ctx.stub.createCompositeKey(balancePrefix, [minter]); - - const currentBalanceBytes = await ctx.stub.getState(balanceKey); - if (!currentBalanceBytes || currentBalanceBytes.length === 0) { - throw new Error('The balance does not exist'); - } - const currentBalance = parseInt(currentBalanceBytes.toString()); - const updatedBalance = this.sub(currentBalance, amountInt); - - await ctx.stub.putState(balanceKey, Buffer.from(updatedBalance.toString())); - - // Decrease totalSupply - const totalSupplyBytes = await ctx.stub.getState(totalSupplyKey); - if (!totalSupplyBytes || totalSupplyBytes.length === 0) { - throw new Error('totalSupply does not exist.'); - } - const totalSupply = this.sub(parseInt(totalSupplyBytes.toString()), amountInt); - await ctx.stub.putState(totalSupplyKey, Buffer.from(totalSupply.toString())); - - // Emit the Transfer event - const transferEvent = { from: minter, to: '0x0', value: amountInt }; - ctx.stub.setEvent('Transfer', Buffer.from(JSON.stringify(transferEvent))); - - console.log(`minter account ${minter} balance updated from ${currentBalance} to ${updatedBalance}`); - return true; - } - - /** - * ClientAccountBalance returns the balance of the requesting client's account. - * - * @param {Context} ctx the transaction context - * @returns {Number} Returns the account balance - */ - async ClientAccountBalance(ctx) { - - // Check contract options are already set first to execute the function - await this.CheckInitialized(ctx); - - // Get ID of submitting client identity - const clientAccountID = ctx.clientIdentity.getID(); - - const balanceKey = ctx.stub.createCompositeKey(balancePrefix, [clientAccountID]); - const balanceBytes = await ctx.stub.getState(balanceKey); - if (!balanceBytes || balanceBytes.length === 0) { - throw new Error(`the account ${clientAccountID} does not exist`); - } - const balance = parseInt(balanceBytes.toString()); - - return balance; - } - - // ClientAccountID returns the id of the requesting client's account. - // In this implementation, the client account ID is the clientId itself. - // Users can use this function to get their own account id, which they can then give to others as the payment address - async ClientAccountID(ctx) { - - // Check contract options are already set first to execute the function - await this.CheckInitialized(ctx); - - // Get ID of submitting client identity - const clientAccountID = ctx.clientIdentity.getID(); - return clientAccountID; - } - - // Checks that contract options have been already initialized - async CheckInitialized(ctx){ - const nameBytes = await ctx.stub.getState(nameKey); - if (!nameBytes || nameBytes.length === 0) { - throw new Error('contract options need to be set before calling any function, call Initialize() to initialize contract'); - } - } - - // add two number checking for overflow - add(a, b) { - let c = a + b; - if (a !== c - b || b !== c - a){ - throw new Error(`Math: addition overflow occurred ${a} + ${b}`); - } - return c; - } - - // add two number checking for overflow - sub(a, b) { - let c = a - b; - if (a !== c + b || b !== a - c){ - throw new Error(`Math: subtraction overflow occurred ${a} - ${b}`); - } - return c; - } -} - -module.exports = TokenERC20Contract; diff --git a/token-erc-20/chaincode-javascript/npm-shrinkwrap.json b/token-erc-20/chaincode-javascript/npm-shrinkwrap.json deleted file mode 100644 index a032b1e2..00000000 --- a/token-erc-20/chaincode-javascript/npm-shrinkwrap.json +++ /dev/null @@ -1,4396 +0,0 @@ -{ - "name": "token-erc20", - "version": "0.0.1", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "token-erc20", - "version": "0.0.1", - "license": "Apache-2.0", - "dependencies": { - "fabric-contract-api": "~2.5", - "fabric-shim": "~2.5" - }, - "devDependencies": { - "chai": "^4.1.2", - "chai-as-promised": "^7.1.1", - "eslint": "^4.19.1", - "mocha": "^8.0.1", - "nyc": "^14.1.1", - "sinon": "^6.0.0", - "sinon-chai": "^3.2.0" - }, - "engines": { - "node": ">=12", - "npm": ">=5" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", - "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.24.7", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/generator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.7.tgz", - "integrity": "sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.24.7", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", - "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", - "dev": true, - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz", - "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==", - "dev": true, - "dependencies": { - "@babel/template": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz", - "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==", - "dev": true, - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", - "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz", - "integrity": "sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", - "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", - "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.24.7", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight/node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/@babel/parser": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.7.tgz", - "integrity": "sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/template": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz", - "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.7.tgz", - "integrity": "sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.7", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-hoist-variables": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/types": "^7.24.7", - "debug": "^4.3.1", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@babel/traverse/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/@babel/types": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz", - "integrity": "sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@colors/colors": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", - "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/@dabh/diagnostics": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", - "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", - "dependencies": { - "colorspace": "1.1.x", - "enabled": "2.0.x", - "kuler": "^2.0.0" - } - }, - "node_modules/@fidm/asn1": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@fidm/asn1/-/asn1-1.0.4.tgz", - "integrity": "sha512-esd1jyNvRb2HVaQGq2Gg8Z0kbQPXzV9Tq5Z14KNIov6KfFD6PTaRIO8UpcsYiTNzOqJpmyzWgVTrUwFV3UF4TQ==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@fidm/x509": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@fidm/x509/-/x509-1.2.1.tgz", - "integrity": "sha512-nwc2iesjyc9hkuzcrMCBXQRn653XuAUKorfWM8PZyJawiy1QzLj4vahwzaI25+pfpwOLvMzbJ0uKpWLDNmo16w==", - "dependencies": { - "@fidm/asn1": "^1.0.4", - "tweetnacl": "^1.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@grpc/grpc-js": { - "version": "1.10.9", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.10.9.tgz", - "integrity": "sha512-5tcgUctCG0qoNyfChZifz2tJqbRbXVO9J7X6duFcOjY3HUNCxg5D0ZCK7EP9vIcZ0zRpLU9bWkyCqVCLZ46IbQ==", - "dependencies": { - "@grpc/proto-loader": "^0.7.13", - "@js-sdsl/ordered-map": "^4.4.2" - }, - "engines": { - "node": ">=12.10.0" - } - }, - "node_modules/@grpc/proto-loader": { - "version": "0.7.13", - "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.13.tgz", - "integrity": "sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw==", - "dependencies": { - "lodash.camelcase": "^4.3.0", - "long": "^5.0.0", - "protobufjs": "^7.2.5", - "yargs": "^17.7.2" - }, - "bin": { - "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@hyperledger/fabric-protos": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@hyperledger/fabric-protos/-/fabric-protos-0.2.1.tgz", - "integrity": "sha512-qjm0vIQIfCall804tWDeA8p/mUfu14sl5Sj+PbOn2yDKJq+7ThoIhNsLAqf+BCxUfqsoqQq6AojhqQeTFyOOqg==", - "dependencies": { - "@grpc/grpc-js": "^1.9.0", - "google-protobuf": "^3.21.0" - }, - "engines": { - "node": ">=14.15.0" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@js-sdsl/ordered-map": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz", - "integrity": "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/js-sdsl" - } - }, - "node_modules/@protobufjs/aspromise": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" - }, - "node_modules/@protobufjs/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" - }, - "node_modules/@protobufjs/codegen": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" - }, - "node_modules/@protobufjs/eventemitter": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" - }, - "node_modules/@protobufjs/fetch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", - "dependencies": { - "@protobufjs/aspromise": "^1.1.1", - "@protobufjs/inquire": "^1.1.0" - } - }, - "node_modules/@protobufjs/float": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" - }, - "node_modules/@protobufjs/inquire": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" - }, - "node_modules/@protobufjs/path": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" - }, - "node_modules/@protobufjs/pool": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" - }, - "node_modules/@protobufjs/utf8": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" - }, - "node_modules/@sinonjs/commons": { - "version": "1.8.6", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", - "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", - "dev": true, - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/formatio": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.2.2.tgz", - "integrity": "sha512-B8SEsgd8gArBLMD6zpRw3juQ2FVSsmdd7qlevyDqzS9WTCtvF55/gAL+h6gue8ZvPYcdiPdvueM/qm//9XzyTQ==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^1", - "@sinonjs/samsam": "^3.1.0" - } - }, - "node_modules/@sinonjs/formatio/node_modules/@sinonjs/samsam": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.3.3.tgz", - "integrity": "sha512-bKCMKZvWIjYD0BLGnNrxVuw4dkWCYsLqFOUWw8VgKF/+5Y+mE7LfHWPIYoDXowH+3a9LsWDMo0uAP8YDosPvHQ==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^1.3.0", - "array-from": "^2.1.1", - "lodash": "^4.17.15" - } - }, - "node_modules/@sinonjs/samsam": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-2.1.3.tgz", - "integrity": "sha512-8zNeBkSKhU9a5cRNbpCKau2WWPfan+Q2zDlcXvXyhn9EsMqgYs4qzo0XHNVlXC6ABQL8fT6nV+zzo5RTHJzyXw==", - "dev": true - }, - "node_modules/@sinonjs/text-encoding": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz", - "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", - "dev": true - }, - "node_modules/@types/node": { - "version": "16.18.98", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.98.tgz", - "integrity": "sha512-fpiC20NvLpTLAzo3oVBKIqBGR6Fx/8oAK/SSf7G+fydnXMY1x4x9RZ6sBXhqKlCU21g2QapUsbLlhv3+a7wS+Q==" - }, - "node_modules/@types/triple-beam": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", - "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==" - }, - "node_modules/@ungap/promise-all-settled": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", - "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", - "dev": true - }, - "node_modules/acorn": { - "version": "5.7.4", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", - "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", - "integrity": "sha512-AU7pnZkguthwBjKgCg6998ByQNIMjbuDQZ8bb78QAFZwPfmKia8AIzgY/gWgqCjnht8JLdXmB4YxA0KaV60ncQ==", - "dev": true, - "dependencies": { - "acorn": "^3.0.4" - } - }, - "node_modules/acorn-jsx/node_modules/acorn": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", - "integrity": "sha512-OLUyIIZ7mF5oaAUT1w0TFqQS81q3saT46x8t7ukpPjMNk+nbs4ZHhs7ToV8EWnLYLepjETXd4XaCE4uxkMeqUw==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/ajv": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", - "integrity": "sha512-Ajr4IcMXq/2QmMkEmSvxqfLN5zGmJ92gHXAeOXq1OekoH2rfDNsgdDoL2f7QaRCy7G/E6TpxBVdRuNraMztGHw==", - "dev": true, - "dependencies": { - "co": "^4.6.0", - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" - } - }, - "node_modules/ajv-keywords": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz", - "integrity": "sha512-ZFztHzVRdGLAzJmpUT9LNFLe1YiVOEylcaNpEutM26PVTCtOD919IMfD01CgbRouB42Dd9atjx1HseC15DgOZA==", - "dev": true, - "peerDependencies": { - "ajv": "^5.0.0" - } - }, - "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/ansi-regex": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", - "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/append-transform": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-1.0.0.tgz", - "integrity": "sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==", - "dev": true, - "dependencies": { - "default-require-extensions": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/archy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", - "dev": true - }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/array-from": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", - "integrity": "sha512-GQTc6Uupx1FCavi5mPzBvVT7nEOeWMmUA9P95wpfpW1XwMSKs+KaymD5C2Up7KAUKg/mYwbsUYzdZWcoajlNZg==", - "dev": true - }, - "node_modules/assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/async": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", - "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" - }, - "node_modules/babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha512-XqYMR2dfdGMW+hd0IUZ2PwK+fGeFkOxZJ0wY+JaQAHzt1Zx8LcvpiZD2NiGkEG8qx0CfkAOr5xt76d1e8vG90g==", - "dev": true, - "dependencies": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" - } - }, - "node_modules/babel-code-frame/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/babel-code-frame/node_modules/ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/babel-code-frame/node_modules/chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", - "dev": true, - "dependencies": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/babel-code-frame/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/babel-code-frame/node_modules/supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "node_modules/caching-transform": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-3.0.2.tgz", - "integrity": "sha512-Mtgcv3lh3U0zRii/6qVgQODdPA4G3zhG+jtbCWj39RXuUFTMzH0vcdMtaJS1jPowd+It2Pqr6y3NJMQqOqCE2w==", - "dev": true, - "dependencies": { - "hasha": "^3.0.0", - "make-dir": "^2.0.0", - "package-hash": "^3.0.0", - "write-file-atomic": "^2.4.2" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/caller-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", - "integrity": "sha512-UJiE1otjXPF5/x+T3zTnSFiTOEmJoGTD9HmBoxnCUwho61a2eSNn/VwtwuIBDAo2SEOv1AJ7ARI5gCmohFLu/g==", - "dev": true, - "dependencies": { - "callsites": "^0.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/callsites": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", - "integrity": "sha512-Zv4Dns9IbXXmPkgRRUjAaJQgfN4xX5p6+RQFhWUqscdvvK2xK/ZL8b3IXIJsj+4sD+f24NwnWy2BY8AJ82JB0A==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/chai": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz", - "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==", - "dev": true, - "dependencies": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.3", - "deep-eql": "^4.1.3", - "get-func-name": "^2.0.2", - "loupe": "^2.3.6", - "pathval": "^1.1.1", - "type-detect": "^4.0.8" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chai-as-promised": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.2.tgz", - "integrity": "sha512-aBDHZxRzYnUYuIAIPBH2s511DjlKPzXNlXSGFC8CwmroWQLfrW0LtE1nK3MAwwNhJPa9raEjNCmRoFpG0Hurdw==", - "dev": true, - "dependencies": { - "check-error": "^1.0.2" - }, - "peerDependencies": { - "chai": ">= 2.1.2 < 6" - } - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chardet": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", - "integrity": "sha512-j/Toj7f1z98Hh2cYo2BVr85EpIRWqUi7rtRSGxh/cqUjqrnJe9l9UE7IUGd2vQ2p+kSHLkSzObQPZPLUC6TQwg==", - "dev": true - }, - "node_modules/check-error": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", - "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", - "dev": true, - "dependencies": { - "get-func-name": "^2.0.2" - }, - "engines": { - "node": "*" - } - }, - "node_modules/chokidar": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", - "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", - "dev": true, - "dependencies": { - "anymatch": "~3.1.1", - "braces": "~3.0.2", - "glob-parent": "~5.1.0", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.5.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.1" - } - }, - "node_modules/circular-json": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", - "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", - "deprecated": "CircularJSON is in maintenance only, flatted is its successor.", - "dev": true - }, - "node_modules/class-transformer": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.4.0.tgz", - "integrity": "sha512-ETWD/H2TbWbKEi7m9N4Km5+cw1hNcqJSxlSYhsLsNjQzWWiZIYA1zafxpK9PwVfaZ6AqR5rrjPVUBGESm5tQUA==" - }, - "node_modules/cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==", - "dev": true, - "dependencies": { - "restore-cursor": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/cli-width": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", - "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", - "dev": true - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/cliui/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", - "dev": true, - "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" - } - }, - "node_modules/color": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", - "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", - "dependencies": { - "color-convert": "^1.9.3", - "color-string": "^1.6.0" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "node_modules/color-string": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", - "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", - "dependencies": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } - }, - "node_modules/colorspace": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", - "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", - "dependencies": { - "color": "^3.1.3", - "text-hex": "1.0.x" - } - }, - "node_modules/commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "dev": true, - "engines": [ - "node >= 0.8" - ], - "dependencies": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true - }, - "node_modules/cp-file": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/cp-file/-/cp-file-6.2.0.tgz", - "integrity": "sha512-fmvV4caBnofhPe8kOcitBwSn2f39QLjnAnGq3gO9dfd75mUytzKNZB1hde6QHunW2Rt+OwuBOMc3i1tNElbszA==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "make-dir": "^2.0.0", - "nested-error-stacks": "^2.0.0", - "pify": "^4.0.1", - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==", - "dev": true, - "dependencies": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/deep-eql": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", - "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", - "dev": true, - "dependencies": { - "type-detect": "^4.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/default-require-extensions": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-2.0.0.tgz", - "integrity": "sha512-B0n2zDIXpzLzKeoEozorDSa1cHc1t0NjmxP0zuAxbizNU2MBqYJJKYXrrFdKuQliojXynrxgd7l4ahfg/+aA5g==", - "dev": true, - "dependencies": { - "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "node_modules/enabled": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", - "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es6-error": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", - "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", - "dev": true - }, - "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/eslint": { - "version": "4.19.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz", - "integrity": "sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ==", - "dev": true, - "dependencies": { - "ajv": "^5.3.0", - "babel-code-frame": "^6.22.0", - "chalk": "^2.1.0", - "concat-stream": "^1.6.0", - "cross-spawn": "^5.1.0", - "debug": "^3.1.0", - "doctrine": "^2.1.0", - "eslint-scope": "^3.7.1", - "eslint-visitor-keys": "^1.0.0", - "espree": "^3.5.4", - "esquery": "^1.0.0", - "esutils": "^2.0.2", - "file-entry-cache": "^2.0.0", - "functional-red-black-tree": "^1.0.1", - "glob": "^7.1.2", - "globals": "^11.0.1", - "ignore": "^3.3.3", - "imurmurhash": "^0.1.4", - "inquirer": "^3.0.6", - "is-resolvable": "^1.0.0", - "js-yaml": "^3.9.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.4", - "minimatch": "^3.0.2", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "optionator": "^0.8.2", - "path-is-inside": "^1.0.2", - "pluralize": "^7.0.0", - "progress": "^2.0.0", - "regexpp": "^1.0.1", - "require-uncached": "^1.0.3", - "semver": "^5.3.0", - "strip-ansi": "^4.0.0", - "strip-json-comments": "~2.0.1", - "table": "4.0.2", - "text-table": "~0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-scope": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.3.tgz", - "integrity": "sha512-W+B0SvF4gamyCTmUc+uITPY0989iXVfKvhwtmJocTaYoc/3khEHmEmvfY/Gn9HA9VV75jrQECsHizkNw1b68FA==", - "dev": true, - "dependencies": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/espree": { - "version": "3.5.4", - "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", - "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", - "dev": true, - "dependencies": { - "acorn": "^5.5.0", - "acorn-jsx": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/external-editor": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", - "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", - "dev": true, - "dependencies": { - "chardet": "^0.4.0", - "iconv-lite": "^0.4.17", - "tmp": "^0.0.33" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/fabric-contract-api": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/fabric-contract-api/-/fabric-contract-api-2.5.6.tgz", - "integrity": "sha512-AosGb8tA+Jgt+pqMEgYNB3/J/P5QuWOC7yhXbhDmAAwUzn4Sc7pdWDICH1YyrFGZNFxMGQmqJmLVWUX8BKHy0w==", - "dependencies": { - "class-transformer": "^0.4.0", - "fabric-shim-api": "2.5.6", - "fast-safe-stringify": "^2.1.1", - "get-params": "^0.1.2", - "reflect-metadata": "^0.1.13", - "winston": "^3.7.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/fabric-shim": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/fabric-shim/-/fabric-shim-2.5.6.tgz", - "integrity": "sha512-4Y8WNFhYuQ9QYSEgPXWdlXnrXjwOlM10sQQzE4kJ7cDh8a4LX0rn44FxtxTCB18lnzrSLMZ8/8Cr5m0c9NeXWA==", - "dependencies": { - "@fidm/x509": "^1.2.1", - "@grpc/grpc-js": "~1.10.9", - "@hyperledger/fabric-protos": "~0.2.1", - "@types/node": "^16.11.1", - "ajv": "^6.12.2", - "fabric-contract-api": "2.5.6", - "fabric-shim-api": "2.5.6", - "fast-safe-stringify": "^2.1.1", - "long": "^5.2.3", - "reflect-metadata": "^0.1.13", - "winston": "^3.7.2", - "yargs": "^17.4.0", - "yargs-parser": "^21.0.1" - }, - "bin": { - "fabric-chaincode-node": "cli.js" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/fabric-shim-api": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/fabric-shim-api/-/fabric-shim-api-2.5.6.tgz", - "integrity": "sha512-1L0nO7CJ31/gEOWKWHEeCqgB5HkqPVfRbpcS7L9eTscT7tffjg2OkZISvC+a7RiqihL0iyrXNBgBg5MwlSSN9g==", - "engines": { - "eslint": "^6.6.0", - "node": ">=18" - } - }, - "node_modules/fabric-shim/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/fabric-shim/node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "node_modules/fabric-shim/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "node_modules/fast-deep-equal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", - "integrity": "sha512-fueX787WZKCV0Is4/T2cyAdM4+x1S3MXXOAhavE1ys/W42SHAPacLTQhucja22QBYrfGw50M2sRiXPtTGv9Ymw==", - "dev": true - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fast-safe-stringify": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", - "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==" - }, - "node_modules/fecha": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", - "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" - }, - "node_modules/figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/file-entry-cache": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", - "integrity": "sha512-uXP/zGzxxFvFfcZGgBIwotm+Tdc55ddPAzF7iHshP4YGaXMww7rSF9peD9D1sui5ebONg5UobsZv+FfgEpGv/w==", - "dev": true, - "dependencies": { - "flat-cache": "^1.2.1", - "object-assign": "^4.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-cache-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", - "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", - "dev": true, - "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^2.0.0", - "pkg-dir": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true, - "bin": { - "flat": "cli.js" - } - }, - "node_modules/flat-cache": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz", - "integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==", - "dev": true, - "dependencies": { - "circular-json": "^0.3.1", - "graceful-fs": "^4.1.2", - "rimraf": "~2.6.2", - "write": "^0.2.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fn.name": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", - "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" - }, - "node_modules/foreground-child": { - "version": "1.5.6", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-1.5.6.tgz", - "integrity": "sha512-3TOY+4TKV0Ml83PXJQY+JFQaHNV38lzQDIzzXYg1kWdBLenGgoZhAs0CKgzI31vi2pWEpQMq/Yi4bpKwCPkw7g==", - "dev": true, - "dependencies": { - "cross-spawn": "^4", - "signal-exit": "^3.0.0" - } - }, - "node_modules/foreground-child/node_modules/cross-spawn": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", - "integrity": "sha512-yAXz/pA1tD8Gtg2S98Ekf/sewp3Lcp3YoFKJ4Hkp5h5yLWnKVTDU0kwjKJ8NDCYcfTLfyGkzTikst+jWypT1iA==", - "dev": true, - "dependencies": { - "lru-cache": "^4.0.1", - "which": "^1.2.9" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", - "dev": true - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-func-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", - "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/get-params": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/get-params/-/get-params-0.1.2.tgz", - "integrity": "sha512-41eOxtlGgHQRbFyA8KTH+w+32Em3cRdfBud7j67ulzmIfmaHX9doq47s0fa4P5o9H64BZX9nrYI6sJvk46Op+Q==" - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/google-protobuf": { - "version": "3.21.2", - "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.21.2.tgz", - "integrity": "sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA==" - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true - }, - "node_modules/growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", - "dev": true, - "engines": { - "node": ">=4.x" - } - }, - "node_modules/has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-ansi/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/hasha": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hasha/-/hasha-3.0.0.tgz", - "integrity": "sha512-w0Kz8lJFBoyaurBiNrIvxPqr/gJ6fOfSkpAPOepN3oECqGJag37xPbOv57izi/KP8auHgNYxn5fXtAb+1LsJ6w==", - "dev": true, - "dependencies": { - "is-stream": "^1.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, - "bin": { - "he": "bin/he" - } - }, - "node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ignore": { - "version": "3.3.10", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", - "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", - "dev": true - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/inquirer": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", - "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", - "dev": true, - "dependencies": { - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.0", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^2.0.4", - "figures": "^2.0.0", - "lodash": "^4.3.0", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rx-lite": "^4.0.8", - "rx-lite-aggregates": "^4.0.8", - "string-width": "^2.1.0", - "strip-ansi": "^4.0.0", - "through": "^2.3.6" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", - "dev": true, - "dependencies": { - "hasown": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-resolvable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", - "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", - "dev": true - }, - "node_modules/is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/istanbul-lib-coverage": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", - "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/istanbul-lib-hook": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-2.0.7.tgz", - "integrity": "sha512-vrRztU9VRRFDyC+aklfLoeXyNdTfga2EI3udDGn4cZ6fpSXpHLV9X6CHvfoMCPtggg8zvDDmC4b9xfu0z6/llA==", - "dev": true, - "dependencies": { - "append-transform": "^1.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/istanbul-lib-instrument": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz", - "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==", - "dev": true, - "dependencies": { - "@babel/generator": "^7.4.0", - "@babel/parser": "^7.4.3", - "@babel/template": "^7.4.0", - "@babel/traverse": "^7.4.3", - "@babel/types": "^7.4.0", - "istanbul-lib-coverage": "^2.0.5", - "semver": "^6.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/istanbul-lib-report": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz", - "integrity": "sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==", - "dev": true, - "dependencies": { - "istanbul-lib-coverage": "^2.0.5", - "make-dir": "^2.1.0", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/istanbul-lib-report/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", - "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^2.0.5", - "make-dir": "^2.1.0", - "rimraf": "^2.6.3", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/istanbul-lib-source-maps/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/istanbul-lib-source-maps/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/istanbul-reports": { - "version": "2.2.7", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.7.tgz", - "integrity": "sha512-uu1F/L1o5Y6LzPVSVZXNOoD/KXpJue9aeLRd0sM9uMXfZvzomB0WxVamWb5ue8kA2vVWEmW7EG+A5n3f1kqHKg==", - "dev": true, - "dependencies": { - "html-escaper": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha512-RjTcuD4xjtthQkaWH7dFlH85L+QaVtSoOyGdZ3g6HFhS9dFNDfLyqgm2NFe2X6cQpeFmt0452FJjFG5UameExg==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha512-4JD/Ivzg7PoW8NzdrBSr3UFwC9mHgvI7Z6z3QGBsSHgKaRTUDmyZAAKJo2UbG1kUVfS9WS8bi36N49U1xw43DA==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/just-extend": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz", - "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==", - "dev": true - }, - "node_modules/kuler": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", - "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" - }, - "node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", - "dev": true, - "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/load-json-file/node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "node_modules/lodash.camelcase": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" - }, - "node_modules/lodash.flattendeep": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", - "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==", - "dev": true - }, - "node_modules/lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", - "dev": true - }, - "node_modules/log-symbols": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", - "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/log-symbols/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/log-symbols/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/log-symbols/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/log-symbols/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/log-symbols/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/log-symbols/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/logform": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.0.tgz", - "integrity": "sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ==", - "dependencies": { - "@colors/colors": "1.6.0", - "@types/triple-beam": "^1.3.2", - "fecha": "^4.2.0", - "ms": "^2.1.1", - "safe-stable-stringify": "^2.3.1", - "triple-beam": "^1.3.0" - }, - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/lolex": { - "version": "2.7.5", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.7.5.tgz", - "integrity": "sha512-l9x0+1offnKKIzYVjyXU2SiwhXDLekRzKyhnbyldPHvC7BvLPVpdNUNR2KeMAiCN2D/kLNttZgQD5WjSxuBx3Q==", - "dev": true - }, - "node_modules/long": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", - "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" - }, - "node_modules/loupe": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", - "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", - "dev": true, - "dependencies": { - "get-func-name": "^2.0.1" - } - }, - "node_modules/lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dev": true, - "dependencies": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "node_modules/make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, - "dependencies": { - "pify": "^4.0.1", - "semver": "^5.6.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/merge-source-map": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", - "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", - "dev": true, - "dependencies": { - "source-map": "^0.6.1" - } - }, - "node_modules/mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dev": true, - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/mocha": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.4.0.tgz", - "integrity": "sha512-hJaO0mwDXmZS4ghXsvPVriOhsxQ7ofcpQdm8dE+jISUOKopitvnXFQmpRR7jd2K6VBG6E26gU3IAbXXGIbu4sQ==", - "dev": true, - "dependencies": { - "@ungap/promise-all-settled": "1.1.2", - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.1", - "debug": "4.3.1", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.1.6", - "growl": "1.10.5", - "he": "1.2.0", - "js-yaml": "4.0.0", - "log-symbols": "4.0.0", - "minimatch": "3.0.4", - "ms": "2.1.3", - "nanoid": "3.1.20", - "serialize-javascript": "5.0.1", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "which": "2.0.2", - "wide-align": "1.1.3", - "workerpool": "6.1.0", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha" - }, - "engines": { - "node": ">= 10.12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mochajs" - } - }, - "node_modules/mocha/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/mocha/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/mocha/node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/mocha/node_modules/debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/mocha/node_modules/debug/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/mocha/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mocha/node_modules/glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/mocha/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/mocha/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/mocha/node_modules/js-yaml": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", - "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/mocha/node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/mocha/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/mocha/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/mocha/node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mocha/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/mocha/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/mocha/node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mocha/node_modules/yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "node_modules/mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha512-r65nCZhrbXXb6dXOACihYApHw2Q6pV0M3V0PSxd74N0+D8nzAdEAITq2oAjA1jVnKI+tGvEBUpqiMh0+rW6zDQ==", - "dev": true - }, - "node_modules/nanoid": { - "version": "3.1.20", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.20.tgz", - "integrity": "sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw==", - "dev": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/nested-error-stacks": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.1.tgz", - "integrity": "sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw==", - "dev": true - }, - "node_modules/nise": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/nise/-/nise-1.5.3.tgz", - "integrity": "sha512-Ymbac/94xeIrMf59REBPOv0thr+CJVFMhrlAkW/gjCIE58BGQdCj0x7KRCb3yz+Ga2Rz3E9XXSvUyyxqqhjQAQ==", - "dev": true, - "dependencies": { - "@sinonjs/formatio": "^3.2.1", - "@sinonjs/text-encoding": "^0.7.1", - "just-extend": "^4.0.2", - "lolex": "^5.0.1", - "path-to-regexp": "^1.7.0" - } - }, - "node_modules/nise/node_modules/lolex": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-5.1.2.tgz", - "integrity": "sha512-h4hmjAvHTmd+25JSwrtTIuwbKdwg5NzZVRMLn9saij4SZaepCrTCxPr35H/3bjwfMJtN+t3CX8672UIkglz28A==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^1.7.0" - } - }, - "node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nyc": { - "version": "14.1.1", - "resolved": "https://registry.npmjs.org/nyc/-/nyc-14.1.1.tgz", - "integrity": "sha512-OI0vm6ZGUnoGZv/tLdZ2esSVzDwUC88SNs+6JoSOMVxA+gKMB8Tk7jBwgemLx4O40lhhvZCVw1C+OYLOBOPXWw==", - "dev": true, - "dependencies": { - "archy": "^1.0.0", - "caching-transform": "^3.0.2", - "convert-source-map": "^1.6.0", - "cp-file": "^6.2.0", - "find-cache-dir": "^2.1.0", - "find-up": "^3.0.0", - "foreground-child": "^1.5.6", - "glob": "^7.1.3", - "istanbul-lib-coverage": "^2.0.5", - "istanbul-lib-hook": "^2.0.7", - "istanbul-lib-instrument": "^3.3.0", - "istanbul-lib-report": "^2.0.8", - "istanbul-lib-source-maps": "^3.0.6", - "istanbul-reports": "^2.2.4", - "js-yaml": "^3.13.1", - "make-dir": "^2.1.0", - "merge-source-map": "^1.1.0", - "resolve-from": "^4.0.0", - "rimraf": "^2.6.3", - "signal-exit": "^3.0.2", - "spawn-wrap": "^1.4.2", - "test-exclude": "^5.2.3", - "uuid": "^3.3.2", - "yargs": "^13.2.2", - "yargs-parser": "^13.0.0" - }, - "bin": { - "nyc": "bin/nyc.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/nyc/node_modules/ansi-regex": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", - "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/nyc/node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/nyc/node_modules/cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", - "dev": true, - "dependencies": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - } - }, - "node_modules/nyc/node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nyc/node_modules/emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "node_modules/nyc/node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/nyc/node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/nyc/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/nyc/node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/nyc/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/nyc/node_modules/string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "dependencies": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/nyc/node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "dependencies": { - "ansi-regex": "^4.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/nyc/node_modules/wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/nyc/node_modules/y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "dev": true - }, - "node_modules/nyc/node_modules/yargs": { - "version": "13.3.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", - "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", - "dev": true, - "dependencies": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.2" - } - }, - "node_modules/nyc/node_modules/yargs-parser": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", - "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", - "dev": true, - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/one-time": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", - "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", - "dependencies": { - "fn.name": "1.x.x" - } - }, - "node_modules/onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==", - "dev": true, - "dependencies": { - "mimic-fn": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/package-hash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-3.0.0.tgz", - "integrity": "sha512-lOtmukMDVvtkL84rJHI7dpTYq+0rli8N2wlnqUcBuDWCfVhRUfOmnR9SsoHFMLpACvEV60dX7rd0rFaYDZI+FA==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.15", - "hasha": "^3.0.0", - "lodash.flattendeep": "^4.4.0", - "release-zalgo": "^1.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", - "dev": true, - "dependencies": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", - "dev": true - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/path-to-regexp": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", - "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", - "dev": true, - "dependencies": { - "isarray": "0.0.1" - } - }, - "node_modules/path-to-regexp/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - }, - "node_modules/path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "dependencies": { - "pify": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/path-type/node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/picocolors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "dev": true, - "dependencies": { - "find-up": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-dir/node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-dir/node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-dir/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pkg-dir/node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-dir/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/pluralize": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", - "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/protobufjs": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.3.2.tgz", - "integrity": "sha512-RXyHaACeqXeqAKGLDl68rQKbmObRsTIn4TYVUUug1KfS47YWCo5MacGITEryugIgZqORCvJWEk4l449POg5Txg==", - "hasInstallScript": true, - "dependencies": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/node": ">=13.7.0", - "long": "^5.0.0" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", - "dev": true - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==", - "dev": true, - "dependencies": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg-up": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", - "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", - "dev": true, - "dependencies": { - "find-up": "^3.0.0", - "read-pkg": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/read-pkg-up/node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/read-pkg-up/node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/read-pkg-up/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/read-pkg-up/node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/read-pkg-up/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/readable-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/readdirp": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", - "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/reflect-metadata": { - "version": "0.1.14", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.14.tgz", - "integrity": "sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A==" - }, - "node_modules/regexpp": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz", - "integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==", - "dev": true, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/release-zalgo": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", - "integrity": "sha512-gUAyHVHPPC5wdqX/LG4LWtRYtgjxyX78oanFNTMMyFEfOqdC54s3eE82imuWKbOeqYht2CrNf64Qb8vgmmtZGA==", - "dev": true, - "dependencies": { - "es6-error": "^4.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, - "node_modules/require-uncached": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", - "integrity": "sha512-Xct+41K3twrbBHdxAgMoOS+cNcoqIjfM2/VxBF4LL2hVph7YsF8VSKyQ3BDFZwEVbok9yeDl2le/qo0S77WG2w==", - "dev": true, - "dependencies": { - "caller-path": "^0.1.0", - "resolve-from": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-uncached/node_modules/resolve-from": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", - "integrity": "sha512-kT10v4dhrlLNcnO084hEjvXCI1wUG9qZLoz2RogxqDQQYy7IxjI/iMUkOtQTNEh6rzHxvdQWHsJyel1pKOVCxg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dev": true, - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==", - "dev": true, - "dependencies": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/rx-lite": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", - "integrity": "sha512-Cun9QucwK6MIrp3mry/Y7hqD1oFqTYLQ4pGxaHTjIdaFDWRGGLikqp6u8LcWJnzpoALg9hap+JGk8sFIUuEGNA==", - "dev": true - }, - "node_modules/rx-lite-aggregates": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz", - "integrity": "sha512-3xPNZGW93oCjiO7PtKxRK6iOVYBWBvtf9QHDfU23Oc+dLIQmAV//UnyXV/yihv81VS/UqoQPk4NegS8EFi55Hg==", - "dev": true, - "dependencies": { - "rx-lite": "*" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/safe-stable-stringify": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", - "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", - "engines": { - "node": ">=10" - } - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/serialize-javascript": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", - "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", - "dev": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "dev": true - }, - "node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", - "dev": true, - "dependencies": { - "shebang-regex": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", - "dependencies": { - "is-arrayish": "^0.3.1" - } - }, - "node_modules/simple-swizzle/node_modules/is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" - }, - "node_modules/sinon": { - "version": "6.3.5", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-6.3.5.tgz", - "integrity": "sha512-xgoZ2gKjyVRcF08RrIQc+srnSyY1JDJtxu3Nsz07j1ffjgXoY6uPLf/qja6nDBZgzYYEovVkFryw2+KiZz11xQ==", - "deprecated": "16.1.1", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^1.0.2", - "@sinonjs/formatio": "^3.0.0", - "@sinonjs/samsam": "^2.1.2", - "diff": "^3.5.0", - "lodash.get": "^4.4.2", - "lolex": "^2.7.5", - "nise": "^1.4.5", - "supports-color": "^5.5.0", - "type-detect": "^4.0.8" - } - }, - "node_modules/sinon-chai": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/sinon-chai/-/sinon-chai-3.7.0.tgz", - "integrity": "sha512-mf5NURdUaSdnatJx3uhoBOrY9dtL19fiOtAdT1Azxg3+lNJFiuN0uzaU3xX1LeAfL17kHQhTAJgpsfhbMJMY2g==", - "dev": true, - "peerDependencies": { - "chai": "^4.0.0", - "sinon": ">=4.0.0" - } - }, - "node_modules/sinon/node_modules/diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/slice-ansi": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", - "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", - "dev": true, - "dependencies": { - "is-fullwidth-code-point": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/spawn-wrap": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-1.4.3.tgz", - "integrity": "sha512-IgB8md0QW/+tWqcavuFgKYR/qIRvJkRLPJDFaoXtLLUaVcCDK0+HeFTkmQHj3eprcYhc+gOl0aEA1w7qZlYezw==", - "dev": true, - "dependencies": { - "foreground-child": "^1.5.6", - "mkdirp": "^0.5.0", - "os-homedir": "^1.0.1", - "rimraf": "^2.6.2", - "signal-exit": "^3.0.2", - "which": "^1.3.0" - } - }, - "node_modules/spdx-correct": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", - "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", - "dev": true, - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", - "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", - "dev": true - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.18", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.18.tgz", - "integrity": "sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ==", - "dev": true - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, - "node_modules/stack-trace": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", - "engines": { - "node": "*" - } - }, - "node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/string_decoder/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "dependencies": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", - "dev": true, - "dependencies": { - "ansi-regex": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/table": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz", - "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==", - "dev": true, - "dependencies": { - "ajv": "^5.2.3", - "ajv-keywords": "^2.1.0", - "chalk": "^2.1.0", - "lodash": "^4.17.4", - "slice-ansi": "1.0.0", - "string-width": "^2.1.1" - } - }, - "node_modules/test-exclude": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz", - "integrity": "sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g==", - "dev": true, - "dependencies": { - "glob": "^7.1.3", - "minimatch": "^3.0.4", - "read-pkg-up": "^4.0.0", - "require-main-filename": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/text-hex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", - "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true - }, - "node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "dependencies": { - "os-tmpdir": "~1.0.2" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/triple-beam": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", - "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/tweetnacl": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", - "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" - }, - "node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", - "dev": true, - "dependencies": { - "prelude-ls": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", - "dev": true - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", - "dev": true, - "bin": { - "uuid": "bin/uuid" - } - }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/which-module": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", - "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", - "dev": true - }, - "node_modules/wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", - "dev": true, - "dependencies": { - "string-width": "^1.0.2 || 2" - } - }, - "node_modules/winston": { - "version": "3.13.0", - "resolved": "https://registry.npmjs.org/winston/-/winston-3.13.0.tgz", - "integrity": "sha512-rwidmA1w3SE4j0E5MuIufFhyJPBDG7Nu71RkZor1p2+qHvJSZ9GYDA81AyleQcZbh/+V6HjeBdfnTZJm9rSeQQ==", - "dependencies": { - "@colors/colors": "^1.6.0", - "@dabh/diagnostics": "^2.0.2", - "async": "^3.2.3", - "is-stream": "^2.0.0", - "logform": "^2.4.0", - "one-time": "^1.0.0", - "readable-stream": "^3.4.0", - "safe-stable-stringify": "^2.3.1", - "stack-trace": "0.0.x", - "triple-beam": "^1.3.0", - "winston-transport": "^4.7.0" - }, - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/winston-transport": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.7.0.tgz", - "integrity": "sha512-ajBj65K5I7denzer2IYW6+2bNIVqLGDHqDw3Ow8Ohh+vdW+rv4MZ6eiDvHoKhfJFZ2auyN8byXieDDJ96ViONg==", - "dependencies": { - "logform": "^2.3.2", - "readable-stream": "^3.6.0", - "triple-beam": "^1.3.0" - }, - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/winston-transport/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/winston/node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/winston/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/workerpool": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.0.tgz", - "integrity": "sha512-toV7q9rWNYha963Pl/qyeZ6wG+3nnsyvolaNUS8+R5Wtw6qJPTxIlOP1ZSvcGhEJw+l3HMMmtiNo9Gl61G4GVg==", - "dev": true - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/wrap-ansi/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "node_modules/write": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", - "integrity": "sha512-CJ17OoULEKXpA5pef3qLj5AxTJ6mSt7g84he2WIskKwqFO4T97d5V7Tadl0DYDk7qyUOQD5WlUlOMChaYrhxeA==", - "dev": true, - "dependencies": { - "mkdirp": "^0.5.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/write-file-atomic": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", - "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.2" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", - "dev": true - }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dev": true, - "dependencies": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - } -} diff --git a/token-erc-20/chaincode-javascript/package.json b/token-erc-20/chaincode-javascript/package.json deleted file mode 100644 index 2036e1ad..00000000 --- a/token-erc-20/chaincode-javascript/package.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "name": "token-erc20", - "version": "0.0.1", - "description": "Token-ERC20 contract implemented in JavaScript", - "main": "index.js", - "engines": { - "node": ">=12", - "npm": ">=5" - }, - "scripts": { - "lint": "eslint .", - "pretest": "npm run lint", - "test": "nyc mocha --recursive", - "mocha": "mocha --recursive", - "start": "fabric-chaincode-node start" - }, - "engineStrict": true, - "author": "Hyperledger", - "license": "Apache-2.0", - "dependencies": { - "fabric-contract-api": "~2.5", - "fabric-shim": "~2.5" - }, - "devDependencies": { - "chai": "^4.1.2", - "chai-as-promised": "^7.1.1", - "eslint": "^4.19.1", - "mocha": "^8.0.1", - "nyc": "^14.1.1", - "sinon": "^6.0.0", - "sinon-chai": "^3.2.0" - }, - "nyc": { - "exclude": [ - "coverage/**", - "test/**", - "index.js", - ".eslintrc.js" - ], - "reporter": [ - "text-summary", - "html" - ], - "all": true, - "check-coverage": false, - "statements": 100, - "branches": 100, - "functions": 100, - "lines": 100 - } -} diff --git a/token-erc-20/chaincode-javascript/test/tokenERC20.test.js b/token-erc-20/chaincode-javascript/test/tokenERC20.test.js deleted file mode 100644 index 133babb2..00000000 --- a/token-erc-20/chaincode-javascript/test/tokenERC20.test.js +++ /dev/null @@ -1,296 +0,0 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 -*/ - -'use strict'; - -const { Context } = require('fabric-contract-api'); -const { ChaincodeStub, ClientIdentity } = require('fabric-shim'); - -const { TokenERC20Contract } = require('..'); - -const chai = require('chai'); -const chaiAsPromised = require('chai-as-promised'); -const sinon = require('sinon'); -const expect = chai.expect; - -chai.should(); -chai.use(chaiAsPromised); - -describe('Chaincode', () => { - let sandbox; - let token; - let ctx; - let mockStub; - let mockClientIdentity; - - beforeEach('Sandbox creation', async () => { - sandbox = sinon.createSandbox(); - token = new TokenERC20Contract('token-erc20'); - - ctx = sinon.createStubInstance(Context); - mockStub = sinon.createStubInstance(ChaincodeStub); - ctx.stub = mockStub; - mockClientIdentity = sinon.createStubInstance(ClientIdentity); - ctx.clientIdentity = mockClientIdentity; - - await token.Initialize(ctx, 'some name', 'some symbol', '2'); - - mockStub.putState.resolves('some state'); - mockStub.setEvent.returns('set event'); - - }); - - afterEach('Sandbox restoration', () => { - sandbox.restore(); - }); - - describe('#TokenName', () => { - it('should work', async () => { - mockStub.getState.resolves('some state'); - - const response = await token.TokenName(ctx); - sinon.assert.calledWith(mockStub.getState, 'name'); - expect(response).to.equals('some state'); - }); - }); - - describe('#Symbol', () => { - it('should work', async () => { - mockStub.getState.resolves('some state'); - - const response = await token.Symbol(ctx); - sinon.assert.calledWith(mockStub.getState, 'symbol'); - expect(response).to.equals('some state'); - }); - }); - - describe('#Decimals', () => { - it('should work', async () => { - mockStub.getState.resolves(Buffer.from('2')); - - const response = await token.Decimals(ctx); - sinon.assert.calledWith(mockStub.getState, 'decimals'); - expect(response).to.equals(2); - }); - }); - - describe('#TotalSupply', () => { - it('should work', async () => { - mockStub.getState.resolves(Buffer.from('10000')); - - const response = await token.TotalSupply(ctx); - sinon.assert.calledWith(mockStub.getState, 'totalSupply'); - expect(response).to.equals(10000); - }); - }); - - describe('#BalanceOf', () => { - it('should work', async () => { - mockStub.createCompositeKey.returns('balance_Alice'); - mockStub.getState.resolves(Buffer.from('1000')); - - const response = await token.BalanceOf(ctx, 'Alice'); - expect(response).to.equals(1000); - }); - }); - - describe('#_transfer', () => { - - it('should fail when the sender and the receipient are the same', async () => { - await expect(token._transfer(ctx, 'Alice', 'Alice', '1000')) - .to.be.rejectedWith(Error, 'cannot transfer to and from same client account'); - }); - - it('should fail when the sender does not have enough token', async () => { - mockStub.createCompositeKey.withArgs('balance', ['Alice']).returns('balance_Alice'); - mockStub.getState.withArgs('balance_Alice').resolves(Buffer.from('500')); - - await expect(token._transfer(ctx, 'Alice', 'Bob', '1000')) - .to.be.rejectedWith(Error, 'client account Alice has insufficient funds.'); - }); - - it('should transfer to a new account when the sender has enough token', async () => { - mockStub.createCompositeKey.withArgs('balance', ['Alice']).returns('balance_Alice'); - mockStub.getState.withArgs('balance_Alice').resolves(Buffer.from('1000')); - - mockStub.createCompositeKey.withArgs('balance', ['Bob']).returns('balance_Bob'); - mockStub.getState.withArgs('balance_Bob').resolves(null); - - const response = await token._transfer(ctx, 'Alice', 'Bob', '1000'); - sinon.assert.calledWith(mockStub.putState.getCall(0), 'balance_Alice', Buffer.from('0')); - sinon.assert.calledWith(mockStub.putState.getCall(1), 'balance_Bob', Buffer.from('1000')); - expect(response).to.equals(true); - }); - - it('should transfer to the existing account when the sender has enough token', async () => { - mockStub.createCompositeKey.withArgs('balance', ['Alice']).returns('balance_Alice'); - mockStub.getState.withArgs('balance_Alice').resolves(Buffer.from('1000')); - - mockStub.createCompositeKey.withArgs('balance', ['Bob']).returns('balance_Bob'); - mockStub.getState.withArgs('balance_Bob').resolves(Buffer.from('2000')); - - const response = await token._transfer(ctx, 'Alice', 'Bob', '1000'); - sinon.assert.calledWith(mockStub.putState.getCall(0), 'balance_Alice', Buffer.from('0')); - sinon.assert.calledWith(mockStub.putState.getCall(1), 'balance_Bob', Buffer.from('3000')); - expect(response).to.equals(true); - }); - - }); - - describe('#Transfer', () => { - it('should work', async () => { - mockClientIdentity.getID.returns('Alice'); - sinon.stub(token, '_transfer').returns(true); - - const response = await token.Transfer(ctx, 'Bob', '1000'); - const event = { from: 'Alice', to: 'Bob', value: 1000 }; - sinon.assert.calledWith(mockStub.setEvent, 'Transfer', Buffer.from(JSON.stringify(event))); - expect(response).to.equals(true); - }); - }); - - describe('#TransferFrom', () => { - it('should fail when the spender is not allowed to spend the token', async () => { - mockClientIdentity.getID.returns('Charlie'); - - mockStub.createCompositeKey.withArgs('allowance', ['Alice', 'Charlie']).returns('allowance_Alice_Charlie'); - mockStub.getState.withArgs('allowance_Alice_Charlie').resolves(Buffer.from('0')); - - await expect(token.TransferFrom(ctx, 'Alice', 'Bob', '1000')) - .to.be.rejectedWith(Error, 'The spender does not have enough allowance to spend.'); - }); - - it('should transfer when the spender is allowed to spend the token', async () => { - mockClientIdentity.getID.returns('Charlie'); - - mockStub.createCompositeKey.withArgs('allowance', ['Alice', 'Charlie']).returns('allowance_Alice_Charlie'); - mockStub.getState.withArgs('allowance_Alice_Charlie').resolves(Buffer.from('3000')); - - sinon.stub(token, '_transfer').returns(true); - - const response = await token.TransferFrom(ctx, 'Alice', 'Bob', '1000'); - sinon.assert.calledWith(mockStub.putState, 'allowance_Alice_Charlie', Buffer.from('2000')); - const event = { from: 'Alice', to: 'Bob', value: 1000 }; - sinon.assert.calledWith(mockStub.setEvent, 'Transfer', Buffer.from(JSON.stringify(event))); - expect(response).to.equals(true); - }); - }); - - describe('#Approve', () => { - it('should work', async () => { - mockClientIdentity.getID.returns('Dave'); - mockStub.createCompositeKey.returns('allowance_Dave_Eve'); - - const response = await token.Approve(ctx, 'Ellen', '1000'); - sinon.assert.calledWith(mockStub.putState, 'allowance_Dave_Eve', Buffer.from('1000')); - expect(response).to.equals(true); - }); - }); - - describe('#Allowance', () => { - it('should work', async () => { - mockStub.createCompositeKey.returns('allowance_Dave_Eve'); - mockStub.getState.resolves(Buffer.from('1000')); - - const response = await token.Allowance(ctx, 'Dave', 'Eve'); - expect(response).to.equals(1000); - }); - }); - - describe('#Initialize', () => { - it('should work', async () => { - // We consider it has already been initialized in the before-each statement - sinon.assert.calledWith(mockStub.putState, 'name', Buffer.from('some name')); - sinon.assert.calledWith(mockStub.putState, 'symbol', Buffer.from('some symbol')); - sinon.assert.calledWith(mockStub.putState, 'decimals', Buffer.from('2')); - }); - - it('should failed if called a second time', async () => { - // We consider it has already been initialized in the before-each statement - await expect(await token.Initialize(ctx, 'some name', 'some symbol', '2')) - .to.be.rejectedWith(Error, 'contract options are already set, client is not authorized to change them'); - }); - }); - - describe('#Mint', () => { - it('should add token to a new account and a new total supply', async () => { - mockClientIdentity.getMSPID.returns('Org1MSP'); - mockClientIdentity.getID.returns('Alice'); - mockStub.createCompositeKey.returns('balance_Alice'); - mockStub.getState.withArgs('balance_Alice').resolves(null); - mockStub.getState.withArgs('totalSupply').resolves(null); - - const response = await token.Mint(ctx, '1000'); - sinon.assert.calledWith(mockStub.putState.getCall(0), 'balance_Alice', Buffer.from('1000')); - sinon.assert.calledWith(mockStub.putState.getCall(1), 'totalSupply', Buffer.from('1000')); - expect(response).to.equals(true); - }); - - it('should add token to the existing account and the existing total supply', async () => { - mockClientIdentity.getMSPID.returns('Org1MSP'); - mockClientIdentity.getID.returns('Alice'); - mockStub.createCompositeKey.returns('balance_Alice'); - mockStub.getState.withArgs('balance_Alice').resolves(Buffer.from('1000')); - mockStub.getState.withArgs('totalSupply').resolves(Buffer.from('2000')); - - const response = await token.Mint(ctx, '1000'); - sinon.assert.calledWith(mockStub.putState.getCall(0), 'balance_Alice', Buffer.from('2000')); - sinon.assert.calledWith(mockStub.putState.getCall(1), 'totalSupply', Buffer.from('3000')); - expect(response).to.equals(true); - }); - - it('should add token to a new account and the existing total supply', async () => { - mockClientIdentity.getMSPID.returns('Org1MSP'); - mockClientIdentity.getID.returns('Alice'); - mockStub.createCompositeKey.returns('balance_Alice'); - mockStub.getState.withArgs('balance_Alice').resolves(null); - mockStub.getState.withArgs('totalSupply').resolves(Buffer.from('2000')); - - const response = await token.Mint(ctx, '1000'); - sinon.assert.calledWith(mockStub.putState.getCall(0), 'balance_Alice', Buffer.from('1000')); - sinon.assert.calledWith(mockStub.putState.getCall(1), 'totalSupply', Buffer.from('3000')); - expect(response).to.equals(true); - }); - - }); - - describe('#Burn', () => { - it('should work', async () => { - mockClientIdentity.getMSPID.returns('Org1MSP'); - mockClientIdentity.getID.returns('Alice'); - mockStub.createCompositeKey.returns('balance_Alice'); - mockStub.getState.withArgs('balance_Alice').resolves(Buffer.from('1000')); - mockStub.getState.withArgs('totalSupply').resolves(Buffer.from('2000')); - - const response = await token.Burn(ctx, '1000'); - sinon.assert.calledWith(mockStub.putState.getCall(0), 'balance_Alice', Buffer.from('0')); - sinon.assert.calledWith(mockStub.putState.getCall(1), 'totalSupply', Buffer.from('1000')); - expect(response).to.equals(true); - }); - }); - - describe('#ClientAccountBalance', () => { - it('should work', async () => { - mockClientIdentity.getID.returns('Alice'); - mockStub.createCompositeKey.returns('balance_Alice'); - mockStub.getState.resolves(Buffer.from('1000')); - - const response = await token.ClientAccountBalance(ctx,); - expect(response).to.equals(1000); - }); - }); - - describe('#ClientAccountID', () => { - it('should work', async () => { - mockClientIdentity.getID.returns('x509::{subject DN}::{issuer DN}'); - - const response = await token.ClientAccountID(ctx); - sinon.assert.calledOnce(mockClientIdentity.getID); - expect(response).to.equals('x509::{subject DN}::{issuer DN}'); - }); - }); - -}); diff --git a/token-erc-721/README.md b/token-erc-721/README.md deleted file mode 100644 index 2fc60f0e..00000000 --- a/token-erc-721/README.md +++ /dev/null @@ -1,477 +0,0 @@ -# ERC-721 token scenario - -The ERC-721 token smart contract demonstrates how to create and transfer non-fungible tokens. -Non-fungible tokens represent ownership over digital or physical assets. Example assets are artworks, houses, tickets, etc. -Non-fungible tokens are distinguishable and we can track the ownership of each one separately. - -In ERC-721, there is an account for each participant that holds a balance of tokens. -A mint transaction creates a non-fungible token for an owner and adds one token in the owner's account. -A transfer transaction changes the ownership of a token from the current owner to a new owner. -The transfer also debits one token from the previous owner's account and credits one token to another account. - -In this sample it is assumed that only one organization (played by Org1) is in an issuer role and can mint new tokens into their account, while any organization can transfer tokens from their account to a recipient's account. -Accounts could be defined at the organization level or client identity level. In this sample accounts are defined at the client identity level, where every authorized client with an enrollment certificate from their organization implicitly has an account ID that matches their client ID. -The client ID is simply a base64-encoded concatenation of the issuer and subject from the client identity's enrollment certificate. The client ID can therefore be considered the account ID that is used as the payment address of a recipient. - -In this tutorial, you will mint and transfer tokens as follows: - -- A member of Org1 uses the `MintWithTokenURI` function to create a new non-fungible token into their account. The `MintWithTokenURI` smart contract function reads the certificate information of the client identity that submitted the transaction using the `GetClientIdentity.GetID()` API and creates a non-fungible token associated with the client ID with the requested token ID. -- The same minter client will then use the `TransferFrom` function to transfer a non-fungible token with a requested token ID to the recipient's account. It is assumed that the recipient has provided their account ID to the transfer caller out of band. The recipient can then transfer tokens to other registered users in the same fashion. - -## Bring up the test network - -You can run the ERC-721 token transfer scenario using the Fabric test network. Open a command terminal and navigate to the test network directory in your local clone of the `fabric-samples`. We will operate from the `test-network` directory for the remainder of the tutorial. -``` -cd fabric-samples/test-network -``` - -Run the following command to start the test network: -``` -./network.sh up createChannel -ca -``` - -The test network is deployed with two peer organizations. The `createChannel` flag deploys the network with a single channel named `mychannel` with Org1 and Org2 as channel members. -The -ca flag is used to deploy the network using certificate authorities. This allows you to use each organization's CA to register and enroll new users for this tutorial. - -## Deploy the smart contract to the channel - -You can use the test network script to deploy the ERC-721 token contract to the channel that was just created. Deploy the smart contract to `mychannel` using the following command: - -``` -./network.sh deployCC -ccn token_erc721 -ccp ../token-erc-721/chaincode-javascript/ -ccl javascript -``` - -The above command deploys the chaincode with short name `token_erc721`. The smart contract will use the default endorsement policy of majority of channel members. -Since the channel has two members, this implies that we'll need to get peer endorsements from 2 out of the 2 channel members. - -Now you are ready to call the deployed smart contract via peer CLI calls. But let's first create the client identities for our scenario. - -## Register identities - -The smart contract supports accounts owned by individual client identities from organizations that are members of the channel. In our scenario, the minter of the tokens will be a member of Org1, while the recipient will belong to Org2. To highlight the connection between the `GetClientIdentity().GetID()` API and the information within a user's certificate, we will register two new identities using the Org1 and Org2 Certificate Authorities (CA's), and then use the CA's to generate each identity's certificate and private key. - -First, we need to set the following environment variables to use the Fabric CA client (and subsequent commands). -``` -export PATH=${PWD}/../bin:${PWD}:$PATH -export FABRIC_CFG_PATH=$PWD/../config/ -``` - -The terminal we have been using will represent Org1. We will use the Org1 CA to create the minter identity. Set the Fabric CA client home to the MSP of the Org1 CA admin (this identity was generated by the test network script): -``` -export FABRIC_CA_CLIENT_HOME=${PWD}/organizations/peerOrganizations/org1.example.com/ -``` - -You can register a new minter client identity using the `fabric-ca-client` tool: -``` -fabric-ca-client register --caname ca-org1 --id.name minter --id.secret minterpw --id.type client --tls.certfiles ${PWD}/organizations/fabric-ca/org1/tls-cert.pem -``` - -You can now generate the identity certificates and MSP folder by providing the minter's enroll name and secret to the enroll command: -``` -fabric-ca-client enroll -u https://minter:minterpw@localhost:7054 --caname ca-org1 -M ${PWD}/organizations/peerOrganizations/org1.example.com/users/minter@org1.example.com/msp --tls.certfiles ${PWD}/organizations/fabric-ca/org1/tls-cert.pem -``` - -Run the command below to copy the Node OU configuration file into the minter identity MSP folder. -``` -cp ${PWD}/organizations/peerOrganizations/org1.example.com/msp/config.yaml ${PWD}/organizations/peerOrganizations/org1.example.com/users/minter@org1.example.com/msp/config.yaml -``` - -Open a new terminal to represent Org2 and navigate to fabric-samples/test-network. We'll use the Org2 CA to create the Org2 recipient identity. Set the Fabric CA client home to the MSP of the Org2 CA admin: -``` -cd fabric-samples/test-network -export PATH=${PWD}/../bin:${PWD}:$PATH -export FABRIC_CA_CLIENT_HOME=${PWD}/organizations/peerOrganizations/org2.example.com/ -``` - -You can register a recipient client identity using the `fabric-ca-client` tool: -``` -fabric-ca-client register --caname ca-org2 --id.name recipient --id.secret recipientpw --id.type client --tls.certfiles ${PWD}/organizations/fabric-ca/org2/tls-cert.pem -``` - -We can now enroll to generate the recipient's identity certificates and MSP folder: -``` -fabric-ca-client enroll -u https://recipient:recipientpw@localhost:8054 --caname ca-org2 -M ${PWD}/organizations/peerOrganizations/org2.example.com/users/recipient@org2.example.com/msp --tls.certfiles ${PWD}/organizations/fabric-ca/org2/tls-cert.pem -``` - -Run the command below to copy the Node OU configuration file into the recipient identity MSP folder. -``` -cp ${PWD}/organizations/peerOrganizations/org2.example.com/msp/config.yaml ${PWD}/organizations/peerOrganizations/org2.example.com/users/recipient@org2.example.com/msp/config.yaml -``` - -## Initialize the contract -Once we created the identity of the minter we can now initialize the contract. -Note that we need to call the initialize function before being able to use any functions of the contract. Initialize() can be called only once. - -Shift back to the Org1 terminal, we'll set the following environment variables to operate the `peer` CLI as the minter identity from Org1. -``` -export CORE_PEER_TLS_ENABLED=true -export CORE_PEER_LOCALMSPID=Org1MSP -export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/minter@org1.example.com/msp -export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt -export CORE_PEER_ADDRESS=localhost:7051 -export TARGET_TLS_OPTIONS=(-o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" --peerAddresses localhost:7051 --tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt" --peerAddresses localhost:9051 --tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt") -``` - -We can then invoke the smart contract to initilize it -``` -peer chaincode invoke "${TARGET_TLS_OPTIONS[@]}" -C mychannel -n token_erc721 -c '{"function":"Initialize","Args":["some name", "some symbol"]}' -``` - -## Mint a non-fungible token - -Now that we have initialized the contract and created the identity of the minter, we can invoke the smart contract to mint a non-fungible token. -Shift back to the Org1 terminal, we'll set the following environment variables to operate the `peer` CLI as the minter identity from Org1. -``` -export CORE_PEER_TLS_ENABLED=true -export CORE_PEER_LOCALMSPID=Org1MSP -export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/minter@org1.example.com/msp -export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt -export CORE_PEER_ADDRESS=localhost:7051 -export TARGET_TLS_OPTIONS="-o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt" -``` - -The last environment variable above will be utilized within the CLI invoke commands to set the target peers for endorsement, and the target ordering service endpoint and TLS options. - -We can then invoke the smart contract to mint a non-fungible token with a unique token ID `101`: -``` -peer chaincode invoke $TARGET_TLS_OPTIONS -C mychannel -n token_erc721 -c '{"function":"MintWithTokenURI","Args":["101", "https://example.com/nft101.json"]}' -``` - -The mint function validated that the client is a member of the minter organization, and then create a new non-fungible token for the minter. We can check the minter client's account balance by calling the `ClientAccountBalance` function. -``` -peer chaincode query -C mychannel -n token_erc721 -c '{"function":"ClientAccountBalance","Args":[]}' -``` - -The function queries the balance of the account associated with the minter client ID and returns: -``` -1 -``` - -We can also check the owner of the issued token by calling the `OwnerOf` function. -``` -peer chaincode query -C mychannel -n token_erc721 -c '{"function":"OwnerOf","Args":["101"]}' -``` - -The function queries the owner of the non-fungible token associated with the token ID and returns: -``` -x509::/C=US/ST=North Carolina/O=Hyperledger/OU=client/CN=minter::/C=US/ST=North Carolina/L=Durham/O=org1.example.com/CN=ca.org1.example.com -``` - -## Transfer a non-fungible token - -The minter intends to transfer a non-fungible token to the Org2 recipient, but first the Org2 recipient needs to provide their own account ID as the payment address. -A client can derive their account ID from their own public certificate, but to be sure the account ID is accurate, the contract has a `ClientAccountID` utility function that simply looks at the callers certificate and returns the calling client's ID, which will be used as the account ID. -Let's prepare the Org2 terminal by setting the environment variables for the Org2 recipient user. -``` -export FABRIC_CFG_PATH=$PWD/../config/ -export CORE_PEER_TLS_ENABLED=true -export CORE_PEER_LOCALMSPID=Org2MSP -export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/recipient@org2.example.com/msp -export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -export CORE_PEER_ADDRESS=localhost:9051 -``` - -Using the Org2 terminal, the Org2 recipient user can retrieve their own account ID: -``` -peer chaincode query -C mychannel -n token_erc721 -c '{"function":"ClientAccountID","Args":[]}' -``` - -The function returns of recipient's client ID. -The result shows that the subject and issuer is indeed the recipient user from Org2: -``` -x509::/C=US/ST=North Carolina/O=Hyperledger/OU=client/CN=recipient::/C=UK/ST=Hampshire/L=Hursley/O=org2.example.com/CN=ca.org2.example.com -``` - -After the Org2 recipient provides their account ID to the minter, the minter can initiate a transfer from their account to the recipient's account. - -To transfer a non-fungible token, minter also needs to provide it's own account ID. -Back in the Org1 terminal, the Org1 minter user can retrieve their own account ID: -``` -peer chaincode query -C mychannel -n token_erc721 -c '{"function":"ClientAccountID","Args":[]}' -``` - -The function returns of minter's client ID. -The result shows that the subject and issuer is indeed the recipient user from Org1: -``` -x509::/C=US/ST=North Carolina/O=Hyperledger/OU=client/CN=minter::/C=US/ST=North Carolina/L=Durham/O=org1.example.com/CN=ca.org1.example.com -``` - -After that, request the transfer of a non-fungible token `101` to the recipient account: -``` -export MINTER="x509::/C=US/ST=North Carolina/O=Hyperledger/OU=client/CN=minter::/C=US/ST=North Carolina/L=Durham/O=org1.example.com/CN=ca.org1.example.com" -export RECIPIENT="x509::/C=US/ST=North Carolina/O=Hyperledger/OU=client/CN=recipient::/C=UK/ST=Hampshire/L=Hursley/O=org2.example.com/CN=ca.org2.example.com" -peer chaincode invoke $TARGET_TLS_OPTIONS -C mychannel -n token_erc721 -c '{"function":"TransferFrom","Args":["'"$MINTER"'", "'"$RECIPIENT"'","101"]}' -``` - -The `TransferFrom` function validates ownership of the given non-fungible token. -It will then change the ownership of the non-fungible token from the current owner to the recipient. -It will also debit the caller's account and credit the recipient's account. Note that the sample contract will automatically create an account with zero balance for the recipient, if one does not yet exist. - -While still in the Org1 terminal, let's request the minter's account balance again: -``` -peer chaincode query -C mychannel -n token_erc721 -c '{"function":"ClientAccountBalance","Args":[]}' -``` - -The function queries the balance of the account associated with the minter client ID and returns: -``` -0 -``` - -And then using the Org2 terminal, let's request the recipient's balance: -``` -peer chaincode query -C mychannel -n token_erc721 -c '{"function":"ClientAccountBalance","Args":[]}' -``` - -The function queries the balance of the account associated with the recipient client ID and returns: -``` -1 -``` - -While still in the Org2 terminal, let's check the current owner of the token. - -``` -peer chaincode query -C mychannel -n token_erc721 -c '{"function":"OwnerOf","Args":["101"]}' -``` - -The function queries the owner of the non-fungible token with the token ID and returns: -``` -x509::/C=US/ST=North Carolina/O=Hyperledger/OU=client/CN=recipient::/C=UK/ST=Hampshire/L=Hursley/O=org2.example.com/CN=ca.org2.example.com -``` - -Congratulations, you've transferred a non-fungible token! The Org2 recipient can now transfer the token to other registered users in the same manner. - -## 3rd party transfers (Specific Token) - -This sample has another option, which allows an approved 3rd party operator to transfer a non-fungible token on behalf of the token owner. The owner appoves only one specific token to be transferred by the operator. This scenario demonstrates how to approve the operator and transfer a non-fungible token. - -In this scenario, you will approve the operator and transfer a specific non-fungible token as follows: - -- A minter has already created a non-fungible token according to the scenario above. -- The same minter client uses the `Approve` function to give the permission for an operator client to transfer a non-fungible token which has a specific token ID on behalf of the minter. It is assumed that the operator has provided their client ID to the `Approve` caller out of band. -- The operator client will then use the `TransferFrom` function to transfer the non-fungible token to the recipient's account on behalf of the minter. It is assumed that the recipient has provided their client ID to the `TransferFrom` caller out of band. - -## Register identity for 3rd party operator - -You have already brought up the network and deployed the smart contract to the channel. We will use the same network and smart contract. - -We will use the Org1 CA to create the operator identity. -Back in the Org1 terminal, you can register a new operator client identity using the `fabric-ca-client` tool: -``` -fabric-ca-client register --caname ca-org1 --id.name operator --id.secret operatorpw --id.type client --tls.certfiles ${PWD}/organizations/fabric-ca/org1/tls-cert.pem -``` - -You can now generate the identity certificates and MSP folder by providing the operator's enroll name and secret to the enroll command: -``` -fabric-ca-client enroll -u https://operator:operatorpw@localhost:7054 --caname ca-org1 -M ${PWD}/organizations/peerOrganizations/org1.example.com/users/operator@org1.example.com/msp --tls.certfiles ${PWD}/organizations/fabric-ca/org1/tls-cert.pem -``` - -Run the command below to copy the Node OU configuration file into the operator identity MSP folder. -``` -cp ${PWD}/organizations/peerOrganizations/org1.example.com/msp/config.yaml ${PWD}/organizations/peerOrganizations/org1.example.com/users/operator@org1.example.com/msp/config.yaml -``` - -## Approve an operator - -The minter intends to approve a non-fungible token to be transferred by the operator, but first the operator needs to provide their own client ID as the payment address. - -Open a 3rd terminal to represent the operator in Org1 and navigate to fabric-samples/test-network. Set the the environment variables for the Org1 operator user. - -``` -export PATH=${PWD}/../bin:${PWD}:$PATH -export FABRIC_CFG_PATH=$PWD/../config/ -export CORE_PEER_TLS_ENABLED=true -export CORE_PEER_LOCALMSPID=Org1MSP -export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/operator@org1.example.com/msp -export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt -export CORE_PEER_ADDRESS=localhost:7051 -export TARGET_TLS_OPTIONS="-o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt" -``` - -Now the Org1 operator can retrieve their own client ID: -``` -peer chaincode query -C mychannel -n token_erc721 -c '{"function":"ClientAccountID","Args":[]}' -``` - -The function returns of operator's client ID. -The result shows that the subject and issuer is indeed the operator user from Org1: -``` -x509::/C=US/ST=North Carolina/O=Hyperledger/OU=client/CN=operator::/C=US/ST=North Carolina/L=Durham/O=org1.example.com/CN=ca.org1.example.com -``` - -After the Org1 operator provides their client ID to the minter, the minter can approve an operator. -Back in the Org1 minter terminal, issue a new non-fungible token with the token ID `102`. -And then request the approval for the operator to transfer the token. - -``` -# Issue a new token -peer chaincode invoke $TARGET_TLS_OPTIONS -C mychannel -n token_erc721 -c '{"function":"MintWithTokenURI","Args":["102", "https://example.com/nft102.json"]}' --waitForEvent - -# The owner approves -export OPERATOR="x509::/C=US/ST=North Carolina/O=Hyperledger/OU=client/CN=operator::/C=US/ST=North Carolina/L=Durham/O=org1.example.com/CN=ca.org1.example.com" -peer chaincode invoke $TARGET_TLS_OPTIONS -C mychannel -n token_erc721 -c '{"function":"Approve","Args":["'"$OPERATOR"'", "102"]}' -``` - -The approve function specified that the operator client can transfer the non-fungible token with the given token ID on behalf of the minter. We can check the operator client's approval by calling the `GetApproved` function. - -Let's request the operator's approval from the Org1 minter terminal. - -``` -peer chaincode query -C mychannel -n token_erc721 -c '{"function":"GetApproved","Args":["102"]}' -``` - -The function queries the approval associated with the operator client ID and returns: -``` -x509::/C=US/ST=North Carolina/O=Hyperledger/OU=client/CN=operator::/C=US/ST=North Carolina/L=Durham/O=org1.example.com/CN=ca.org1.example.com -``` - -## Transfer a non-fungible token - -The operator intends to transfer a non-fungible token to the Org2 recipient on behalf of the minter. The operator has already got the minter client Id and the recipient client ID. - -Back in the 3rd operator terminal, request the transfer of a non-fungible token `102` to the recipient account: - -``` -export MINTER="x509::/C=US/ST=North Carolina/O=Hyperledger/OU=client/CN=minter::/C=US/ST=North Carolina/L=Durham/O=org1.example.com/CN=ca.org1.example.com" -export RECIPIENT="x509::/C=US/ST=North Carolina/O=Hyperledger/OU=client/CN=recipient::/C=UK/ST=Hampshire/L=Hursley/O=org2.example.com/CN=ca.org2.example.com" -peer chaincode invoke $TARGET_TLS_OPTIONS -C mychannel -n token_erc721 -c '{"function":"TransferFrom","Args":[ "'"$MINTER"'", "'"$RECIPIENT"'", "102"]}' -``` - -The `TransferFrom` function validates that the account associated with the calling client ID has the permission to transfer the given token on behalf of the current owner. -It will then change the ownership of the non-fungible token from the current owner to the recipient. -It will also debit the previous owner's account and credit the recipient's account. -It will also remove the operator's permission for this non-fungible token approved by the minter. -Note that the sample contract will automatically create an account with zero balance for the recipient, if one does not yet exist. - -While still in the 3rd operator terminal for the operator, let's request the minter's account balance again: -``` -peer chaincode query -C mychannel -n token_erc721 -c '{"function":"BalanceOf","Args":["'"$MINTER"'"]}' -``` - -The function queries the balance of the account associated with the minter client ID and returns: -``` -0 -``` - -And then, let's check the current owner of the token. - -``` -peer chaincode query -C mychannel -n token_erc721 -c '{"function":"OwnerOf","Args":["102"]}' -``` - -The function queries the owner of the non-fungible token with the token ID and returns: -``` -x509::/C=US/ST=North Carolina/O=Hyperledger/OU=client/CN=recipient::/C=UK/ST=Hampshire/L=Hursley/O=org2.example.com/CN=ca.org2.example.com -``` - -While still in the 3rd operator terminal for the operator, let's request the operator's approval from the minter again. - -``` -peer chaincode query -C mychannel -n token_erc721 -c '{"function":"GetApproved","Args":["102"]}' -``` - -The function queries the approval associated with the operator client ID and returns no value. - -And then using the Org2 terminal, let's request the recipient's balance: -``` -peer chaincode query -C mychannel -n token_erc721 -c '{"function":"ClientAccountBalance","Args":[]}' -``` - -The function queries the balance of the account associated with the recipient client ID and returns: -``` -2 -``` - -Congratulations, you've transferred a non-fungible token! The Org2 recipient can now transfer tokens to other registered users in the same manner. - - -## 3rd party transfers (All tokens) - -This sample has another option, which allows an approved 3rd party operator to transfer all non-fungible tokens on behalf of the token owner. The owner approves all tokens to be transferred by the operator. This scenario demonstrates how to approve the operator and transfer non-fungible tokens. - -In this scenario, you will approve the operator and transfer a non-fungible token as follows: - -- A minter has already created a non-fungible token according to the scenario above. -- The same minter client uses the `SetApprovalForAll` function to give the permission for an operator client to transfer all non-fungible tokens on behalf of the minter. It is assumed that the operator has provided their client ID to the `SetApprovalForAll` caller out of band. -- The operator client will then use the `TransferFrom` function to transfer the non-fungible token to the recipient's account on behalf of the minter. It is assumed that the recipient has provided their client ID to the `TransferFrom` caller out of band. - -## Approve an operator - -Request the approval for the operator to transfer the token. -we assume that the minter has already got the operator client ID as the payment address. - -Back in the Org1 minter terminal, request the approval for the operator to transfer all tokens on behalf of the original owner. -``` -peer chaincode invoke $TARGET_TLS_OPTIONS -C mychannel -n token_erc721 -c '{"function":"SetApprovalForAll","Args":["'"$OPERATOR"'", "true"]}' -``` - -The `SetApprovalForAll` function specified that the operator client can transfer any non-fungible tokens on behalf of the minter. We can check the operator client's approval by calling the `IsApprovedForAll` function. - -Let's request the operator's approval from the Org1 minter terminal. - -``` -peer chaincode query -C mychannel -n token_erc721 -c '{"function":"IsApprovedForAll","Args":["'"$MINTER"'", "'"$OPERATOR"'"]}' -``` - -The function queries the approval associated with the operator client ID and returns: -``` -true -``` - -## Transfer a non-fungible token - -The operator intends to transfer a non-fungible token to the Org2 recipient on behalf of the minter. The operator has already got the minter client Id and the recipient client ID. - -Still in the Org1 minter terminal, issue a new non-fungible token with the token ID `103`. -``` -peer chaincode invoke $TARGET_TLS_OPTIONS -C mychannel -n token_erc721 -c '{"function":"MintWithTokenURI","Args":["103", "https://example.com/nft103.json"]}' - -``` - -Back in the 3rd operator terminal, request the transfer of a non-fungible token `103` to the recipient account: - -``` -peer chaincode invoke $TARGET_TLS_OPTIONS -C mychannel -n token_erc721 -c '{"function":"TransferFrom","Args":[ "'"$MINTER"'", "'"$RECIPIENT"'", "103"]}' -``` - -The `TransferFrom` function validates that the account associated with the calling client ID has the permission to transfer tokens on behalf of the current owner. -It will then change the ownership of the non-fungible token and update balances like the other options. - -While still in the 3rd operator terminal for the operator, let's request the minter's account balance again: -``` -peer chaincode query -C mychannel -n token_erc721 -c '{"function":"BalanceOf","Args":["'"$MINTER"'"]}' -``` - -The function queries the balance of the account associated with the minter client ID and returns: -``` -0 -``` - -And then, let's check the current owner of the token. - -``` -peer chaincode query -C mychannel -n token_erc721 -c '{"function":"OwnerOf","Args":["103"]}' -``` - -The function queries the owner of the non-fungible token with the token ID and returns: -``` -x509::/C=US/ST=North Carolina/O=Hyperledger/OU=client/CN=recipient::/C=UK/ST=Hampshire/L=Hursley/O=org2.example.com/CN=ca.org2.example.com -``` - -And then using the Org2 terminal, let's request the recipient's balance: -``` -peer chaincode query -C mychannel -n token_erc721 -c '{"function":"ClientAccountBalance","Args":[]}' -``` - -The function queries the balance of the account associated with the recipient client ID and returns: -``` -3 -``` - -Congratulations, you've transferred a non-fungible token! The Org2 recipient can now transfer tokens to other registered users in the same manner. - -## Clean up - -When you are finished, you can bring down the test network. The command will remove all the nodes of the test network, and delete any ledger data that you created: -``` -./network.sh down -``` diff --git a/token-erc-721/chaincode-go/chaincode/erc721-contract.go b/token-erc-721/chaincode-go/chaincode/erc721-contract.go deleted file mode 100644 index a31695aa..00000000 --- a/token-erc-721/chaincode-go/chaincode/erc721-contract.go +++ /dev/null @@ -1,789 +0,0 @@ -package chaincode - -import ( - "encoding/base64" - "encoding/json" - "errors" - "fmt" - - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" -) - -// Define objectType names for prefix -const balancePrefix = "balance" -const nftPrefix = "nft" -const approvalPrefix = "approval" - -// Define key names for options -const nameKey = "name" -const symbolKey = "symbol" - -// TokenERC721Contract contract for managing CRUD operations -type TokenERC721Contract struct { - contractapi.Contract -} - -func _readNFT(ctx contractapi.TransactionContextInterface, tokenId string) (*Nft, error) { - nftKey, err := ctx.GetStub().CreateCompositeKey(nftPrefix, []string{tokenId}) - if err != nil { - return nil, fmt.Errorf("failed to CreateCompositeKey %s: %v", tokenId, err) - } - - nftBytes, err := ctx.GetStub().GetState(nftKey) - if err != nil { - return nil, fmt.Errorf("failed to GetState %s: %v", tokenId, err) - } - - nft := new(Nft) - err = json.Unmarshal(nftBytes, nft) - if err != nil { - return nil, fmt.Errorf("failed to Unmarshal nftBytes: %v", err) - } - - return nft, nil -} - -func _nftExists(ctx contractapi.TransactionContextInterface, tokenId string) bool { - nftKey, err := ctx.GetStub().CreateCompositeKey(nftPrefix, []string{tokenId}) - if err != nil { - panic("error creating CreateCompositeKey:" + err.Error()) - } - - nftBytes, err := ctx.GetStub().GetState(nftKey) - if err != nil { - panic("error GetState nftBytes:" + err.Error()) - } - - return len(nftBytes) > 0 -} - -// BalanceOf counts all non-fungible tokens assigned to an owner -// param owner {String} An owner for whom to query the balance -// returns {int} The number of non-fungible tokens owned by the owner, possibly zero -func (c *TokenERC721Contract) BalanceOf(ctx contractapi.TransactionContextInterface, owner string) int { - - // Check if contract has been intilized first - initialized, err := checkInitialized(ctx) - if err != nil { - panic("failed to check if contract is already initialized:" + err.Error()) - } - if !initialized { - panic("Contract options need to be set before calling any function, call Initialize() to initialize contract") - } - - // There is a key record for every non-fungible token in the format of balancePrefix.owner.tokenId. - // BalanceOf() queries for and counts all records matching balancePrefix.owner.* - - iterator, err := ctx.GetStub().GetStateByPartialCompositeKey(balancePrefix, []string{owner}) - if err != nil { - panic("Error creating asset chaincode:" + err.Error()) - } - - // Count the number of returned composite keys - balance := 0 - for iterator.HasNext() { - _, err := iterator.Next() - if err != nil { - return 0 - } - balance++ - - } - return balance -} - -// OwnerOf finds the owner of a non-fungible token -// param {String} tokenId The identifier for a non-fungible token -// returns {String} Return the owner of the non-fungible token -func (c *TokenERC721Contract) OwnerOf(ctx contractapi.TransactionContextInterface, tokenId string) (string, error) { - - // Check if contract has been intilized first - initialized, err := checkInitialized(ctx) - if err != nil { - return "", fmt.Errorf("failed to check if contract is already initialized: %v", err) - } - if !initialized { - return "", errors.New("contract options need to be set before calling any function, call Initialize() to initialize contract") - } - - nft, err := _readNFT(ctx, tokenId) - if err != nil { - return "", fmt.Errorf("could not process OwnerOf for tokenId: %w", err) - } - - return nft.Owner, nil -} - -// Approve changes or reaffirms the approved client for a non-fungible token -// param {String} operator The new approved client -// param {String} tokenId the non-fungible token to approve -// returns {Boolean} Return whether the approval was successful or not -func (c *TokenERC721Contract) Approve(ctx contractapi.TransactionContextInterface, operator string, tokenId string) (bool, error) { - - // Check if contract has been intilized first - initialized, err := checkInitialized(ctx) - if err != nil { - return false, fmt.Errorf("failed to check if contract is already initialized: %v", err) - } - if !initialized { - return false, errors.New("contract options need to be set before calling any function, call Initialize() to initialize contract") - } - - sender64, err := ctx.GetClientIdentity().GetID() - if err != nil { - return false, fmt.Errorf("failed to GetClientIdentity: %v", err) - } - - senderBytes, err := base64.StdEncoding.DecodeString(sender64) - if err != nil { - return false, fmt.Errorf("failed to DecodeString senderBytes: %v", err) - } - sender := string(senderBytes) - - nft, err := _readNFT(ctx, tokenId) - if err != nil { - return false, fmt.Errorf("failed to _readNFT: %v", err) - } - - // Check if the sender is the current owner of the non-fungible token - // or an authorized operator of the current owner - owner := nft.Owner - operatorApproval, err := c.IsApprovedForAll(ctx, owner, sender) - if err != nil { - return false, fmt.Errorf("failed to get IsApprovedForAll: %v", err) - } - if owner != sender && !operatorApproval { - return false, errors.New("the sender is not the current owner nor an authorized operator") - } - - // Update the approved operator of the non-fungible token - nft.Approved = operator - nftKey, err := ctx.GetStub().CreateCompositeKey(nftPrefix, []string{tokenId}) - if err != nil { - return false, fmt.Errorf("failed to CreateCompositeKey %s: %v", nftKey, err) - } - - nftBytes, err := json.Marshal(nft) - if err != nil { - return false, fmt.Errorf("failed to marshal nftBytes: %v", err) - } - - err = ctx.GetStub().PutState(nftKey, nftBytes) - if err != nil { - return false, fmt.Errorf("failed to PutState for nftKey: %v", err) - } - - return true, nil -} - -// SetApprovalForAll enables or disables approval for a third party ("operator") -// to manage all the message sender's assets -// param {String} operator A client to add to the set of authorized operators -// param {Boolean} approved True if the operator is approved, false to revoke approval -// returns {Boolean} Return whether the approval was successful or not -func (c *TokenERC721Contract) SetApprovalForAll(ctx contractapi.TransactionContextInterface, operator string, approved bool) (bool, error) { - - // Check if contract has been intilized first - initialized, err := checkInitialized(ctx) - if err != nil { - return false, fmt.Errorf("failed to check if contract is already initialized: %v", err) - } - if !initialized { - return false, errors.New("contract options need to be set before calling any function, call Initialize() to initialize contract") - } - - sender64, err := ctx.GetClientIdentity().GetID() - if err != nil { - return false, fmt.Errorf("failed to GetClientIdentity: %v", err) - } - - senderBytes, err := base64.StdEncoding.DecodeString(sender64) - if err != nil { - return false, fmt.Errorf("failed to DecodeString sender: %v", err) - } - sender := string(senderBytes) - - nftApproval := new(Approval) - nftApproval.Owner = sender - nftApproval.Operator = operator - nftApproval.Approved = approved - - approvalKey, err := ctx.GetStub().CreateCompositeKey(approvalPrefix, []string{sender, operator}) - if err != nil { - return false, fmt.Errorf("failed to CreateCompositeKey: %v", err) - } - - approvalBytes, err := json.Marshal(nftApproval) - if err != nil { - return false, fmt.Errorf("failed to marshal approvalBytes: %v", err) - } - - err = ctx.GetStub().PutState(approvalKey, approvalBytes) - if err != nil { - return false, fmt.Errorf("failed to PutState approvalBytes: %v", err) - } - - // Emit the ApprovalForAll event - err = ctx.GetStub().SetEvent("ApprovalForAll", approvalBytes) - if err != nil { - return false, fmt.Errorf("failed to SetEvent ApprovalForAll: %v", err) - } - - return true, nil -} - -// IsApprovedForAll returns if a client is an authorized operator for another client -// param {String} owner The client that owns the non-fungible tokens -// param {String} operator The client that acts on behalf of the owner -// returns {Boolean} Return true if the operator is an approved operator for the owner, false otherwise -func (c *TokenERC721Contract) IsApprovedForAll(ctx contractapi.TransactionContextInterface, owner string, operator string) (bool, error) { - - // Check if contract has been intilized first - initialized, err := checkInitialized(ctx) - if err != nil { - return false, fmt.Errorf("failed to check if contract is already initialized: %v", err) - } - if !initialized { - return false, errors.New("contract options need to be set before calling any function, call Initialize() to initialize contract") - } - - approvalKey, err := ctx.GetStub().CreateCompositeKey(approvalPrefix, []string{owner, operator}) - if err != nil { - return false, fmt.Errorf("failed to CreateCompositeKey: %v", err) - } - approvalBytes, err := ctx.GetStub().GetState(approvalKey) - if err != nil { - return false, fmt.Errorf("failed to GetState approvalBytes %s: %v", approvalBytes, err) - } - - if len(approvalBytes) < 1 { - return false, nil - } - - approval := new(Approval) - err = json.Unmarshal(approvalBytes, approval) - if err != nil { - return false, fmt.Errorf("failed to Unmarshal: %v, string %s", err, string(approvalBytes)) - } - - return approval.Approved, nil - -} - -// GetApproved returns the approved client for a single non-fungible token -// param {String} tokenId the non-fungible token to find the approved client for -// returns {Object} Return the approved client for this non-fungible token, or null if there is none -func (c *TokenERC721Contract) GetApproved(ctx contractapi.TransactionContextInterface, tokenId string) (string, error) { - - // Check if contract has been intilized first - initialized, err := checkInitialized(ctx) - if err != nil { - return "false", fmt.Errorf("failed to check if contract is already initialized: %v", err) - } - if !initialized { - return "false", errors.New("contract options need to be set before calling any function, call Initialize() to initialize contract") - } - - nft, err := _readNFT(ctx, tokenId) - if err != nil { - return "false", fmt.Errorf("failed GetApproved for tokenId : %v", err) - } - return nft.Approved, nil -} - -// TransferFrom transfers the ownership of a non-fungible token -// from one owner to another owner -// param {String} from The current owner of the non-fungible token -// param {String} to The new owner -// param {String} tokenId the non-fungible token to transfer -// returns {Boolean} Return whether the transfer was successful or not - -func (c *TokenERC721Contract) TransferFrom(ctx contractapi.TransactionContextInterface, from string, to string, tokenId string) (bool, error) { - - // Check if contract has been intilized first - initialized, err := checkInitialized(ctx) - if err != nil { - return false, fmt.Errorf("failed to check if contract is already initialized: %v", err) - } - if !initialized { - return false, errors.New("contract options need to be set before calling any function, call Initialize() to initialize contract") - } - - // Get ID of submitting client identity - sender64, err := ctx.GetClientIdentity().GetID() - if err != nil { - return false, fmt.Errorf("failed to GetClientIdentity: %v", err) - } - - senderBytes, err := base64.StdEncoding.DecodeString(sender64) - if err != nil { - return false, fmt.Errorf("failed to DecodeString sender: %v", err) - } - sender := string(senderBytes) - - nft, err := _readNFT(ctx, tokenId) - if err != nil { - return false, fmt.Errorf("failed to _readNFT : %v", err) - } - - owner := nft.Owner - operator := nft.Approved - operatorApproval, err := c.IsApprovedForAll(ctx, owner, sender) - if err != nil { - return false, fmt.Errorf("failed to get IsApprovedForAll : %v", err) - } - if owner != sender && operator != sender && !operatorApproval { - return false, errors.New("the sender is not the current owner nor an authorized operator") - } - - // Check if `from` is the current owner - if owner != from { - return false, errors.New("the from is not the current owner") - } - - // Clear the approved client for this non-fungible token - nft.Approved = "" - - // Overwrite a non-fungible token to assign a new owner. - nft.Owner = to - nftKey, err := ctx.GetStub().CreateCompositeKey(nftPrefix, []string{tokenId}) - if err != nil { - return false, fmt.Errorf("failed to CreateCompositeKey: %v", err) - } - - nftBytes, err := json.Marshal(nft) - if err != nil { - return false, fmt.Errorf("failed to marshal approval: %v", err) - } - - err = ctx.GetStub().PutState(nftKey, nftBytes) - if err != nil { - return false, fmt.Errorf("failed to PutState nftBytes %s: %v", nftBytes, err) - } - - // Remove a composite key from the balance of the current owner - balanceKeyFrom, err := ctx.GetStub().CreateCompositeKey(balancePrefix, []string{from, tokenId}) - if err != nil { - return false, fmt.Errorf("failed to CreateCompositeKey from: %v", err) - } - - err = ctx.GetStub().DelState(balanceKeyFrom) - if err != nil { - return false, fmt.Errorf("failed to DelState balanceKeyFrom %s: %v", nftBytes, err) - } - - // Save a composite key to count the balance of a new owner - balanceKeyTo, err := ctx.GetStub().CreateCompositeKey(balancePrefix, []string{to, tokenId}) - if err != nil { - return false, fmt.Errorf("failed to CreateCompositeKey to: %v", err) - } - err = ctx.GetStub().PutState(balanceKeyTo, []byte{0}) - if err != nil { - return false, fmt.Errorf("failed to PutState balanceKeyTo %s: %v", balanceKeyTo, err) - } - - // Emit the Transfer event - transferEvent := new(Transfer) - transferEvent.From = from - transferEvent.To = to - transferEvent.TokenId = tokenId - - transferEventBytes, err := json.Marshal(transferEvent) - if err != nil { - return false, fmt.Errorf("failed to marshal transferEventBytes: %v", err) - } - - err = ctx.GetStub().SetEvent("Transfer", transferEventBytes) - if err != nil { - return false, fmt.Errorf("failed to SetEvent transferEventBytes %s: %v", transferEventBytes, err) - } - return true, nil -} - -// ============== ERC721 metadata extension =============== - -// Name returns a descriptive name for a collection of non-fungible tokens in this contract -// returns {String} Returns the name of the token - -func (c *TokenERC721Contract) Name(ctx contractapi.TransactionContextInterface) (string, error) { - - // Check if contract has been intilized first - initialized, err := checkInitialized(ctx) - if err != nil { - return "", fmt.Errorf("failed to check if contract is already initialized: %v", err) - } - if !initialized { - return "", errors.New("contract options need to be set before calling any function, call Initialize() to initialize contract") - } - - bytes, err := ctx.GetStub().GetState(nameKey) - if err != nil { - return "", fmt.Errorf("failed to get Name bytes: %s", err) - } - - return string(bytes), nil -} - -// Symbol returns an abbreviated name for non-fungible tokens in this contract. -// returns {String} Returns the symbol of the token - -func (c *TokenERC721Contract) Symbol(ctx contractapi.TransactionContextInterface) (string, error) { - - // Check if contract has been intilized first - initialized, err := checkInitialized(ctx) - if err != nil { - return "", fmt.Errorf("failed to check if contract is already initialized: %v", err) - } - if !initialized { - return "", errors.New("contract options need to be set before calling any function, call Initialize() to initialize contract") - } - - bytes, err := ctx.GetStub().GetState(symbolKey) - if err != nil { - return "", fmt.Errorf("failed to get Symbol: %v", err) - } - - return string(bytes), nil -} - -// TokenURI returns a distinct Uniform Resource Identifier (URI) for a given token. -// param {string} tokenId The identifier for a non-fungible token -// returns {String} Returns the URI of the token - -func (c *TokenERC721Contract) TokenURI(ctx contractapi.TransactionContextInterface, tokenId string) (string, error) { - - // Check if contract has been intilized first - initialized, err := checkInitialized(ctx) - if err != nil { - return "", fmt.Errorf("failed to check if contract is already initialized: %v", err) - } - if !initialized { - return "", errors.New("contract options need to be set before calling any function, call Initialize() to initialize contract") - } - - nft, err := _readNFT(ctx, tokenId) - if err != nil { - return "", fmt.Errorf("failed to get TokenURI: %v", err) - } - return nft.TokenURI, nil -} - -// ============== ERC721 enumeration extension =============== -// TotalSupply counts non-fungible tokens tracked by this contract. -// -// @param {Context} ctx the transaction context -// @returns {Number} Returns a count of valid non-fungible tokens tracked by this contract, -// where each one of them has an assigned and queryable owner. - -func (c *TokenERC721Contract) TotalSupply(ctx contractapi.TransactionContextInterface) int { - - // Check if contract has been intilized first - initialized, err := checkInitialized(ctx) - if err != nil { - panic("failed to check if contract is already initialized:" + err.Error()) - } - if !initialized { - panic("Contract options need to be set before calling any function, call Initialize() to initialize contract") - } - - // There is a key record for every non-fungible token in the format of nftPrefix.tokenId. - // TotalSupply() queries for and counts all records matching nftPrefix.* - - iterator, err := ctx.GetStub().GetStateByPartialCompositeKey(nftPrefix, []string{}) - if err != nil { - panic("Error creating GetStateByPartialCompositeKey:" + err.Error()) - } - // Count the number of returned composite keys - - totalSupply := 0 - for iterator.HasNext() { - _, err := iterator.Next() - if err != nil { - return 0 - } - totalSupply++ - - } - return totalSupply - -} - -// ============== ERC721 enumeration extension =============== -// Set information for a token and intialize contract. -// param {String} name The name of the token -// param {String} symbol The symbol of the token - -func (c *TokenERC721Contract) Initialize(ctx contractapi.TransactionContextInterface, name string, symbol string) (bool, error) { - // Check minter authorization - this sample assumes Org1 is the issuer with privilege to set the name and symbol - clientMSPID, err := ctx.GetClientIdentity().GetMSPID() - if err != nil { - return false, fmt.Errorf("failed to get clientMSPID: %v", err) - } - if clientMSPID != "Org1MSP" { - return false, errors.New("client is not authorized to set the name and symbol of the token") - } - - bytes, err := ctx.GetStub().GetState(nameKey) - if err != nil { - return false, fmt.Errorf("failed to get Name: %v", err) - } - if bytes != nil { - return false, errors.New("contract options are already set, client is not authorized to change them") - } - - err = ctx.GetStub().PutState(nameKey, []byte(name)) - if err != nil { - return false, fmt.Errorf("failed to PutState nameKey %s: %v", nameKey, err) - } - - err = ctx.GetStub().PutState(symbolKey, []byte(symbol)) - if err != nil { - return false, fmt.Errorf("failed to PutState symbolKey %s: %v", symbolKey, err) - } - - return true, nil -} - -// Mint a new non-fungible token -// param {String} tokenId Unique ID of the non-fungible token to be minted -// param {String} tokenURI URI containing metadata of the minted non-fungible token -// returns {Object} Return the non-fungible token object - -func (c *TokenERC721Contract) MintWithTokenURI(ctx contractapi.TransactionContextInterface, tokenId string, tokenURI string) (*Nft, error) { - - // Check if contract has been intilized first - initialized, err := checkInitialized(ctx) - if err != nil { - return nil, fmt.Errorf("failed to check if contract is already initialized: %v", err) - } - if !initialized { - return nil, errors.New("contract options need to be set before calling any function, call Initialize() to initialize contract") - } - - // Check minter authorization - this sample assumes Org1 is the issuer with privilege to mint a new token - clientMSPID, err := ctx.GetClientIdentity().GetMSPID() - if err != nil { - return nil, fmt.Errorf("failed to get clientMSPID: %v", err) - } - - if clientMSPID != "Org1MSP" { - return nil, errors.New("client is not authorized to set the name and symbol of the token") - } - - // Get ID of submitting client identity - minter64, err := ctx.GetClientIdentity().GetID() - if err != nil { - return nil, fmt.Errorf("failed to get minter id: %v", err) - } - - minterBytes, err := base64.StdEncoding.DecodeString(minter64) - if err != nil { - return nil, fmt.Errorf("failed to DecodeString minter64: %v", err) - } - minter := string(minterBytes) - - // Check if the token to be minted does not exist - exists := _nftExists(ctx, tokenId) - if exists { - return nil, fmt.Errorf("the token %s is already minted.: %v", tokenId, err) - } - - // Add a non-fungible token - nft := new(Nft) - nft.TokenId = tokenId - nft.Owner = minter - nft.TokenURI = tokenURI - - nftKey, err := ctx.GetStub().CreateCompositeKey(nftPrefix, []string{tokenId}) - if err != nil { - return nil, fmt.Errorf("failed to CreateCompositeKey to nftKey: %v", err) - } - - nftBytes, err := json.Marshal(nft) - if err != nil { - return nil, fmt.Errorf("failed to marshal nft: %v", err) - } - - err = ctx.GetStub().PutState(nftKey, nftBytes) - if err != nil { - return nil, fmt.Errorf("failed to PutState nftBytes %s: %v", nftBytes, err) - } - - // A composite key would be balancePrefix.owner.tokenId, which enables partial - // composite key query to find and count all records matching balance.owner.* - // An empty value would represent a delete, so we simply insert the null character. - - balanceKey, err := ctx.GetStub().CreateCompositeKey(balancePrefix, []string{minter, tokenId}) - if err != nil { - return nil, fmt.Errorf("failed to CreateCompositeKey to balanceKey: %v", err) - } - - err = ctx.GetStub().PutState(balanceKey, []byte{'\u0000'}) - if err != nil { - return nil, fmt.Errorf("failed to PutState balanceKey %s: %v", nftBytes, err) - } - - // Emit the Transfer event - transferEvent := new(Transfer) - transferEvent.From = "0x0" - transferEvent.To = minter - transferEvent.TokenId = tokenId - - transferEventBytes, err := json.Marshal(transferEvent) - if err != nil { - return nil, fmt.Errorf("failed to marshal transferEventBytes: %v", err) - } - - err = ctx.GetStub().SetEvent("Transfer", transferEventBytes) - if err != nil { - return nil, fmt.Errorf("failed to SetEvent transferEventBytes %s: %v", transferEventBytes, err) - } - - return nft, nil -} - -// Burn a non-fungible token -// param {String} tokenId Unique ID of a non-fungible token -// returns {Boolean} Return whether the burn was successful or not -func (c *TokenERC721Contract) Burn(ctx contractapi.TransactionContextInterface, tokenId string) (bool, error) { - - // Check if contract has been intilized first - initialized, err := checkInitialized(ctx) - if err != nil { - return false, fmt.Errorf("failed to check if contract is already initialized: %v", err) - } - if !initialized { - return false, errors.New("contract options need to be set before calling any function, call Initialize() to initialize contract") - } - - owner64, err := ctx.GetClientIdentity().GetID() - if err != nil { - return false, fmt.Errorf("failed to GetClientIdentity owner64: %v", err) - } - - ownerBytes, err := base64.StdEncoding.DecodeString(owner64) - if err != nil { - return false, fmt.Errorf("failed to DecodeString owner64: %v", err) - } - owner := string(ownerBytes) - - // Check if a caller is the owner of the non-fungible token - nft, err := _readNFT(ctx, tokenId) - if err != nil { - return false, fmt.Errorf("failed to _readNFT nft : %v", err) - } - if nft.Owner != owner { - return false, fmt.Errorf("non-fungible token %s is not owned by %s", tokenId, owner) - } - - // Delete the token - nftKey, err := ctx.GetStub().CreateCompositeKey(nftPrefix, []string{tokenId}) - if err != nil { - return false, fmt.Errorf("failed to CreateCompositeKey tokenId: %v", err) - } - - err = ctx.GetStub().DelState(nftKey) - if err != nil { - return false, fmt.Errorf("failed to DelState nftKey: %v", err) - } - - // Remove a composite key from the balance of the owner - balanceKey, err := ctx.GetStub().CreateCompositeKey(balancePrefix, []string{owner, tokenId}) - if err != nil { - return false, fmt.Errorf("failed to CreateCompositeKey balanceKey %s: %v", balanceKey, err) - } - - err = ctx.GetStub().DelState(balanceKey) - if err != nil { - return false, fmt.Errorf("failed to DelState balanceKey %s: %v", balanceKey, err) - } - - // Emit the Transfer event - transferEvent := new(Transfer) - transferEvent.From = owner - transferEvent.To = "0x0" - transferEvent.TokenId = tokenId - - transferEventBytes, err := json.Marshal(transferEvent) - if err != nil { - return false, fmt.Errorf("failed to marshal transferEventBytes: %v", err) - } - - err = ctx.GetStub().SetEvent("Transfer", transferEventBytes) - if err != nil { - return false, fmt.Errorf("failed to SetEvent transferEventBytes: %v", err) - } - - return true, nil -} - -// ClientAccountBalance returns the balance of the requesting client's account. -// returns {Number} Returns the account balance -func (c *TokenERC721Contract) ClientAccountBalance(ctx contractapi.TransactionContextInterface) (int, error) { - - // Check if contract has been intilized first - initialized, err := checkInitialized(ctx) - if err != nil { - return 0, fmt.Errorf("failed to check if contract is already initialized: %v", err) - } - if !initialized { - return 0, errors.New("contract options need to be set before calling any function, call Initialize() to initialize contract") - } - - // Get ID of submitting client identity - clientAccountID64, err := ctx.GetClientIdentity().GetID() - if err != nil { - return 0, fmt.Errorf("failed to GetClientIdentity minter: %v", err) - } - - clientAccountIDBytes, err := base64.StdEncoding.DecodeString(clientAccountID64) - if err != nil { - return 0, fmt.Errorf("failed to DecodeString sender: %v", err) - } - - clientAccountID := string(clientAccountIDBytes) - - return c.BalanceOf(ctx, clientAccountID), nil -} - -// ClientAccountID returns the id of the requesting client's account. -// In this implementation, the client account ID is the clientId itself. -// Users can use this function to get their own account id, which they can then give to others as the payment address - -func (c *TokenERC721Contract) ClientAccountID(ctx contractapi.TransactionContextInterface) (string, error) { - - // Check if contract has been intilized first - initialized, err := checkInitialized(ctx) - if err != nil { - return "", fmt.Errorf("failed to check if contract is already initialized: %v", err) - } - if !initialized { - return "", errors.New("contract options need to be set before calling any function, call Initialize() to initialize contract") - } - - // Get ID of submitting client identity - clientAccountID64, err := ctx.GetClientIdentity().GetID() - if err != nil { - return "", fmt.Errorf("failed to GetClientIdentity minter: %v", err) - } - - clientAccountBytes, err := base64.StdEncoding.DecodeString(clientAccountID64) - if err != nil { - return "", fmt.Errorf("failed to DecodeString clientAccount64: %v", err) - } - clientAccount := string(clientAccountBytes) - - return clientAccount, nil -} - -// Checks that contract options have been already initialized -func checkInitialized(ctx contractapi.TransactionContextInterface) (bool, error) { - tokenName, err := ctx.GetStub().GetState(nameKey) - if err != nil { - return false, fmt.Errorf("failed to get token name: %v", err) - } - if tokenName == nil { - return false, nil - } - return true, nil -} diff --git a/token-erc-721/chaincode-go/chaincode/erc721-contract_test.go b/token-erc-721/chaincode-go/chaincode/erc721-contract_test.go deleted file mode 100644 index 50fe8a63..00000000 --- a/token-erc-721/chaincode-go/chaincode/erc721-contract_test.go +++ /dev/null @@ -1,282 +0,0 @@ -package chaincode - -import ( - "encoding/base64" - "testing" - - "github.com/hyperledger/fabric-chaincode-go/v2/pkg/cid" - "github.com/hyperledger/fabric-chaincode-go/v2/shim" - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" - "github.com/hyperledger/fabric-protos-go-apiv2/ledger/queryresult" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" -) - -const owner = "x509::CN=minter,OU=client,O=Hyperledger,ST=North Carolina,C=US::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=US" -const operator = "x509::CN=org,OU=client,O=Hyperledger,ST=North Carolina,C=US::CN=ca.org1.example.com,O=org1.example.com,L=Durham,ST=North Carolina,C=AR" - -type MockStub struct { - shim.ChaincodeStubInterface - mock.Mock -} - -func (ms *MockStub) GetStateByPartialCompositeKey(objectType string, keys []string) (shim.StateQueryIteratorInterface, error) { - args := ms.Called(objectType, keys) - return args.Get(0).(shim.StateQueryIteratorInterface), args.Error(1) -} - -func (ms *MockStub) GetState(key string) ([]byte, error) { - args := ms.Called(key) - return args.Get(0).([]byte), args.Error(1) -} - -func (ms *MockStub) PutState(key string, value []byte) error { - args := ms.Called(key, value) - return args.Error(0) -} -func (ms *MockStub) SetEvent(key string, value []byte) error { - args := ms.Called(key, value) - return args.Error(0) -} - -func (ms *MockStub) DelState(key string) error { - args := ms.Called(key) - return args.Error(0) -} - -func (ms *MockStub) CreateCompositeKey(objectType string, attributes []string) (string, error) { - args := ms.Called(objectType, attributes) - return args.Get(0).(string), args.Error(1) -} - -type MockClientIdentity struct { - cid.ClientIdentity - mock.Mock -} - -func (mci *MockClientIdentity) GetID() (string, error) { - args := mci.Called() - return args.Get(0).(string), args.Error(1) -} - -func (mci *MockClientIdentity) GetMSPID() (string, error) { - args := mci.Called() - return args.Get(0).(string), args.Error(1) -} - -func (mc *MockContext) GetStub() shim.ChaincodeStubInterface { - args := mc.Called() - return args.Get(0).(*MockStub) -} - -type MockContext struct { - contractapi.TransactionContextInterface - mock.Mock -} - -func (mc *MockContext) GetClientIdentity() cid.ClientIdentity { - args := mc.Called() - return args.Get(0).(*MockClientIdentity) -} - -type MockIterator struct { - shim.StateQueryIteratorInterface - queryresult.KV -} - -func (it *MockIterator) HasNext() bool { - return false -} - -func setupStub() (*MockContext, *MockStub) { - balancePrefix := "balance" - approvalPrefix := "approval" - nftPrefix := "nft" - mockTokenId := "101" - anyString := mock.AnythingOfType("string") - anyUint8Slice := mock.AnythingOfType("[]uint8") - nftStr := "{\"tokenId\":\"101\",\"owner\":\"" + owner + "\",\"tokenURI\":\"https://example.com/nft101.json\",\"approved\":\"" + operator + "\"}" - approvalStr := "{\"owner\":\"" + owner + "\",\"operator\":\"" + owner + "\",\"approved\":true}" - - ms := new(MockStub) - iterator := new(MockIterator) - - ms.On("GetStateByPartialCompositeKey", balancePrefix, []string{owner}).Return(iterator, nil) - ms.On("GetStateByPartialCompositeKey", nftPrefix, []string{}).Return(iterator, nil) - - ms.On("CreateCompositeKey", nftPrefix, []string{mockTokenId}).Return("nft101", nil) - ms.On("CreateCompositeKey", nftPrefix, []string{"102"}).Return("nft102", nil) - ms.On("CreateCompositeKey", approvalPrefix, []string{owner, owner}).Return(approvalPrefix+owner+owner, nil) - ms.On("CreateCompositeKey", approvalPrefix, []string{owner, operator}).Return(approvalPrefix+owner+operator, nil) - ms.On("CreateCompositeKey", balancePrefix, []string{owner, mockTokenId}).Return(balancePrefix+owner+mockTokenId, nil) - ms.On("CreateCompositeKey", balancePrefix, []string{operator, mockTokenId}).Return(balancePrefix+operator+mockTokenId, nil) - ms.On("CreateCompositeKey", balancePrefix, []string{owner, "102"}).Return(balancePrefix+owner+mockTokenId, nil) - - ms.On("GetState", "nft101").Return([]byte(nftStr), nil) - ms.On("GetState", "nft102").Return([]uint8{}, nil) - ms.On("GetState", approvalPrefix+owner+owner).Return([]byte(approvalStr), nil) - ms.On("GetState", "name").Return([]byte("lala"), nil) - ms.On("GetState", "symbol").Return([]byte("lelo"), nil) - - ms.On("PutState", "name", []byte("someName")).Return(nil) - ms.On("PutState", "symbol", []byte("someSymbol")).Return(nil) - ms.On("PutState", anyString, anyUint8Slice).Return(nil) - ms.On("PutState", balancePrefix+owner+"101", []byte{0}).Return(nil) - ms.On("PutState", balancePrefix+owner+"102", []byte{'\u0000'}).Return(nil) - ms.On("PutState", "nft101", []byte("nft101")).Return(nil) - ms.On("PutState", "nft102", []byte("nft102")).Return(nil) - - ms.On("SetEvent", "ApprovalForAll", anyUint8Slice).Return(nil) - ms.On("SetEvent", "Transfer", anyUint8Slice).Return(nil) - - ms.On("DelState", anyString).Return(nil) - - mci := new(MockClientIdentity) - owner64 := base64.StdEncoding.EncodeToString([]byte(owner)) - operator64 := base64.StdEncoding.EncodeToString([]byte(owner)) - - mci.On("GetID").Return(owner64, nil) - mci.On("GetID").Return(operator64, nil) - mci.On("GetMSPID").Return("Org1MSP", nil) - - mc := new(MockContext) - mc.On("GetStub").Return(ms) - mc.On("GetClientIdentity").Return(mci) - return mc, ms -} - -func TestBalanceOf(t *testing.T) { - ctx, _ := setupStub() - c := new(TokenERC721Contract) - - balance := c.BalanceOf(ctx, owner) - assert.Equal(t, 0, balance) - -} -func TestTotalSupply(t *testing.T) { - ctx, _ := setupStub() - c := new(TokenERC721Contract) - totalNft := c.TotalSupply(ctx) - assert.Equal(t, 0, totalNft) - -} - -func TestOwnerOf(t *testing.T) { - ctx, _ := setupStub() - c := new(TokenERC721Contract) - - owner, _ := c.OwnerOf(ctx, "101") - assert.Equal(t, owner, owner) - -} - -func TestApprove(t *testing.T) { - ctx, _ := setupStub() - c := new(TokenERC721Contract) - - approved, _ := c.Approve(ctx, "", "101") - assert.Equal(t, true, approved) - -} - -func TestSetApprovalForAll(t *testing.T) { - ctx, _ := setupStub() - c := new(TokenERC721Contract) - - appAll, _ := c.SetApprovalForAll(ctx, operator, true) - assert.Equal(t, true, appAll) - -} - -func TestIsApprovedForAll(t *testing.T) { - ctx, _ := setupStub() - c := new(TokenERC721Contract) - - isApp, _ := c.SetApprovalForAll(ctx, operator, true) - assert.Equal(t, true, isApp) - -} - -func TestGetApproved(t *testing.T) { - ctx, _ := setupStub() - c := new(TokenERC721Contract) - - getApp, _ := c.GetApproved(ctx, "101") - assert.Equal(t, ""+operator+"", getApp) -} - -func TestTransferFrom(t *testing.T) { - ctx, _ := setupStub() - c := new(TokenERC721Contract) - - transfer, _ := c.TransferFrom(ctx, owner, operator, "101") - - assert.Equal(t, true, transfer) -} - -func TestName(t *testing.T) { - ctx, _ := setupStub() - c := new(TokenERC721Contract) - - name, _ := c.Name(ctx) - - assert.Equal(t, "lala", name) -} - -func TestSymbol(t *testing.T) { - ctx, _ := setupStub() - c := new(TokenERC721Contract) - - symbol, _ := c.Symbol(ctx) - - assert.Equal(t, "lelo", symbol) -} - -func TestTokenURI(t *testing.T) { - ctx, _ := setupStub() - c := new(TokenERC721Contract) - - tokenURI, _ := c.TokenURI(ctx, "101") - - assert.Equal(t, "https://example.com/nft101.json", tokenURI) -} - -func TestInitialize(t *testing.T) { - ctx, _ := setupStub() - c := new(TokenERC721Contract) - - option, _ := c.Initialize(ctx, "someName", "someSymbol") - assert.Equal(t, true, option) -} - -func TestMintWithTokenURI(t *testing.T) { - ctx, _ := setupStub() - c := new(TokenERC721Contract) - - mint, _ := c.MintWithTokenURI(ctx, "102", "https://example.com/nft102.json") - - nft := new(Nft) - nft.Owner = owner - nft.TokenId = "102" - nft.TokenURI = "https://example.com/nft102.json" - - assert.Equal(t, nft.Owner, mint.Owner) - assert.Equal(t, nft, mint) - -} - -func TestBurn(t *testing.T) { - ctx, _ := setupStub() - c := new(TokenERC721Contract) - - burn, _ := c.Burn(ctx, "101") - assert.Equal(t, true, burn) -} - -func TestClientAccoundId(t *testing.T) { - ctx, _ := setupStub() - c := new(TokenERC721Contract) - client, _ := c.ClientAccountID(ctx) - assert.Equal(t, owner, client) -} diff --git a/token-erc-721/chaincode-go/chaincode/erc721.go b/token-erc-721/chaincode-go/chaincode/erc721.go deleted file mode 100644 index 5302f4d5..00000000 --- a/token-erc-721/chaincode-go/chaincode/erc721.go +++ /dev/null @@ -1,25 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ - -package chaincode - -// Define structs to be used by chaincode -type Nft struct { - TokenId string `json:"tokenId"` - Owner string `json:"owner"` - TokenURI string `json:"tokenURI"` - Approved string `json:"approved"` -} - -type Approval struct { - Owner string `json:"owner"` - Operator string `json:"operator"` - Approved bool `json:"approved"` -} - -type Transfer struct { - From string `json:"from"` - To string `json:"to"` - TokenId string `json:"tokenId"` -} diff --git a/token-erc-721/chaincode-go/go.mod b/token-erc-721/chaincode-go/go.mod deleted file mode 100644 index 57d048f5..00000000 --- a/token-erc-721/chaincode-go/go.mod +++ /dev/null @@ -1,38 +0,0 @@ -module github.com/hyperledger/fabric-samples/token-erc-721/chaincode-go - -go 1.21 - -require ( - github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0-20240618210511-f7903324a8af - github.com/hyperledger/fabric-contract-api-go/v2 v2.0.0 - github.com/hyperledger/fabric-protos-go-apiv2 v0.3.3 - github.com/stretchr/testify v1.9.0 -) - -require ( - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/go-openapi/jsonpointer v0.21.0 // indirect - github.com/go-openapi/jsonreference v0.21.0 // indirect - github.com/go-openapi/spec v0.21.0 // indirect - github.com/go-openapi/swag v0.23.0 // indirect - github.com/gobuffalo/envy v1.10.2 // indirect - github.com/gobuffalo/packd v1.0.2 // indirect - github.com/gobuffalo/packr v1.30.1 // indirect - github.com/joho/godotenv v1.5.1 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/mailru/easyjson v0.7.7 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/rogpeppe/go-internal v1.12.0 // indirect - github.com/stretchr/objx v0.5.2 // indirect - github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect - github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect - github.com/xeipuuv/gojsonschema v1.2.0 // indirect - golang.org/x/mod v0.17.0 // indirect - golang.org/x/net v0.24.0 // indirect - golang.org/x/sys v0.19.0 // indirect - golang.org/x/text v0.14.0 // indirect - google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect - google.golang.org/grpc v1.64.0 // indirect - google.golang.org/protobuf v1.34.2 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) diff --git a/token-erc-721/chaincode-go/go.sum b/token-erc-721/chaincode-go/go.sum deleted file mode 100644 index 7c5e414c..00000000 --- a/token-erc-721/chaincode-go/go.sum +++ /dev/null @@ -1,132 +0,0 @@ -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= -github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= -github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= -github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= -github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= -github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= -github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= -github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= -github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= -github.com/gobuffalo/envy v1.10.2 h1:EIi03p9c3yeuRCFPOKcSfajzkLb3hrRjEpHGI8I2Wo4= -github.com/gobuffalo/envy v1.10.2/go.mod h1:qGAGwdvDsaEtPhfBzb3o0SfDea8ByGn9j8bKmVft9z8= -github.com/gobuffalo/logger v1.0.0/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs= -github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q= -github.com/gobuffalo/packd v1.0.2 h1:Yg523YqnOxGIWCp69W12yYBKsoChwI7mtu6ceM9Bwfw= -github.com/gobuffalo/packd v1.0.2/go.mod h1:sUc61tDqGMXON80zpKGp92lDb86Km28jfvX7IAyxFT8= -github.com/gobuffalo/packr v1.30.1 h1:hu1fuVR3fXEZR7rXNW3h8rqSML8EVAf6KNm0NKO/wKg= -github.com/gobuffalo/packr v1.30.1/go.mod h1:ljMyFO2EcrnzsHsN99cvbq055Y9OhRrIaviy289eRuk= -github.com/gobuffalo/packr/v2 v2.5.1/go.mod h1:8f9c96ITobJlPzI44jj+4tHnEKNt0xXWSVlXRN9X1Iw= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0-20240618210511-f7903324a8af h1:WT4NjX7Uk03GSeH++jF3a0wp4FhybTM86zDPCETvmSk= -github.com/hyperledger/fabric-chaincode-go/v2 v2.0.0-20240618210511-f7903324a8af/go.mod h1:f/ER25FaBepxJugwpLhbD2hLAoZaZEVqkBjOcHjw72Y= -github.com/hyperledger/fabric-contract-api-go/v2 v2.0.0 h1:IDiCGVOBlRd6zpL0Y+f6V7IpBqa4/Z5JAK9SF7a5ea8= -github.com/hyperledger/fabric-contract-api-go/v2 v2.0.0/go.mod h1:pdqhe7ALf4lmXgQdprCyNWYdnCPxgj02Vhf8JF5w8po= -github.com/hyperledger/fabric-protos-go-apiv2 v0.3.3 h1:Xpd6fzG/KjAOHJsq7EQXY2l+qi/y8muxBaY7R6QWABk= -github.com/hyperledger/fabric-protos-go-apiv2 v0.3.3/go.mod h1:2pq0ui6ZWA0cC8J+eCErgnMDCS1kPOEYVY+06ZAK0qE= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= -github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= -github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= -github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= -golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= -google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/token-erc-721/chaincode-go/main.go b/token-erc-721/chaincode-go/main.go deleted file mode 100644 index b0b2b38a..00000000 --- a/token-erc-721/chaincode-go/main.go +++ /dev/null @@ -1,35 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ - -package main - -import ( - "github.com/hyperledger/fabric-contract-api-go/v2/contractapi" - "github.com/hyperledger/fabric-contract-api-go/v2/metadata" - "github.com/hyperledger/fabric-samples/token-erc-721/chaincode-go/chaincode" -) - -func main() { - nftContract := new(chaincode.TokenERC721Contract) - nftContract.Info.Version = "0.0.1" - nftContract.Info.Description = "ERC-721 fabric port" - nftContract.Info.License = new(metadata.LicenseMetadata) - nftContract.Info.License.Name = "Apache-2.0" - nftContract.Info.Contact = new(metadata.ContactMetadata) - nftContract.Info.Contact.Name = "Matias Salimbene" - - chaincode, err := contractapi.NewChaincode(nftContract) - chaincode.Info.Title = "ERC-721 chaincode" - chaincode.Info.Version = "0.0.1" - - if err != nil { - panic("Could not create chaincode from TokenERC721Contract." + err.Error()) - } - - err = chaincode.Start() - - if err != nil { - panic("Failed to start chaincode. " + err.Error()) - } -} diff --git a/token-erc-721/chaincode-java/Dockerfile b/token-erc-721/chaincode-java/Dockerfile deleted file mode 100755 index e5992148..00000000 --- a/token-erc-721/chaincode-java/Dockerfile +++ /dev/null @@ -1,30 +0,0 @@ -# the first stage -FROM gradle:jdk11 AS GRADLE_BUILD - -# copy the build.gradle and src code to the container -COPY src/ src/ -COPY build.gradle ./ - -# Build and package our code -RUN gradle --no-daemon build shadowJar -x checkstyleMain -x checkstyleTest - -# the second stage of our build just needs the compiled files -FROM openjdk:11-jre -ARG CC_SERVER_PORT=9999 - -# Setup tini to work better handle signals -ENV TINI_VERSION v0.19.0 -ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini -RUN chmod +x /tini - -RUN addgroup --system javauser && useradd -g javauser javauser - -# copy only the artifacts we need from the first stage and discard the rest -COPY --chown=javauser:javauser --from=GRADLE_BUILD /home/gradle/build/libs/chaincode.jar /chaincode.jar -COPY --chown=javauser:javauser docker/docker-entrypoint.sh /docker-entrypoint.sh -RUN chmod +x /docker-entrypoint.sh -ENV PORT $CC_SERVER_PORT -EXPOSE $CC_SERVER_PORT - -USER javauser -ENTRYPOINT [ "/tini", "--", "/docker-entrypoint.sh" ] diff --git a/token-erc-721/chaincode-java/build.gradle b/token-erc-721/chaincode-java/build.gradle deleted file mode 100755 index 3f94609b..00000000 --- a/token-erc-721/chaincode-java/build.gradle +++ /dev/null @@ -1,97 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ - -plugins { - id 'com.github.johnrengelman.shadow' version '8.1.1' - id 'application' - id 'checkstyle' - id 'jacoco' -} - -group 'org.hyperledger.fabric.samples' -version '1.0-SNAPSHOT' - -dependencies { - - implementation 'org.hyperledger.fabric-chaincode-java:fabric-chaincode-shim:2.5.+' - implementation 'org.json:json:+' - implementation 'com.owlike:genson:1.5' - testImplementation 'org.junit.jupiter:junit-jupiter:5.10.2' - testImplementation 'org.assertj:assertj-core:3.25.3' - testImplementation 'org.mockito:mockito-core:5.12.0' - testRuntimeOnly("net.bytebuddy:byte-buddy:1.10.6") - -} - -repositories { - mavenCentral() - maven { - url 'https://jitpack.io' - } -} - -java { - toolchain { - languageVersion = JavaLanguageVersion.of(11) - } -} - -application { - mainClass = 'org.hyperledger.fabric.contract.ContractRouter' -} - -checkstyle { - toolVersion '8.21' - configFile file("config/checkstyle/checkstyle.xml") -} - -checkstyleMain { - source ='src/main/java' -} - -checkstyleTest { - source ='src/test/java' -} - -jacocoTestReport { - dependsOn test -} - -jacocoTestCoverageVerification { - violationRules { - rule { - limit { - minimum = 0.8 - } - } - } - - finalizedBy jacocoTestReport -} - -test { - useJUnitPlatform() - testLogging { - showStandardStreams = true - } - testLogging { - events "passed", "skipped", "failed" - } -} - -mainClassName = 'org.hyperledger.fabric.contract.ContractRouter' - -shadowJar { - archiveBaseName = 'chaincode' - archiveVersion = '' - archiveClassifier = '' - mergeServiceFiles() - - manifest { - attributes 'Main-Class': 'org.hyperledger.fabric.contract.ContractRouter' - } -} - -check.dependsOn jacocoTestCoverageVerification -installDist.dependsOn check diff --git a/token-erc-721/chaincode-java/config/checkstyle/checkstyle.xml b/token-erc-721/chaincode-java/config/checkstyle/checkstyle.xml deleted file mode 100644 index deafca76..00000000 --- a/token-erc-721/chaincode-java/config/checkstyle/checkstyle.xml +++ /dev/null @@ -1,174 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/token-erc-721/chaincode-java/config/checkstyle/suppressions.xml b/token-erc-721/chaincode-java/config/checkstyle/suppressions.xml deleted file mode 100644 index f3b0387f..00000000 --- a/token-erc-721/chaincode-java/config/checkstyle/suppressions.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - diff --git a/token-erc-721/chaincode-java/docker/docker-entrypoint.sh b/token-erc-721/chaincode-java/docker/docker-entrypoint.sh deleted file mode 100755 index 1ff8e07e..00000000 --- a/token-erc-721/chaincode-java/docker/docker-entrypoint.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env bash -# -# SPDX-License-Identifier: Apache-2.0 -# -set -euo pipefail -: ${CORE_PEER_TLS_ENABLED:="false"} -: ${DEBUG:="false"} - -if [ "${DEBUG,,}" = "true" ]; then - exec java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=0.0.0.0:8000 -jar /chaincode.jar -elif [ "${CORE_PEER_TLS_ENABLED,,}" = "true" ]; then - exec java -jar /chaincode.jar # todo -else - exec java -jar /chaincode.jar -fi - diff --git a/token-erc-721/chaincode-java/gradle/wrapper/gradle-wrapper.jar b/token-erc-721/chaincode-java/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 7f93135c49b765f8051ef9d0a6055ff8e46073d8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 63721 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鯊%1Et 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⁢ zv5o9#E7!G0XmdzfsS{efPNi`1b44~SZ4Z8fuX!I}#8g+(wxzQwUT#Xb2(tbY1+EUhGKoT@KEU9Ktl>_0 z%bjDJg;#*gtJZv!-Zs`?^}v5eKmnbjqlvnSzE@_SP|LG_PJ6CYU+6zY6>92%E+ z=j@TZf-iW4(%U{lnYxQA;7Q!b;^brF8n0D>)`q5>|WDDXLrqYU_tKN2>=#@~OE7grMnNh?UOz-O~6 z6%rHy{#h9K0AT+lDC7q4{hw^|q6*Ry;;L%Q@)Ga}$60_q%D)rv(CtS$CQbpq9|y1e zRSrN4;$Jyl{m5bZw`$8TGvb}(LpY{-cQ)fcyJv7l3S52TLXVDsphtv&aPuDk1OzCA z4A^QtC(!11`IsNx_HnSy?>EKpHJWT^wmS~hc^p^zIIh@9f6U@I2 zC=Mve{j2^)mS#U$e{@Q?SO6%LDsXz@SY+=cK_QMmXBIU)j!$ajc-zLx3V60EXJ!qC zi<%2x8Q24YN+&8U@CIlN zrZkcT9yh%LrlGS9`G)KdP(@9Eo-AQz@8GEFWcb7U=a0H^ZVbLmz{+&M7W(nXJ4sN8 zJLR7eeK(K8`2-}j(T7JsO`L!+CvbueT%izanm-^A1Dn{`1Nw`9P?cq;7no+XfC`K(GO9?O^5zNIt4M+M8LM0=7Gz8UA@Z0N+lg+cX)NfazRu z5D)~HA^(u%w^cz+@2@_#S|u>GpB+j4KzQ^&Wcl9f z&hG#bCA(Yk0D&t&aJE^xME^&E-&xGHhXn%}psEIj641H+Nl-}boj;)Zt*t(4wZ5DN z@GXF$bL=&pBq-#vkTkh>7hl%K5|3 z{`Vn9b$iR-SoGENp}bn4;fR3>9sA%X2@1L3aE9yTra;Wb#_`xWwLSLdfu+PAu+o3| zGVnpzPr=ch{uuoHjtw7+_!L_2;knQ!DuDl0R`|%jr+}jFzXtrHIKc323?JO{l&;VF z*L1+}JU7%QJOg|5|Tc|D8fN zJORAg=_vsy{ak|o);@)Yh8Lkcg@$FG3k@ep36BRa^>~UmnRPziS>Z=`Jb2x*Q#`%A zU*i3&Vg?TluO@X0O;r2Jl6LKLUOVhSqg1*qOt^|8*c7 zo(298@+r$k_wQNGHv{|$tW(T8L+4_`FQ{kEW5Jgg{yf7ey4ss_(SNKfz(N9lx&a;< je(UuV8hP?p&}TPdm1I$XmG#(RzlD&B2izSj9sl%y5~4qc diff --git a/token-erc-721/chaincode-java/gradle/wrapper/gradle-wrapper.properties b/token-erc-721/chaincode-java/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index a80b22ce..00000000 --- a/token-erc-721/chaincode-java/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,7 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip -networkTimeout=10000 -validateDistributionUrl=true -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/token-erc-721/chaincode-java/gradlew b/token-erc-721/chaincode-java/gradlew deleted file mode 100755 index 0adc8e1a..00000000 --- a/token-erc-721/chaincode-java/gradlew +++ /dev/null @@ -1,249 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -# This is normally unused -# shellcheck disable=SC2034 -APP_BASE_NAME=${0##*/} -# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - if ! command -v java >/dev/null 2>&1 - then - die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/token-erc-721/chaincode-java/gradlew.bat b/token-erc-721/chaincode-java/gradlew.bat deleted file mode 100755 index 6689b85b..00000000 --- a/token-erc-721/chaincode-java/gradlew.bat +++ /dev/null @@ -1,92 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/token-erc-721/chaincode-java/settings.gradle b/token-erc-721/chaincode-java/settings.gradle deleted file mode 100755 index 241078cf..00000000 --- a/token-erc-721/chaincode-java/settings.gradle +++ /dev/null @@ -1,5 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ - -rootProject.name = 'token_erc721' diff --git a/token-erc-721/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc721/ContractConstants.java b/token-erc-721/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc721/ContractConstants.java deleted file mode 100644 index 3b8b2283..00000000 --- a/token-erc-721/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc721/ContractConstants.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.fabric.samples.erc721; - -public enum ContractConstants { - BALANCE("balance"), - NFT("nft"), - APPROVAL("approval"), - NAMEKEY("nameKey"), - SYMBOLKEY("symbolKey"), - APPROVE_FOR_ALL("ApproveForAll"), - TRANSFER("Transfer"), - MINTER_ORG_MSP("Org1MSP"); - private final String prefix; - - ContractConstants(final String value) { - this.prefix = value; - } - - public String getValue() { - return prefix; - } -} diff --git a/token-erc-721/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc721/ContractErrors.java b/token-erc-721/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc721/ContractErrors.java deleted file mode 100644 index ab340142..00000000 --- a/token-erc-721/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc721/ContractErrors.java +++ /dev/null @@ -1,13 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.fabric.samples.erc721; - -public enum ContractErrors { - TOKEN_NOT_FOUND, - TOKEN_ALREADY_EXITS, - NO_OWNER_ASSIGNED, - UNAUTHORIZED_SENDER, - TOKEN_NONOWNER, - INVALID_TOKEN_OWNER -} diff --git a/token-erc-721/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc721/ERC721TokenContract.java b/token-erc-721/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc721/ERC721TokenContract.java deleted file mode 100644 index 5aa2c159..00000000 --- a/token-erc-721/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc721/ERC721TokenContract.java +++ /dev/null @@ -1,491 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ - -package org.hyperledger.fabric.samples.erc721; - -import org.hyperledger.fabric.contract.Context; -import org.hyperledger.fabric.contract.ContractInterface; -import org.hyperledger.fabric.contract.annotation.Transaction; -import org.hyperledger.fabric.contract.annotation.Default; -import org.hyperledger.fabric.contract.annotation.Info; -import org.hyperledger.fabric.contract.annotation.License; -import org.hyperledger.fabric.contract.annotation.Contact; -import org.hyperledger.fabric.contract.annotation.Contract; -import org.hyperledger.fabric.samples.erc721.models.Approval; -import org.hyperledger.fabric.samples.erc721.models.NFT; -import org.hyperledger.fabric.samples.erc721.models.Transfer; -import org.hyperledger.fabric.shim.ChaincodeException; -import org.hyperledger.fabric.shim.ChaincodeStub; -import org.hyperledger.fabric.shim.ledger.CompositeKey; -import org.hyperledger.fabric.shim.ledger.KeyValue; -import org.hyperledger.fabric.shim.ledger.QueryResultsIterator; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.hyperledger.fabric.samples.erc721.utils.ContractUtility.stringIsNullOrEmpty; - -@Contract( - name = "erc721token", - info = - @Info( - title = "ERC721Token Contract", - description = "The erc721 NFT implementation", - version = "0.0.1-SNAPSHOT", - license = - @License( - name = "Apache 2.0 License", - url = "http://www.apache.org/licenses/LICENSE-2.0.html"), - contact = - @Contact( - email = "renjith.narayanan@gmail.com", - name = "Renjith Narayanan", - url = "https://hyperledger.example.com"))) -@Default -public class ERC721TokenContract implements ContractInterface { - - /** - * BalanceOf counts all non-fungible tokens assigned to an owner.There is a key record for every - * non-fungible token in the format of balancePrefix.owner.tokenId. balanceOf() queries for and - * counts all records matching balancePrefix.owner.* - * - * @param ctx the transaction context - * @param owner An owner for whom to query the balance - * @return The number of non-fungible tokens owned by the owner, possibly zero - */ - @Transaction(intent = Transaction.TYPE.EVALUATE) - public long BalanceOf(final Context ctx, final String owner) { - // Check contract options are already set first to execute the function - this.checkInitialized(ctx); - final ChaincodeStub stub = ctx.getStub(); - final CompositeKey balanceKey = - stub.createCompositeKey(ContractConstants.BALANCE.getValue(), owner); - final QueryResultsIterator results = stub.getStateByPartialCompositeKey(balanceKey); - long balance = 0; - for (KeyValue result : results) { - if (!stringIsNullOrEmpty(result.getStringValue())) { - balance++; - } - } - return balance; - } - - /** - * Finds the owner of a non-fungible token. - * - * @param ctx the transaction context - * @param tokenId the identifier for a non-fungible token. - * @return return the owner of the non-fungible token. - */ - @Transaction(intent = Transaction.TYPE.EVALUATE) - public String OwnerOf(final Context ctx, final String tokenId) { - // Check contract options are already set first to execute the function - this.checkInitialized(ctx); - final NFT nft = this._readNft(ctx, tokenId); - if (stringIsNullOrEmpty(nft.getOwner())) { - final String errorMessage = String.format("No owner is assigned o the token %s", tokenId); - throw new ChaincodeException(errorMessage, ContractErrors.NO_OWNER_ASSIGNED.toString()); - } - return nft.getOwner(); - } - - /** - * It returns if a client is an authorized operator for another client. - * - * @param ctx the transaction context - * @param owner The client that owns the non-fungible tokens - * @param operator The client that acts on behalf of the owner - * @return Return true if the operator is an approved operator for the owner, false otherwise - */ - @Transaction(intent = Transaction.TYPE.EVALUATE) - public boolean IsApprovedForAll(final Context ctx, final String owner, final String operator) { - // Check contract options are already set first to execute the function - this.checkInitialized(ctx); - final ChaincodeStub stub = ctx.getStub(); - final CompositeKey approvalKey = - stub.createCompositeKey(ContractConstants.APPROVAL.getValue(), owner, operator); - final String approvalJson = stub.getStringState(approvalKey.toString()); - if (stringIsNullOrEmpty(approvalJson)) { - return false; - } else { - final Approval approval = Approval.fromJSONString(approvalJson); - return approval.isApproved(); - } - } - - /** - * Approve changes or reaffirms the approved client for a non-fungible token. The function update - * the approved operator of the non-fungible token. - * - * @param ctx the transaction context - * @param operator: operator The new approved client - * @param tokenId: tokenId the non-fungible token to approve - */ - @Transaction(intent = Transaction.TYPE.SUBMIT) - public void Approve(final Context ctx, final String operator, final String tokenId) { - // Check contract options are already set first to execute the function - this.checkInitialized(ctx); - final ChaincodeStub stub = ctx.getStub(); - final String sender = ctx.getClientIdentity().getId(); - NFT nft = this._readNft(ctx, tokenId); - final String owner = nft.getOwner(); - final boolean operatorApproval = this.IsApprovedForAll(ctx, owner, sender); - if ((!owner.equalsIgnoreCase(sender)) && (!operatorApproval)) { - final String errorMessage = - String.format( - "The sender %s is not the current owner nor an authorized operator of the token %s.", - sender, tokenId); - throw new ChaincodeException(errorMessage, ContractErrors.UNAUTHORIZED_SENDER.toString()); - } - - nft.setApproved(operator); - final CompositeKey nftKey = stub.createCompositeKey(ContractConstants.NFT.getValue(), tokenId); - stub.putStringState(nftKey.toString(), nft.toJSONString()); - } - - /** - * Enables or disables approval for a third party ("operator") to manage all the message sender's - * assets. - * - * @param ctx the transaction context - * @param operator A client to add to the set of authorized operators - * @param approved: True if the operator is approved, false to revoke approval - */ - @Transaction(intent = Transaction.TYPE.SUBMIT) - public void SetApprovalForAll(final Context ctx, final String operator, final boolean approved) { - // Check contract options are already set first to execute the function - this.checkInitialized(ctx); - final String sender = ctx.getClientIdentity().getId(); - final ChaincodeStub stub = ctx.getStub(); - final Approval nftApproval = new Approval(sender, operator, approved); - final CompositeKey approvalKey = - stub.createCompositeKey(ContractConstants.APPROVAL.getValue(), sender, operator); - stub.putStringState(approvalKey.toString(), nftApproval.toJSONString()); - stub.setEvent( - ContractConstants.APPROVE_FOR_ALL.getValue(), nftApproval.toJSONString().getBytes(UTF_8)); - } - - /** - * Get the approved client for a single non-fungible token. - * - * @param ctx the transaction context - * @param tokenId The non-fungible token to find the approved client for - * @return Return The approved client for this non-fungible token, or null if there is none - */ - @Transaction(intent = Transaction.TYPE.EVALUATE) - public String GetApproved(final Context ctx, final String tokenId) { - // Check contract options are already set first to execute the function - this.checkInitialized(ctx); - final NFT nft = this._readNft(ctx, tokenId); - return nft.getApproved(); - } - - /** - * Transfers the ownership of a non-fungible token from one owner to another owner. - * - * @param ctx the transaction context - * @param from the current owner of the non-fungible token - * @param to the new token owner - * @param tokenId The non-fungible token to transfer - */ - @Transaction(intent = Transaction.TYPE.SUBMIT) - public void TransferFrom( - final Context ctx, final String from, final String to, final String tokenId) { - // Check contract options are already set first to execute the function - this.checkInitialized(ctx); - final String sender = ctx.getClientIdentity().getId(); - final ChaincodeStub stub = ctx.getStub(); - NFT nft = this._readNft(ctx, tokenId); - final String owner = nft.getOwner(); - final String operator = nft.getApproved(); - final boolean operatorApproval = this.IsApprovedForAll(ctx, owner, sender); - if ((!owner.equalsIgnoreCase(sender)) - && !operator.equalsIgnoreCase(sender) - && !operatorApproval) { - final String errorMessage = - String.format( - "The sender %s is not the current owner nor an authorized operator of the token %s.", - sender, tokenId); - throw new ChaincodeException(errorMessage, ContractErrors.UNAUTHORIZED_SENDER.toString()); - } - - // Check if `from` is the current owner - if (!owner.equalsIgnoreCase(from)) { - throw new ChaincodeException( - String.format("The from %s is not the current owner of the token %s.", from, tokenId), - ContractErrors.INVALID_TOKEN_OWNER.toString()); - } - - // Clear the approved client for this non-fungible token - nft.setApproved(""); - - // Overwrite a non-fungible token to assign a new owner. - nft.setOwner(to); - final CompositeKey nftKey = stub.createCompositeKey(ContractConstants.NFT.getValue(), tokenId); - stub.putStringState(nftKey.toString(), nft.toJSONString()); - - // Remove a composite key from the balance of the current owner - final CompositeKey balanceKeyFrom = - stub.createCompositeKey(ContractConstants.BALANCE.getValue(), from, tokenId); - stub.delState(balanceKeyFrom.toString()); - - // Save a composite key to count the balance of a new owner - final CompositeKey balanceKeyTo = - stub.createCompositeKey(ContractConstants.BALANCE.getValue(), to, tokenId); - stub.putState(balanceKeyTo.toString(), Character.toString(Character.MIN_VALUE).getBytes(UTF_8)); - - // Emit the Transfer event - final Transfer transferEvent = new Transfer(from, to, tokenId); - stub.setEvent( - ContractConstants.TRANSFER.getValue(), transferEvent.toJSONString().getBytes(UTF_8)); - } - - // ============== ERC721 metadata extension =============== - - /** - * Returns a descriptive name for a collection of non-fungible tokens in this contract - * - * @param ctx the transaction context - * @return name of the token. - */ - @Transaction(intent = Transaction.TYPE.EVALUATE) - public String Name(final Context ctx) { - // Check contract options are already set first to execute the function - this.checkInitialized(ctx); - return ctx.getStub().getStringState(ContractConstants.NAMEKEY.getValue()); - } - - /** - * Returns an abbreviated name for non-fungible tokens in this contract. - * - * @param ctx the transaction context - * @return token symbol. - */ - @Transaction(intent = Transaction.TYPE.EVALUATE) - public String Symbol(final Context ctx) { - // Check contract options are already set first to execute the function - this.checkInitialized(ctx); - return ctx.getStub().getStringState(ContractConstants.SYMBOLKEY.getValue()); - } - - /** - * Return a distinct Uniform Resource Identifier (URI) for a given token. - * - * @param ctx the transaction context - * @param tokenId the identifier for a non-fungible token - * @return : Returns the URI of the token - */ - @Transaction(intent = Transaction.TYPE.EVALUATE) - public String TokenURI(final Context ctx, final String tokenId) { - // Check contract options are already set first to execute the function - this.checkInitialized(ctx); - final NFT nft = this._readNft(ctx, tokenId); - return nft.getTokenURI(); - } - - /** ============= ERC721 enumeration extension =============== * */ - - /** - * Counts non-fungible tokens tracked by this contract. There is a key record for every - * non-fungible token in the format of nftPrefix.tokenId. The function queries for and counts all - * records matching nftPrefix.* - * - * @param ctx the transaction context - * @return count of valid non-fungible tokens tracked by this contract,where each one of them has - * an assigned and queryable owner. - */ - @Transaction(intent = Transaction.TYPE.EVALUATE) - public long TotalSupply(final Context ctx) { - // Check contract options are already set first to execute the function - this.checkInitialized(ctx); - final ChaincodeStub stub = ctx.getStub(); - final CompositeKey nftKey = stub.createCompositeKey(ContractConstants.NFT.getValue()); - final QueryResultsIterator iterator = stub.getStateByPartialCompositeKey(nftKey); - long totalSupply = 0; - for (KeyValue result : iterator) { - if (!stringIsNullOrEmpty(result.getStringValue())) { - totalSupply++; - } - } - return totalSupply; - } - - /** ============== Extended Functions for this sample =============== * */ - - /** - * Set optional information for a token. - * - * @param ctx the transaction context - * @param name The name of the token - * @param symbol The symbol of the token - */ - @Transaction(intent = Transaction.TYPE.SUBMIT) - public void Initialize(final Context ctx, final String name, final String symbol) { - - final ChaincodeStub stub = ctx.getStub(); - - final String clientMSPID = ctx.getClientIdentity().getMSPID(); - // Check minter authorization - this sample assumes Org1 is the issuer with privilege to set the - // name and symbol - if (!clientMSPID.equalsIgnoreCase(ContractConstants.MINTER_ORG_MSP.getValue())) { - throw new ChaincodeException( - "Client is not authorized to initialize the contract (set the name and symbol of the token)"); - } - - // Check contract options are not already set, client is not authorized to change them once intitialized - String tokenName = stub.getStringState(ContractConstants.NAMEKEY.getValue()); - if (!stringIsNullOrEmpty(tokenName)) { - throw new ChaincodeException("contract options are already set, client is not authorized to change them"); - } - - stub.putStringState(ContractConstants.NAMEKEY.getValue(), name); - stub.putStringState(ContractConstants.SYMBOLKEY.getValue(), symbol); - } - - /** - * Mint a new non-fungible token - * - * @param ctx the transaction context - * @param tokenId Unique ID of the non-fungible token to be minted - * @param tokenURI URI containing metadata of the minted non-fungible token - * @return Return the non-fungible token object - */ - @Transaction(intent = Transaction.TYPE.SUBMIT) - public NFT MintWithTokenURI(final Context ctx, final String tokenId, final String tokenURI) { - // Check contract options are already set first to execute the function - this.checkInitialized(ctx); - final String clientMSPID = ctx.getClientIdentity().getMSPID(); - final ChaincodeStub stub = ctx.getStub(); - // Check minter authorization this sample assumes Org1 is the issuer with privilege to mint a - // new token - if (!clientMSPID.equalsIgnoreCase(ContractConstants.MINTER_ORG_MSP.getValue())) { - throw new ChaincodeException( - "Client is not authorized to set the name and symbol of the token", - ContractErrors.UNAUTHORIZED_SENDER.toString()); - } - final String minter = ctx.getClientIdentity().getId(); - final boolean exists = this._nftExists(ctx, tokenId); - if (exists) { - throw new ChaincodeException( - String.format("The token %s is already minted.", tokenId), - ContractErrors.TOKEN_ALREADY_EXITS.toString()); - } - final NFT nft = new NFT(tokenId, minter, tokenURI, ""); - final CompositeKey nftKey = stub.createCompositeKey(ContractConstants.NFT.getValue(), tokenId); - stub.putStringState(nftKey.toString(), nft.toJSONString()); - // A composite key would be balancePrefix.owner.tokenId, which enables partial - // composite key query to find and count all records matching balance.owner.* - // An empty value would represent a delete, so we simply insert the null character. - final CompositeKey balanceKey = - stub.createCompositeKey(ContractConstants.BALANCE.getValue(), minter, tokenId); - stub.putStringState(balanceKey.toString(), Character.toString(Character.MIN_VALUE)); - final Transfer transferEvent = new Transfer("0x0", minter, tokenId); - stub.setEvent( - ContractConstants.TRANSFER.getValue(), transferEvent.toJSONString().getBytes(UTF_8)); - return nft; - } - - /** - * Burn a non-fungible token - * - * @param ctx the transaction context - * @param tokenId Unique ID of a non-fungible token - */ - @Transaction(intent = Transaction.TYPE.SUBMIT) - public void Burn(final Context ctx, final String tokenId) { - // Check contract options are already set first to execute the function - this.checkInitialized(ctx); - final ChaincodeStub stub = ctx.getStub(); - final String owner = ctx.getClientIdentity().getId(); - // Check if a caller is the owner of the non-fungible token - final NFT nft = this._readNft(ctx, tokenId); - if (!nft.getOwner().equalsIgnoreCase(owner)) { - throw new ChaincodeException( - String.format("Non-fungible token %s is not owned by %s", tokenId, owner), - ContractErrors.TOKEN_NONOWNER.toString()); - } - // Delete the token - final CompositeKey nftKey = stub.createCompositeKey(ContractConstants.NFT.getValue(), tokenId); - stub.delState(nftKey.toString()); - - // Remove a composite key from the balance of the owner - final CompositeKey balanceKey = - stub.createCompositeKey(ContractConstants.BALANCE.getValue(), owner, tokenId); - stub.delState(balanceKey.toString()); - final Transfer transferEvent = new Transfer(owner, "0x0", tokenId); - stub.setEvent( - ContractConstants.TRANSFER.getValue(), transferEvent.toJSONString().getBytes(UTF_8)); - } - - /** - * Returns the balance of the requesting client's account. - * - * @param ctx the transaction context - * @return the account balance - */ - @Transaction(intent = Transaction.TYPE.EVALUATE) - public long ClientAccountBalance(final Context ctx) { - // Check contract options are already set first to execute the function - this.checkInitialized(ctx); - return this.BalanceOf(ctx, ctx.getClientIdentity().getId()); - } - - /** - * Returns the id of the requesting client's account.In this implementation, the client account ID - * is the clientId itself. Users can use this function to get their own account id, which they can - * then give to others as the payment address. - * - * @param ctx the transaction context - * @return sender account id . - */ - @Transaction(intent = Transaction.TYPE.EVALUATE) - public String ClientAccountID(final Context ctx) { - // Check contract options are already set first to execute the function - this.checkInitialized(ctx); - return ctx.getClientIdentity().getId(); - } - - /** - * Get the the NFT details by token id. - * - * @param ctx the transaction context - * @param tokenId Unique ID of a non-fungible token - * @return token details. - */ - private NFT _readNft(final Context ctx, final String tokenId) { - final ChaincodeStub stub = ctx.getStub(); - final CompositeKey nftKey = stub.createCompositeKey(ContractConstants.NFT.getValue(), tokenId); - final String nft = stub.getStringState(nftKey.toString()); - if (stringIsNullOrEmpty(nft)) { - final String errorMessage = String.format("Token with id %s not found!.", tokenId); - throw new ChaincodeException(errorMessage, ContractErrors.TOKEN_NOT_FOUND.toString()); - } - return NFT.fromJSONString(nft); - } - - /** - * Check NFT exits. - * - * @param ctx the transaction context - * @param tokenId Unique ID of a non-fungible token - * @return true if token exits else false. - */ - private boolean _nftExists(final Context ctx, final String tokenId) { - final ChaincodeStub stub = ctx.getStub(); - final CompositeKey nftKey = stub.createCompositeKey(ContractConstants.NFT.getValue(), tokenId); - final String nft = stub.getStringState(nftKey.toString()); - return ((stringIsNullOrEmpty(nft)) ? false : true); - } - - /** - * Checks that contract options have been already initialized - * - * @param ctx the transaction context - * @return the number of decimals - */ - private void checkInitialized(final Context ctx) { - String tokenName = ctx.getStub().getStringState(ContractConstants.NAMEKEY.getValue()); - if (stringIsNullOrEmpty(tokenName)) { - throw new ChaincodeException("Contract options need to be set before calling any function, call Initialize() to initialize contract", ContractErrors.TOKEN_NOT_FOUND.toString()); - } - } -} diff --git a/token-erc-721/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc721/models/Approval.java b/token-erc-721/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc721/models/Approval.java deleted file mode 100644 index ec0d0dd6..00000000 --- a/token-erc-721/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc721/models/Approval.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.fabric.samples.erc721.models; - -import com.owlike.genson.Genson; -import com.owlike.genson.annotation.JsonProperty; -import org.hyperledger.fabric.contract.annotation.DataType; -import org.hyperledger.fabric.contract.annotation.Property; -import org.json.JSONObject; - -import static java.nio.charset.StandardCharsets.UTF_8; - -@DataType() -public final class Approval { - - @Property() - @JsonProperty("owner") - private String owner; - - @Property() - @JsonProperty("operator") - private String operator; - - @Property() - @JsonProperty("approved") - private boolean approved; - - /** Default constructor */ - public Approval() { - super(); - } - - /** - * Constructor of the class - * - * @param owner - * @param operator - * @param approved - */ - public Approval( - @JsonProperty("owner") final String owner, - @JsonProperty("operator") final String operator, - @JsonProperty("approved") final boolean approved) { - super(); - this.owner = owner; - this.operator = operator; - this.approved = approved; - } - - /** - * @param data - * @return - */ - public static Approval fromJSONString(final String data) { - final JSONObject json = new JSONObject(data); - final Approval approver = - new Approval( - json.getString("owner"), - json.getString("operator"), - Boolean.valueOf(json.getBoolean("approved"))); - return approver; - } - - /** - * Constructs new Approval from JSON String. - * - * @param json Approval format. - * @return - */ - public static Approval fromBytes(final byte[] bytes) { - return new Genson().deserialize(new String(bytes, UTF_8), Approval.class); - } - - /** @return */ - public String getOwner() { - return owner; - } - - public void setOwner(final String owner) { - this.owner = owner; - } - - /** @return */ - public String getOperator() { - return operator; - } - - /** @param operator */ - public void setOperator(final String operator) { - this.operator = operator; - } - - /** @return */ - public boolean isApproved() { - return approved; - } - - /** @param approved */ - public void setApproved(final boolean approved) { - this.approved = approved; - } - - /** @return JSON String of the Approval object. */ - public String toJSONString() { - return new Genson().serialize(this).toString(); - } -} diff --git a/token-erc-721/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc721/models/NFT.java b/token-erc-721/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc721/models/NFT.java deleted file mode 100644 index 8bd0d906..00000000 --- a/token-erc-721/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc721/models/NFT.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.fabric.samples.erc721.models; - -import com.owlike.genson.Genson; -import com.owlike.genson.annotation.JsonProperty; -import org.hyperledger.fabric.contract.annotation.DataType; -import org.hyperledger.fabric.contract.annotation.Property; -import org.json.JSONObject; - -import java.io.Serializable; - -@DataType() -public final class NFT implements Serializable { - - private static final long serialVersionUID = -29439695319757532L; - - @Property() - @JsonProperty("tokenId") - private String tokenId; - - @Property() - @JsonProperty("owner") - private String owner; - - @Property() - @JsonProperty("tokenURI") - private String tokenURI; - - @Property() - @JsonProperty("approved") - private String approved; - - /** Default constructor */ - public NFT() { - super(); - } - - /** - * Constructor of the class - * - * @param tokenId - * @param owner - * @param tokenURI - * @param approved - */ - public NFT( - @JsonProperty("tokenId") final String tokenId, - @JsonProperty("owner") final String owner, - @JsonProperty("tokenURI") final String tokenURI, - @JsonProperty("approved") final String approved) { - super(); - this.tokenId = tokenId; - this.owner = owner; - this.tokenURI = tokenURI; - this.approved = approved; - } - - /** - * Convert JSON string to NFT object. - * - * @param data JSON string. - * @return NFT object - */ - public static NFT fromJSONString(final String data) { - final JSONObject json = new JSONObject(data); - final NFT nft = - new NFT( - json.getString("tokenId"), - json.getString("owner"), - json.getString("tokenURI"), - json.getString("approved")); - - return nft; - } - - /** @return */ - public String getTokenId() { - return tokenId; - } - - /** @param tokenId */ - public void setTokenId(final String tokenId) { - this.tokenId = tokenId; - } - - /** @return */ - public String getOwner() { - return owner; - } - - /** @param owner */ - public void setOwner(final String owner) { - this.owner = owner; - } - - /** @return */ - public String getTokenURI() { - return tokenURI; - } - - /** @param tokenURI */ - public void setTokenURI(final String tokenURI) { - this.tokenURI = tokenURI; - } - - /** @return */ - public String getApproved() { - return approved; - } - - /** @param approved */ - public void setApproved(final String approved) { - this.approved = approved; - } - - /** @return String JSON */ - public String toJSONString() { - return new Genson().serialize(this).toString(); - } -} diff --git a/token-erc-721/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc721/models/Transfer.java b/token-erc-721/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc721/models/Transfer.java deleted file mode 100644 index 4d8024fc..00000000 --- a/token-erc-721/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc721/models/Transfer.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.fabric.samples.erc721.models; - -import com.owlike.genson.Genson; -import com.owlike.genson.annotation.JsonProperty; -import org.hyperledger.fabric.contract.annotation.DataType; -import org.hyperledger.fabric.contract.annotation.Property; - -import static java.nio.charset.StandardCharsets.UTF_8; - -@DataType() -public final class Transfer { - - @Property() - @JsonProperty("from") - private String from; - - @Property() - @JsonProperty("to") - private String to; - - @Property() - @JsonProperty("tokenId") - private String tokenId; - - /** - * Constructor of the class - * - * @param owner - * @param operator - * @param approved - */ - public Transfer( - @JsonProperty("from") final String from, - @JsonProperty("to") final String to, - @JsonProperty("tokenId") final String tokenId) { - super(); - this.from = from; - this.to = to; - this.tokenId = tokenId; - } - - /** Default Constructor of the class. */ - public Transfer() { - super(); - } - - /** - * Constructs new Approval from JSON String. - * - * @param json Approval format. - * @return - */ - public static Transfer fromBytes(final byte[] bytes) { - return new Genson().deserialize(new String(bytes, UTF_8), Transfer.class); - } - - public String getFrom() { - return from; - } - - public void setFrom(final String from) { - this.from = from; - } - - public String getTo() { - return to; - } - - /** @param to */ - public void setTo(final String to) { - this.to = to; - } - - /** @return */ - public String getTokenId() { - return tokenId; - } - - /** @param tokenId */ - public void setTokenId(final String tokenId) { - this.tokenId = tokenId; - } - - /** @return String JSON */ - public String toJSONString() { - return new Genson().serialize(this).toString(); - } -} diff --git a/token-erc-721/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc721/utils/ContractUtility.java b/token-erc-721/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc721/utils/ContractUtility.java deleted file mode 100644 index 01c423a7..00000000 --- a/token-erc-721/chaincode-java/src/main/java/org/hyperledger/fabric/samples/erc721/utils/ContractUtility.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.fabric.samples.erc721.utils; - -public final class ContractUtility { - - private ContractUtility() { - - } - - /** - * @param string - * @return - */ - public static boolean stringIsNullOrEmpty(final String string) { - return string == null || string.isEmpty(); - } -} diff --git a/token-erc-721/chaincode-java/src/test/java/org/hyperledger/fabric/samples/erc721/ERC721TokenContractTest.java b/token-erc-721/chaincode-java/src/test/java/org/hyperledger/fabric/samples/erc721/ERC721TokenContractTest.java deleted file mode 100644 index 48641cf1..00000000 --- a/token-erc-721/chaincode-java/src/test/java/org/hyperledger/fabric/samples/erc721/ERC721TokenContractTest.java +++ /dev/null @@ -1,507 +0,0 @@ -package org.hyperledger.fabric.samples.erc721; - -import org.hyperledger.fabric.contract.ClientIdentity; -import org.hyperledger.fabric.contract.Context; -import org.hyperledger.fabric.samples.erc721.models.Approval; -import org.hyperledger.fabric.samples.erc721.models.NFT; -import org.hyperledger.fabric.shim.ChaincodeException; -import org.hyperledger.fabric.shim.ChaincodeStub; -import org.hyperledger.fabric.shim.ledger.CompositeKey; -import org.hyperledger.fabric.shim.ledger.KeyValue; -import org.hyperledger.fabric.shim.ledger.QueryResultsIterator; -import org.json.JSONException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; - -import java.io.IOException; -import java.security.cert.CertificateException; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.catchThrowable; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -public class ERC721TokenContractTest { - - private static final class MockKeyValue implements KeyValue { - - private final String key; - private final String value; - - MockKeyValue(final String key, final String value) { - super(); - this.key = key; - this.value = value; - } - - @Override - public String getKey() { - return this.key; - } - - @Override - public String getStringValue() { - return this.value; - } - - @Override - public byte[] getValue() { - return this.value.getBytes(); - } - } - - private static final class MockAssetResultsIterator implements QueryResultsIterator { - - private final List assetList; - - MockAssetResultsIterator(final List list) { - super(); - this.assetList = list; - } - - @Override - public Iterator iterator() { - return assetList.iterator(); - } - - @Override - public void close() throws Exception { - // do nothing - } - } - - @Nested - class InvokeERC721TokenBalanceOf { - - @Test - public void invokeToGetTokenBalance() { - ERC721TokenContract contract = new ERC721TokenContract(); - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - List list = new ArrayList<>(); - when(stub.getStringState(ContractConstants.NAMEKEY.getValue())).thenReturn("ARBTToken"); - list.add(new MockKeyValue("balance_Alice_101", "\u0000")); - list.add(new MockKeyValue("balance_Alice_101", "\u0000")); - when(ctx.getStub()).thenReturn(stub); - CompositeKey balanceKey = - stub.createCompositeKey(ContractConstants.BALANCE.getValue(), "Alice"); - when(stub.getStateByPartialCompositeKey(balanceKey)) - .thenReturn(new MockAssetResultsIterator(list)); - long balance = contract.BalanceOf(ctx, "Alice"); - assertThat(balance).isEqualTo(2); - } - - @Test - public void invokeToGetOwnerOf() { - ERC721TokenContract contract = new ERC721TokenContract(); - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - NFT nft = new NFT("101", "Alicd", "http://test.com", ""); - when(ctx.getStub()).thenReturn(stub); - CompositeKey ck = mock(CompositeKey.class); - when(stub.getStringState(ContractConstants.NAMEKEY.getValue())).thenReturn("ARBTToken"); - when(ck.toString()).thenReturn(ContractConstants.NFT.getValue() + "101"); - when(stub.createCompositeKey(ContractConstants.NFT.getValue(), "101")).thenReturn(ck); - when(stub.getStringState(ck.toString())).thenReturn(nft.toJSONString()); - String owner = contract.OwnerOf(ctx, "101"); - assertThat(owner).isEqualTo(nft.getOwner()); - } - } - - @Nested - class ERC721TransferFromFunctionTest { - - private Context ctx = null; - private ChaincodeStub stub = null; - private ERC721TokenContract contract = null; - private NFT currentNFT = null; - private NFT updatedNFT = null; - - @BeforeEach - public void initialize() { - - this.currentNFT = new NFT("101", "Alice", "http://test.com", "Charlie"); - this.updatedNFT = new NFT("101", "Bob", "http://test.com", ""); - this.ctx = mock(Context.class); - this.stub = mock(ChaincodeStub.class); - when(this.ctx.getStub()).thenReturn(stub); - contract = new ERC721TokenContract(); - when(stub.getStringState(ContractConstants.NAMEKEY.getValue())).thenReturn("ARBTToken"); - CompositeKey ck1 = mock(CompositeKey.class); - when(ck1.toString()).thenReturn(ContractConstants.NFT.getValue() + "101"); - when(this.stub.createCompositeKey(ContractConstants.NFT.getValue(), "101")).thenReturn(ck1); - when(stub.getStringState(ck1.toString())).thenReturn(currentNFT.toJSONString()); - CompositeKey ck2 = mock(CompositeKey.class); - when(ck2.toString()).thenReturn(ContractConstants.BALANCE.getValue() + "Alice" + "101"); - when(stub.createCompositeKey(ContractConstants.BALANCE.getValue(), "Alice", "101")) - .thenReturn(ck2); - - CompositeKey ck3 = mock(CompositeKey.class); - when(ck3.toString()).thenReturn(ContractConstants.BALANCE.getValue() + "Bob" + "101"); - when(stub.createCompositeKey(ContractConstants.BALANCE.getValue(), "Bob", "101")) - .thenReturn(ck3); - } - - @Test - public void whenSenderIsCurrentTokenOwner() - throws CertificateException, JSONException, IOException { - Approval approval = new Approval("Alice", "Alice", false); - CompositeKey ck = mock(CompositeKey.class); - when(ck.toString()).thenReturn(ContractConstants.APPROVAL.getValue() + "Alice" + "Alice"); - when(this.stub.createCompositeKey(ContractConstants.APPROVAL.getValue(), "Alice", "Alice")) - .thenReturn(ck); - when(this.stub.getStringState(ck.toString())).thenReturn(approval.toJSONString()); - ClientIdentity ci = null; - ci = mock(ClientIdentity.class); - when(ci.getId()).thenReturn("Alice"); - when(this.ctx.getClientIdentity()).thenReturn(ci); - contract.TransferFrom(this.ctx, "Alice", "Bob", "101"); - verify(stub) - .putStringState(ContractConstants.NFT.getValue() + "101", this.updatedNFT.toJSONString()); - } - - @Test - public void whenSenderIsApprovedClientOfToken() - throws CertificateException, JSONException, IOException { - Approval approval = new Approval("Alice", "Charlie", false); - CompositeKey ck = mock(CompositeKey.class); - when(ck.toString()).thenReturn(ContractConstants.APPROVAL.getValue() + "Alice" + "Charlie"); - when(this.stub.createCompositeKey(ContractConstants.APPROVAL.getValue(), "Alice", "Charlie")) - .thenReturn(ck); - when(this.stub.getStringState(ck.toString())).thenReturn(approval.toJSONString()); - ClientIdentity ci = null; - ci = mock(ClientIdentity.class); - when(ci.getId()).thenReturn("Charlie"); - when(this.ctx.getClientIdentity()).thenReturn(ci); - contract.TransferFrom(this.ctx, "Alice", "Bob", "101"); - verify(stub) - .putStringState(ContractConstants.NFT.getValue() + "101", this.updatedNFT.toJSONString()); - } - - @Test - public void whenSenderIsAuthorizedOperatorOfToken() - throws CertificateException, JSONException, IOException { - Approval approval = new Approval("Alice", "Dave", true); - CompositeKey ck = mock(CompositeKey.class); - when(ck.toString()).thenReturn(ContractConstants.APPROVAL.getValue() + "Alice" + "Dave"); - when(this.stub.createCompositeKey(ContractConstants.APPROVAL.getValue(), "Alice", "Dave")) - .thenReturn(ck); - when(this.stub.getStringState(ck.toString())).thenReturn(approval.toJSONString()); - ClientIdentity ci = null; - ci = mock(ClientIdentity.class); - when(ci.getId()).thenReturn("Dave"); - when(this.ctx.getClientIdentity()).thenReturn(ci); - contract.TransferFrom(this.ctx, "Alice", "Bob", "101"); - verify(stub) - .putStringState(ContractConstants.NFT.getValue() + "101", this.updatedNFT.toJSONString()); - } - - @Test - public void whenSenderIsInvalid() throws CertificateException, JSONException, IOException { - Approval approval = new Approval("Alice", "Alice", false); - CompositeKey ck = mock(CompositeKey.class); - when(ck.toString()).thenReturn(ContractConstants.APPROVAL.getValue() + "Alice" + "Dev"); - when(this.stub.createCompositeKey(ContractConstants.APPROVAL.getValue(), "Alice", "Dev")) - .thenReturn(ck); - when(this.stub.getStringState(ck.toString())).thenReturn(approval.toJSONString()); - ClientIdentity ci = null; - ci = mock(ClientIdentity.class); - when(ci.getId()).thenReturn("Dev"); - when(this.ctx.getClientIdentity()).thenReturn(ci); - Throwable thrown = - catchThrowable( - () -> { - contract.TransferFrom(this.ctx, "Alice", "Bob", "101"); - }); - String message = - String.format( - "The sender %s is not the current owner nor an authorized operator of the token %s.", - "Dev", "101"); - assertThat(thrown).isInstanceOf(ChaincodeException.class).hasMessage(message); - } - - @Test - public void whenCurrentOwnerDoesNotMatch() - throws CertificateException, JSONException, IOException { - Approval approval = new Approval("Alice", "Alice", false); - CompositeKey ck = mock(CompositeKey.class); - when(ck.toString()).thenReturn(ContractConstants.APPROVAL.getValue() + "Alice" + "Alice"); - when(this.stub.createCompositeKey(ContractConstants.APPROVAL.getValue(), "Alice", "Alice")) - .thenReturn(ck); - when(this.stub.getStringState(ck.toString())).thenReturn(approval.toJSONString()); - ClientIdentity ci = null; - ci = mock(ClientIdentity.class); - when(ci.getId()).thenReturn("Alice"); - when(this.ctx.getClientIdentity()).thenReturn(ci); - Throwable thrown = - catchThrowable( - () -> { - contract.TransferFrom(this.ctx, "Charlie", "Bob", "101"); - }); - System.out.println(thrown); - assertThat(thrown) - .isInstanceOf(ChaincodeException.class) - .hasMessage("The from Charlie is not the current owner of the token 101."); - } - } - - @Nested - class ERC721ApproveFunctionalitiesTest { - - @Test - public void invokeApprove() throws CertificateException, JSONException, IOException { - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - NFT nft = new NFT("101", "Alice", "http://test.com", ""); - when(ctx.getStub()).thenReturn(stub); - when(stub.getStringState(ContractConstants.NAMEKEY.getValue())).thenReturn("ARBTToken"); - CompositeKey ck = mock(CompositeKey.class); - when(ck.toString()).thenReturn(ContractConstants.NFT.getValue() + "101"); - when(stub.createCompositeKey(ContractConstants.NFT.getValue(), "101")).thenReturn(ck); - when(stub.getStringState(ck.toString())).thenReturn(nft.toJSONString()); - ClientIdentity ci = null; - ci = mock(ClientIdentity.class); - when(ci.getId()).thenReturn("Alice"); - when(ctx.getClientIdentity()).thenReturn(ci); - CompositeKey ck1 = mock(CompositeKey.class); - when(ck1.toString()).thenReturn(ContractConstants.APPROVAL.getValue() + "Alice" + "Alice"); - when(stub.createCompositeKey(ContractConstants.APPROVAL.getValue(), "Alice", "Alice")) - .thenReturn(ck1); - ERC721TokenContract contract = new ERC721TokenContract(); - contract.Approve(ctx, "Bob", "101"); - verify(stub) - .putStringState( - ContractConstants.NFT.getValue() + "101", - new NFT("101", "Alice", "http://test.com", "Bob").toJSONString()); - } - - @Test - public void invokeSetApproveForAll() { - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - when(ctx.getStub()).thenReturn(stub); - when(stub.getStringState(ContractConstants.NAMEKEY.getValue())).thenReturn("ARBTToken"); - ClientIdentity ci = null; - ci = mock(ClientIdentity.class); - when(ctx.getClientIdentity()).thenReturn(ci); - when(ci.getId()).thenReturn("Alice"); - CompositeKey ck1 = mock(CompositeKey.class); - when(stub.createCompositeKey(ContractConstants.APPROVAL.getValue(), "Alice", "Bob")) - .thenReturn(ck1); - when(ck1.toString()).thenReturn(ContractConstants.APPROVAL.getValue() + "Alice" + "Bob"); - ERC721TokenContract contract = new ERC721TokenContract(); - NFT nft = new NFT("101", "Alice", "http://test.com", ""); - CompositeKey ck = mock(CompositeKey.class); - when(ck.toString()).thenReturn(ContractConstants.NFT.getValue() + "101"); - when(stub.createCompositeKey(ContractConstants.NFT.getValue(), "101")).thenReturn(ck); - when(stub.getStringState(ck.toString())).thenReturn(nft.toJSONString()); - contract.SetApprovalForAll(ctx, "Bob", true); - - verify(stub) - .putStringState(ck1.toString(), new Approval("Alice", "Bob", true).toJSONString()); - } - - @Test - public void invokeGetApproved() { - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - when(ctx.getStub()).thenReturn(stub); - when(stub.getStringState(ContractConstants.NAMEKEY.getValue())).thenReturn("ARBTToken"); - ClientIdentity ci = null; - ci = mock(ClientIdentity.class); - when(ctx.getClientIdentity()).thenReturn(ci); - when(ci.getId()).thenReturn("Alice"); - - ERC721TokenContract contract = new ERC721TokenContract(); - NFT nft = new NFT("101", "Alice", "http://test.com", "Bob"); - - CompositeKey ck = mock(CompositeKey.class); - when(ck.toString()).thenReturn(ContractConstants.NFT.getValue() + "101"); - when(stub.createCompositeKey(ContractConstants.NFT.getValue(), "101")).thenReturn(ck); - when(stub.getStringState(ck.toString())).thenReturn(nft.toJSONString()); - String approved = contract.GetApproved(ctx, "101"); - assertThat(approved).isEqualTo("Bob"); - } - - @Test - public void invokeIsApprovedForAll() { - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - when(ctx.getStub()).thenReturn(stub); - when(stub.getStringState(ContractConstants.NAMEKEY.getValue())).thenReturn("ARBTToken"); - ClientIdentity ci = null; - ci = mock(ClientIdentity.class); - when(ctx.getClientIdentity()).thenReturn(ci); - when(ci.getId()).thenReturn("Alice"); - ERC721TokenContract contract = new ERC721TokenContract(); - Approval approval = new Approval("Alice", "Bob", true); - CompositeKey ck = mock(CompositeKey.class); - when(ck.toString()).thenReturn(ContractConstants.APPROVAL.getValue() + "Alice" + "Bob"); - when(stub.createCompositeKey(ContractConstants.APPROVAL.getValue(), "Alice", "Bob")) - .thenReturn(ck); - when(stub.getStringState(ck.toString())).thenReturn(approval.toJSONString()); - boolean response = contract.IsApprovedForAll(ctx, "Alice", "Bob"); - assertThat(response).isEqualTo(true); - } - } - - @Nested - class ERC721OptionsTest { - - @Test - public void invokeGetName() { - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - when(ctx.getStub()).thenReturn(stub); - when(stub.getStringState(ContractConstants.NAMEKEY.getValue())).thenReturn("AmadoueNFT"); - ERC721TokenContract contract = new ERC721TokenContract(); - String name = contract.Name(ctx); - assertThat(name).isEqualTo("AmadoueNFT"); - } - - @Test - public void invokeGetSysmbol() { - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - when(ctx.getStub()).thenReturn(stub); - when(stub.getStringState(ContractConstants.NAMEKEY.getValue())).thenReturn("ARBTToken"); - when(stub.getStringState(ContractConstants.NAMEKEY.getValue())).thenReturn("ANFT"); - ERC721TokenContract contract = new ERC721TokenContract(); - final String name = contract.Name(ctx); - assertThat(name).isEqualTo("ANFT"); - } - - @Test - public void invokeTokenURI() { - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - when(ctx.getStub()).thenReturn(stub); - when(stub.getStringState(ContractConstants.NAMEKEY.getValue())).thenReturn("ARBTToken"); - ERC721TokenContract contract = new ERC721TokenContract(); - final NFT nft = new NFT("101", "Alice", "http://test.com", "Bob"); - CompositeKey ck = mock(CompositeKey.class); - when(ck.toString()).thenReturn(ContractConstants.NFT.getValue() + "101"); - when(stub.createCompositeKey(ContractConstants.NFT.getValue(), "101")).thenReturn(ck); - when(stub.getStringState(ck.toString())).thenReturn(nft.toJSONString()); - String response = contract.TokenURI(ctx, "101"); - assertThat(response).isEqualTo("http://test.com"); - } - - @Test - public void getTokenTotalSupply() { - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - when(ctx.getStub()).thenReturn(stub); - when(stub.getStringState(ContractConstants.NAMEKEY.getValue())).thenReturn("ARBTToken"); - List list = new ArrayList<>(); - list.add( - new MockKeyValue( - "101", new NFT("101", "Alice", "http://test.com", "Bob").toJSONString())); - list.add( - new MockKeyValue( - "balance_Alice_101", - new NFT("102", "Alice", "http://test.com", "Bob").toJSONString())); - - CompositeKey ck = mock(CompositeKey.class); - when(ck.toString()).thenReturn(ContractConstants.NFT.getValue()); - when(stub.createCompositeKey(ContractConstants.NFT.getValue())).thenReturn(ck); - - when(stub.getStateByPartialCompositeKey(ck)).thenReturn(new MockAssetResultsIterator(list)); - ERC721TokenContract contract = new ERC721TokenContract(); - - final long total = contract.TotalSupply(ctx); - assertThat(total).isEqualTo(2L); - } - } - - @Nested - class ERC721MintFunctionTest { - - @Test - public void whenInvokeMintForNewToken() { - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - when(ctx.getStub()).thenReturn(stub); - when(stub.getStringState(ContractConstants.NAMEKEY.getValue())).thenReturn("ARBTToken"); - final NFT nft = new NFT("101", "Alice", "DummyURI", ""); - CompositeKey ck = mock(CompositeKey.class); - when(ck.toString()).thenReturn(ContractConstants.NFT.getValue() + "101"); - when(stub.createCompositeKey(ContractConstants.NFT.getValue(), "101")).thenReturn(ck); - when(stub.getStringState(ck.toString())).thenReturn(null); - - CompositeKey ck2 = mock(CompositeKey.class); - when(ck2.toString()).thenReturn(ContractConstants.BALANCE.getValue() + "Alice" + "101"); - when(stub.createCompositeKey(ContractConstants.BALANCE.getValue(), "Alice", "101")) - .thenReturn(ck2); - ClientIdentity ci = null; - ci = mock(ClientIdentity.class); - when(ctx.getClientIdentity()).thenReturn(ci); - when(ci.getMSPID()).thenReturn("Org1MSP"); - when(ci.getId()).thenReturn("Alice"); - ERC721TokenContract contract = new ERC721TokenContract(); - final NFT response = contract.MintWithTokenURI(ctx, "101", "DummyURI"); - - verify(stub).putStringState(ck.toString(), nft.toJSONString()); - verify(stub).putStringState(ck2.toString(), "\u0000"); - assertThat(response.toJSONString()).isEqualTo(nft.toJSONString()); - } - - @Test - public void whenInvokeMintForAlreadyExistingToken() { - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - when(ctx.getStub()).thenReturn(stub); - when(stub.getStringState(ContractConstants.NAMEKEY.getValue())).thenReturn("ARBTToken"); - final NFT nft = new NFT("101", "Alice", "DummyURI", ""); - CompositeKey ck = mock(CompositeKey.class); - when(ck.toString()).thenReturn(ContractConstants.NFT.getValue() + "101"); - when(stub.createCompositeKey(ContractConstants.NFT.getValue(), "101")).thenReturn(ck); - when(stub.getStringState(ck.toString())).thenReturn(nft.toJSONString()); - ClientIdentity ci = null; - ci = mock(ClientIdentity.class); - when(ctx.getClientIdentity()).thenReturn(ci); - when(ci.getMSPID()).thenReturn("Org1MSP"); - when(ci.getId()).thenReturn("Alice"); - ERC721TokenContract contract = new ERC721TokenContract(); - Throwable thrown = - catchThrowable( - () -> { - contract.MintWithTokenURI(ctx, "101", "DummyURI"); - }); - assertThat(thrown) - .isInstanceOf(ChaincodeException.class) - .hasMessage("The token 101 is already minted."); - } - - @Test - public void whenInvokeBurnToken() { - Context ctx = mock(Context.class); - ChaincodeStub stub = mock(ChaincodeStub.class); - when(ctx.getStub()).thenReturn(stub); - when(stub.getStringState(ContractConstants.NAMEKEY.getValue())).thenReturn("ARBTToken"); - final NFT nft = new NFT("101", "Alice", "DummyURI", ""); - CompositeKey ck = mock(CompositeKey.class); - when(ck.toString()).thenReturn(ContractConstants.NFT.getValue() + "101"); - when(stub.createCompositeKey(ContractConstants.NFT.getValue(), "101")).thenReturn(ck); - when(stub.getStringState(ck.toString())).thenReturn(nft.toJSONString()); - CompositeKey ck2 = mock(CompositeKey.class); - when(ck2.toString()).thenReturn(ContractConstants.BALANCE.getValue() + "Alice" + "101"); - when(stub.createCompositeKey(ContractConstants.BALANCE.getValue(), "Alice", "101")) - .thenReturn(ck2); - ClientIdentity ci = null; - ci = mock(ClientIdentity.class); - when(ctx.getClientIdentity()).thenReturn(ci); - when(ci.getMSPID()).thenReturn("Org1MSP"); - when(ci.getId()).thenReturn("Alice"); - ERC721TokenContract contract = new ERC721TokenContract(); - contract.Burn(ctx, "101"); - verify(stub).delState(ck.toString()); - verify(stub).delState(ck2.toString()); - } - } -} diff --git a/token-erc-721/chaincode-java/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/token-erc-721/chaincode-java/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker deleted file mode 100644 index ca6ee9ce..00000000 --- a/token-erc-721/chaincode-java/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker +++ /dev/null @@ -1 +0,0 @@ -mock-maker-inline \ No newline at end of file diff --git a/token-erc-721/chaincode-javascript/.editorconfig b/token-erc-721/chaincode-javascript/.editorconfig deleted file mode 100755 index 75a13be2..00000000 --- a/token-erc-721/chaincode-javascript/.editorconfig +++ /dev/null @@ -1,16 +0,0 @@ -# -# SPDX-License-Identifier: Apache-2.0 -# - -root = true - -[*] -indent_style = space -indent_size = 4 -end_of_line = lf -charset = utf-8 -trim_trailing_whitespace = true -insert_final_newline = true - -[*.md] -trim_trailing_whitespace = false diff --git a/token-erc-721/chaincode-javascript/.eslintignore b/token-erc-721/chaincode-javascript/.eslintignore deleted file mode 100644 index 15958470..00000000 --- a/token-erc-721/chaincode-javascript/.eslintignore +++ /dev/null @@ -1,5 +0,0 @@ -# -# SPDX-License-Identifier: Apache-2.0 -# - -coverage diff --git a/token-erc-721/chaincode-javascript/.eslintrc.js b/token-erc-721/chaincode-javascript/.eslintrc.js deleted file mode 100644 index 8d99762d..00000000 --- a/token-erc-721/chaincode-javascript/.eslintrc.js +++ /dev/null @@ -1,39 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - */ - -module.exports = { - env: { - node: true, - es6: true, - mocha: true - }, - parserOptions: { - ecmaVersion: 8, - sourceType: 'script' - }, - extends: "eslint:recommended", - rules: { - indent: ['error', 4], - 'linebreak-style': ['error', 'unix'], - quotes: ['error', 'single'], - semi: ['error', 'always'], - 'no-unused-vars': ['error', { args: 'none' }], - 'no-console': 'off', - curly: 'error', - eqeqeq: 'error', - 'no-throw-literal': 'error', - strict: 'error', - 'no-var': 'error', - 'dot-notation': 'error', - 'no-tabs': 'error', - 'no-trailing-spaces': 'error', - 'no-use-before-define': 'error', - 'no-useless-call': 'error', - 'no-with': 'error', - 'operator-linebreak': 'error', - yoda: 'error', - 'quote-props': ['error', 'as-needed'], - 'no-constant-condition': ["error", { "checkLoops": false }] - } -}; diff --git a/token-erc-721/chaincode-javascript/.gitignore b/token-erc-721/chaincode-javascript/.gitignore deleted file mode 100644 index c84ff1db..00000000 --- a/token-erc-721/chaincode-javascript/.gitignore +++ /dev/null @@ -1,78 +0,0 @@ -# -# SPDX-License-Identifier: Apache-2.0 -# - -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (https://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules/ -jspm_packages/ -package-lock.json - -# TypeScript v1 declaration files -typings/ - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variables file -.env - -# parcel-bundler cache (https://parceljs.org/) -.cache - -# next.js build output -.next - -# nuxt.js build output -.nuxt - -# vuepress build output -.vuepress/dist - -# Serverless directories -.serverless diff --git a/token-erc-721/chaincode-javascript/index.js b/token-erc-721/chaincode-javascript/index.js deleted file mode 100644 index 65ac82b3..00000000 --- a/token-erc-721/chaincode-javascript/index.js +++ /dev/null @@ -1,10 +0,0 @@ -/* -SPDX-License-Identifier: Apache-2.0 -*/ - -'use strict'; - -const tokenERC721Contract = require('./lib/tokenERC721.js'); - -module.exports.tokenERC721Contract = tokenERC721Contract; -module.exports.contracts = [tokenERC721Contract]; \ No newline at end of file diff --git a/token-erc-721/chaincode-javascript/lib/tokenERC721.js b/token-erc-721/chaincode-javascript/lib/tokenERC721.js deleted file mode 100644 index fd507380..00000000 --- a/token-erc-721/chaincode-javascript/lib/tokenERC721.js +++ /dev/null @@ -1,464 +0,0 @@ -/* -SPDX-License-Identifier: Apache-2.0 -*/ - -'use strict'; - -const { Contract } = require('fabric-contract-api'); - -// Define objectType names for prefix -const balancePrefix = 'balance'; -const nftPrefix = 'nft'; -const approvalPrefix = 'approval'; - -// Define key names for options -const nameKey = 'name'; -const symbolKey = 'symbol'; - -class TokenERC721Contract extends Contract { - - /** - * BalanceOf counts all non-fungible tokens assigned to an owner - * - * @param {Context} ctx the transaction context - * @param {String} owner An owner for whom to query the balance - * @returns {Number} The number of non-fungible tokens owned by the owner, possibly zero - */ - async BalanceOf(ctx, owner) { - // Check contract options are already set first to execute the function - await this.CheckInitialized(ctx); - - // There is a key record for every non-fungible token in the format of balancePrefix.owner.tokenId. - // BalanceOf() queries for and counts all records matching balancePrefix.owner.* - const iterator = await ctx.stub.getStateByPartialCompositeKey(balancePrefix, [owner]); - - // Count the number of returned composite keys - let balance = 0; - let result = await iterator.next(); - while (!result.done) { - balance++; - result = await iterator.next(); - } - return balance; - } - - /** - * OwnerOf finds the owner of a non-fungible token - * - * @param {Context} ctx the transaction context - * @param {String} tokenId The identifier for a non-fungible token - * @returns {String} Return the owner of the non-fungible token - */ - async OwnerOf(ctx, tokenId) { - // Check contract options are already set first to execute the function - await this.CheckInitialized(ctx); - - const nft = await this._readNFT(ctx, tokenId); - const owner = nft.owner; - if (!owner) { - throw new Error('No owner is assigned to this token'); - } - - return owner; - } - - /** - * TransferFrom transfers the ownership of a non-fungible token - * from one owner to another owner - * - * @param {Context} ctx the transaction context - * @param {String} from The current owner of the non-fungible token - * @param {String} to The new owner - * @param {String} tokenId the non-fungible token to transfer - * @returns {Boolean} Return whether the transfer was successful or not - */ - async TransferFrom(ctx, from, to, tokenId) { - // Check contract options are already set first to execute the function - await this.CheckInitialized(ctx); - - const sender = ctx.clientIdentity.getID(); - - const nft = await this._readNFT(ctx, tokenId); - - // Check if the sender is the current owner, an authorized operator, - // or the approved client for this non-fungible token. - const owner = nft.owner; - const tokenApproval = nft.approved; - const operatorApproval = await this.IsApprovedForAll(ctx, owner, sender); - if (owner !== sender && tokenApproval !== sender && !operatorApproval) { - throw new Error('The sender is not allowed to transfer the non-fungible token'); - } - - // Check if `from` is the current owner - if (owner !== from) { - throw new Error('The from is not the current owner.'); - } - - // Clear the approved client for this non-fungible token - nft.approved = ''; - - // Overwrite a non-fungible token to assign a new owner. - nft.owner = to; - const nftKey = ctx.stub.createCompositeKey(nftPrefix, [tokenId]); - await ctx.stub.putState(nftKey, Buffer.from(JSON.stringify(nft))); - - // Remove a composite key from the balance of the current owner - const balanceKeyFrom = ctx.stub.createCompositeKey(balancePrefix, [from, tokenId]); - await ctx.stub.deleteState(balanceKeyFrom); - - // Save a composite key to count the balance of a new owner - const balanceKeyTo = ctx.stub.createCompositeKey(balancePrefix, [to, tokenId]); - await ctx.stub.putState(balanceKeyTo, Buffer.from('\u0000')); - - // Emit the Transfer event - const tokenIdInt = parseInt(tokenId); - const transferEvent = { from: from, to: to, tokenId: tokenIdInt }; - ctx.stub.setEvent('Transfer', Buffer.from(JSON.stringify(transferEvent))); - - return true; - } - - /** - * Approve changes or reaffirms the approved client for a non-fungible token - * - * @param {Context} ctx the transaction context - * @param {String} approved The new approved client - * @param {String} tokenId the non-fungible token to approve - * @returns {Boolean} Return whether the approval was successful or not - */ - async Approve(ctx, approved, tokenId) { - // Check contract options are already set first to execute the function - await this.CheckInitialized(ctx); - - const sender = ctx.clientIdentity.getID(); - - const nft = await this._readNFT(ctx, tokenId); - - // Check if the sender is the current owner of the non-fungible token - // or an authorized operator of the current owner - const owner = nft.owner; - const operatorApproval = await this.IsApprovedForAll(ctx, owner, sender); - if (owner !== sender && !operatorApproval) { - throw new Error('The sender is not the current owner nor an authorized operator'); - } - - // Update the approved client of the non-fungible token - nft.approved = approved; - const nftKey = ctx.stub.createCompositeKey(nftPrefix, [tokenId]); - await ctx.stub.putState(nftKey, Buffer.from(JSON.stringify(nft))); - - // Emit the Approval event - const tokenIdInt = parseInt(tokenId); - const approvalEvent = { owner: owner, approved: approved, tokenId: tokenIdInt }; - ctx.stub.setEvent('Approval', Buffer.from(JSON.stringify(approvalEvent))); - - return true; - } - - /** - * SetApprovalForAll enables or disables approval for a third party ("operator") - * to manage all of message sender's assets - * - * @param {Context} ctx the transaction context - * @param {String} operator A client to add to the set of authorized operators - * @param {Boolean} approved True if the operator is approved, false to revoke approval - * @returns {Boolean} Return whether the approval was successful or not - */ - async SetApprovalForAll(ctx, operator, approved) { - // Check contract options are already set first to execute the function - await this.CheckInitialized(ctx); - - const sender = ctx.clientIdentity.getID(); - - const approval = { owner: sender, operator: operator, approved: approved }; - const approvalKey = ctx.stub.createCompositeKey(approvalPrefix, [sender, operator]); - await ctx.stub.putState(approvalKey, Buffer.from(JSON.stringify(approval))); - - // Emit the ApprovalForAll event - const approvalForAllEvent = { owner: sender, operator: operator, approved: approved }; - ctx.stub.setEvent('ApprovalForAll', Buffer.from(JSON.stringify(approvalForAllEvent))); - - return true; - } - - /** - * GetApproved returns the approved client for a single non-fungible token - * - * @param {Context} ctx the transaction context - * @param {String} tokenId the non-fungible token to find the approved client for - * @returns {Object} Return the approved client for this non-fungible token, or null if there is none - */ - async GetApproved(ctx, tokenId) { - // Check contract options are already set first to execute the function - await this.CheckInitialized(ctx); - - const nft = await this._readNFT(ctx, tokenId); - return nft.approved; - } - - /** - * IsApprovedForAll returns if a client is an authorized operator for another client - * - * @param {Context} ctx the transaction context - * @param {String} owner The client that owns the non-fungible tokens - * @param {String} operator The client that acts on behalf of the owner - * @returns {Boolean} Return true if the operator is an approved operator for the owner, false otherwise - */ - async IsApprovedForAll(ctx, owner, operator) { - // Check contract options are already set first to execute the function - await this.CheckInitialized(ctx); - - const approvalKey = ctx.stub.createCompositeKey(approvalPrefix, [owner, operator]); - const approvalBytes = await ctx.stub.getState(approvalKey); - let approved; - if (approvalBytes && approvalBytes.length > 0) { - const approval = JSON.parse(approvalBytes.toString()); - approved = approval.approved; - } else { - approved = false; - } - - return approved; - } - - // ============== ERC721 metadata extension =============== - - /** - * Name returns a descriptive name for a collection of non-fungible tokens in this contract - * - * @param {Context} ctx the transaction context - * @returns {String} Returns the name of the token - */ - async Name(ctx) { - // Check contract options are already set first to execute the function - await this.CheckInitialized(ctx); - - const nameAsBytes = await ctx.stub.getState(nameKey); - return nameAsBytes.toString(); - } - - /** - * Symbol returns an abbreviated name for non-fungible tokens in this contract. - * - * @param {Context} ctx the transaction context - * @returns {String} Returns the symbol of the token - */ - async Symbol(ctx) { - // Check contract options are already set first to execute the function - await this.CheckInitialized(ctx); - - const symbolAsBytes = await ctx.stub.getState(symbolKey); - return symbolAsBytes.toString(); - } - - /** - * TokenURI returns a distinct Uniform Resource Identifier (URI) for a given token. - * - * @param {Context} ctx the transaction context - * @param {string} tokenId The identifier for a non-fungible token - * @returns {String} Returns the URI of the token - */ - async TokenURI(ctx, tokenId) { - // Check contract options are already set first to execute the function - await this.CheckInitialized(ctx); - - const nft = await this._readNFT(ctx, tokenId); - return nft.tokenURI; - } - - // ============== ERC721 enumeration extension =============== - - /** - * TotalSupply counts non-fungible tokens tracked by this contract. - * - * @param {Context} ctx the transaction context - * @returns {Number} Returns a count of valid non-fungible tokens tracked by this contract, - * where each one of them has an assigned and queryable owner. - */ - async TotalSupply(ctx) { - // Check contract options are already set first to execute the function - await this.CheckInitialized(ctx); - - // There is a key record for every non-fungible token in the format of nftPrefix.tokenId. - // TotalSupply() queries for and counts all records matching nftPrefix.* - const iterator = await ctx.stub.getStateByPartialCompositeKey(nftPrefix, []); - - // Count the number of returned composite keys - let totalSupply = 0; - let result = await iterator.next(); - while (!result.done) { - totalSupply++; - result = await iterator.next(); - } - return totalSupply; - } - - // ============== Extended Functions for this sample =============== - - /** - * Set optional information for a token. - * - * @param {Context} ctx the transaction context - * @param {String} name The name of the token - * @param {String} symbol The symbol of the token - */ - async Initialize(ctx, name, symbol) { - - // Check minter authorization - this sample assumes Org1 is the issuer with privilege to initialize contract (set the name and symbol) - const clientMSPID = ctx.clientIdentity.getMSPID(); - if (clientMSPID !== 'Org1MSP') { - throw new Error('client is not authorized to set the name and symbol of the token'); - } - - // Check contract options are not already set, client is not authorized to change them once intitialized - const nameBytes = await ctx.stub.getState(nameKey); - if (nameBytes && nameBytes.length > 0) { - throw new Error('contract options are already set, client is not authorized to change them'); - } - - await ctx.stub.putState(nameKey, Buffer.from(name)); - await ctx.stub.putState(symbolKey, Buffer.from(symbol)); - return true; - } - - /** - * Mint a new non-fungible token - * - * @param {Context} ctx the transaction context - * @param {String} tokenId Unique ID of the non-fungible token to be minted - * @param {String} tokenURI URI containing metadata of the minted non-fungible token - * @returns {Object} Return the non-fungible token object - */ - async MintWithTokenURI(ctx, tokenId, tokenURI) { - // Check contract options are already set first to execute the function - await this.CheckInitialized(ctx); - - // Check minter authorization - this sample assumes Org1 is the issuer with privilege to mint a new token - const clientMSPID = ctx.clientIdentity.getMSPID(); - if (clientMSPID !== 'Org1MSP') { - throw new Error('client is not authorized to mint new tokens'); - } - - // Get ID of submitting client identity - const minter = ctx.clientIdentity.getID(); - - // Check if the token to be minted does not exist - const exists = await this._nftExists(ctx, tokenId); - if (exists) { - throw new Error(`The token ${tokenId} is already minted.`); - } - - // Add a non-fungible token - const tokenIdInt = parseInt(tokenId); - if (isNaN(tokenIdInt)) { - throw new Error(`The tokenId ${tokenId} is invalid. tokenId must be an integer`); - } - const nft = { - tokenId: tokenIdInt, - owner: minter, - tokenURI: tokenURI - }; - const nftKey = ctx.stub.createCompositeKey(nftPrefix, [tokenId]); - await ctx.stub.putState(nftKey, Buffer.from(JSON.stringify(nft))); - - // A composite key would be balancePrefix.owner.tokenId, which enables partial - // composite key query to find and count all records matching balance.owner.* - // An empty value would represent a delete, so we simply insert the null character. - const balanceKey = ctx.stub.createCompositeKey(balancePrefix, [minter, tokenId]); - await ctx.stub.putState(balanceKey, Buffer.from('\u0000')); - - // Emit the Transfer event - const transferEvent = { from: '0x0', to: minter, tokenId: tokenIdInt }; - ctx.stub.setEvent('Transfer', Buffer.from(JSON.stringify(transferEvent))); - - return nft; - } - - /** - * Burn a non-fungible token - * - * @param {Context} ctx the transaction context - * @param {String} tokenId Unique ID of a non-fungible token - * @returns {Boolean} Return whether the burn was successful or not - */ - async Burn(ctx, tokenId) { - // check contract options are already set first to execute the function - await this.CheckInitialized(ctx); - - const owner = ctx.clientIdentity.getID(); - - // Check if a caller is the owner of the non-fungible token - const nft = await this._readNFT(ctx, tokenId); - if (nft.owner !== owner) { - throw new Error(`Non-fungible token ${tokenId} is not owned by ${owner}`); - } - - // Delete the token - const nftKey = ctx.stub.createCompositeKey(nftPrefix, [tokenId]); - await ctx.stub.deleteState(nftKey); - - // Remove a composite key from the balance of the owner - const balanceKey = ctx.stub.createCompositeKey(balancePrefix, [owner, tokenId]); - await ctx.stub.deleteState(balanceKey); - - // Emit the Transfer event - const tokenIdInt = parseInt(tokenId); - const transferEvent = { from: owner, to: '0x0', tokenId: tokenIdInt }; - ctx.stub.setEvent('Transfer', Buffer.from(JSON.stringify(transferEvent))); - - return true; - } - - async _readNFT(ctx, tokenId) { - const nftKey = ctx.stub.createCompositeKey(nftPrefix, [tokenId]); - const nftBytes = await ctx.stub.getState(nftKey); - if (!nftBytes || nftBytes.length === 0) { - throw new Error(`The tokenId ${tokenId} is invalid. It does not exist`); - } - const nft = JSON.parse(nftBytes.toString()); - return nft; - } - - async _nftExists(ctx, tokenId) { - const nftKey = ctx.stub.createCompositeKey(nftPrefix, [tokenId]); - const nftBytes = await ctx.stub.getState(nftKey); - return nftBytes && nftBytes.length > 0; - } - - /** - * ClientAccountBalance returns the balance of the requesting client's account. - * - * @param {Context} ctx the transaction context - * @returns {Number} Returns the account balance - */ - async ClientAccountBalance(ctx) { - // check contract options are already set first to execute the function - await this.CheckInitialized(ctx); - - // Get ID of submitting client identity - const clientAccountID = ctx.clientIdentity.getID(); - return this.BalanceOf(ctx, clientAccountID); - } - - // ClientAccountID returns the id of the requesting client's account. - // In this implementation, the client account ID is the clientId itself. - // Users can use this function to get their own account id, which they can then give to others as the payment address - async ClientAccountID(ctx) { - // check contract options are already set first to execute the function - await this.CheckInitialized(ctx); - - // Get ID of submitting client identity - const clientAccountID = ctx.clientIdentity.getID(); - return clientAccountID; - } - - // Checks that contract options have been already initialized - async CheckInitialized(ctx){ - const nameBytes = await ctx.stub.getState(nameKey); - if (!nameBytes || nameBytes.length === 0) { - throw new Error('contract options need to be set before calling any function, call Initialize() to initialize contract'); - } - } -} - -module.exports = TokenERC721Contract; diff --git a/token-erc-721/chaincode-javascript/npm-shrinkwrap.json b/token-erc-721/chaincode-javascript/npm-shrinkwrap.json deleted file mode 100644 index 1e63a3e1..00000000 --- a/token-erc-721/chaincode-javascript/npm-shrinkwrap.json +++ /dev/null @@ -1,4396 +0,0 @@ -{ - "name": "token-erc721", - "version": "0.0.1", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "token-erc721", - "version": "0.0.1", - "license": "Apache-2.0", - "dependencies": { - "fabric-contract-api": "~2.5", - "fabric-shim": "~2.5" - }, - "devDependencies": { - "chai": "^4.1.2", - "chai-as-promised": "^7.1.1", - "eslint": "^4.19.1", - "mocha": "^8.0.1", - "nyc": "^14.1.1", - "sinon": "^6.0.0", - "sinon-chai": "^3.2.0" - }, - "engines": { - "node": ">=12", - "npm": ">=5" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", - "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.24.7", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/generator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.7.tgz", - "integrity": "sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.24.7", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", - "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", - "dev": true, - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz", - "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==", - "dev": true, - "dependencies": { - "@babel/template": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz", - "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==", - "dev": true, - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", - "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz", - "integrity": "sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", - "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", - "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.24.7", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight/node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/@babel/parser": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.7.tgz", - "integrity": "sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/template": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz", - "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.7.tgz", - "integrity": "sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.7", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-hoist-variables": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/types": "^7.24.7", - "debug": "^4.3.1", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@babel/traverse/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/@babel/types": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz", - "integrity": "sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@colors/colors": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", - "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/@dabh/diagnostics": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", - "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", - "dependencies": { - "colorspace": "1.1.x", - "enabled": "2.0.x", - "kuler": "^2.0.0" - } - }, - "node_modules/@fidm/asn1": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@fidm/asn1/-/asn1-1.0.4.tgz", - "integrity": "sha512-esd1jyNvRb2HVaQGq2Gg8Z0kbQPXzV9Tq5Z14KNIov6KfFD6PTaRIO8UpcsYiTNzOqJpmyzWgVTrUwFV3UF4TQ==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@fidm/x509": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@fidm/x509/-/x509-1.2.1.tgz", - "integrity": "sha512-nwc2iesjyc9hkuzcrMCBXQRn653XuAUKorfWM8PZyJawiy1QzLj4vahwzaI25+pfpwOLvMzbJ0uKpWLDNmo16w==", - "dependencies": { - "@fidm/asn1": "^1.0.4", - "tweetnacl": "^1.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@grpc/grpc-js": { - "version": "1.10.9", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.10.9.tgz", - "integrity": "sha512-5tcgUctCG0qoNyfChZifz2tJqbRbXVO9J7X6duFcOjY3HUNCxg5D0ZCK7EP9vIcZ0zRpLU9bWkyCqVCLZ46IbQ==", - "dependencies": { - "@grpc/proto-loader": "^0.7.13", - "@js-sdsl/ordered-map": "^4.4.2" - }, - "engines": { - "node": ">=12.10.0" - } - }, - "node_modules/@grpc/proto-loader": { - "version": "0.7.13", - "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.13.tgz", - "integrity": "sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw==", - "dependencies": { - "lodash.camelcase": "^4.3.0", - "long": "^5.0.0", - "protobufjs": "^7.2.5", - "yargs": "^17.7.2" - }, - "bin": { - "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@hyperledger/fabric-protos": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@hyperledger/fabric-protos/-/fabric-protos-0.2.1.tgz", - "integrity": "sha512-qjm0vIQIfCall804tWDeA8p/mUfu14sl5Sj+PbOn2yDKJq+7ThoIhNsLAqf+BCxUfqsoqQq6AojhqQeTFyOOqg==", - "dependencies": { - "@grpc/grpc-js": "^1.9.0", - "google-protobuf": "^3.21.0" - }, - "engines": { - "node": ">=14.15.0" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@js-sdsl/ordered-map": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz", - "integrity": "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/js-sdsl" - } - }, - "node_modules/@protobufjs/aspromise": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" - }, - "node_modules/@protobufjs/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" - }, - "node_modules/@protobufjs/codegen": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" - }, - "node_modules/@protobufjs/eventemitter": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" - }, - "node_modules/@protobufjs/fetch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", - "dependencies": { - "@protobufjs/aspromise": "^1.1.1", - "@protobufjs/inquire": "^1.1.0" - } - }, - "node_modules/@protobufjs/float": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" - }, - "node_modules/@protobufjs/inquire": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" - }, - "node_modules/@protobufjs/path": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" - }, - "node_modules/@protobufjs/pool": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" - }, - "node_modules/@protobufjs/utf8": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" - }, - "node_modules/@sinonjs/commons": { - "version": "1.8.6", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", - "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", - "dev": true, - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/formatio": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.2.2.tgz", - "integrity": "sha512-B8SEsgd8gArBLMD6zpRw3juQ2FVSsmdd7qlevyDqzS9WTCtvF55/gAL+h6gue8ZvPYcdiPdvueM/qm//9XzyTQ==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^1", - "@sinonjs/samsam": "^3.1.0" - } - }, - "node_modules/@sinonjs/formatio/node_modules/@sinonjs/samsam": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.3.3.tgz", - "integrity": "sha512-bKCMKZvWIjYD0BLGnNrxVuw4dkWCYsLqFOUWw8VgKF/+5Y+mE7LfHWPIYoDXowH+3a9LsWDMo0uAP8YDosPvHQ==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^1.3.0", - "array-from": "^2.1.1", - "lodash": "^4.17.15" - } - }, - "node_modules/@sinonjs/samsam": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-2.1.3.tgz", - "integrity": "sha512-8zNeBkSKhU9a5cRNbpCKau2WWPfan+Q2zDlcXvXyhn9EsMqgYs4qzo0XHNVlXC6ABQL8fT6nV+zzo5RTHJzyXw==", - "dev": true - }, - "node_modules/@sinonjs/text-encoding": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz", - "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", - "dev": true - }, - "node_modules/@types/node": { - "version": "16.18.98", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.98.tgz", - "integrity": "sha512-fpiC20NvLpTLAzo3oVBKIqBGR6Fx/8oAK/SSf7G+fydnXMY1x4x9RZ6sBXhqKlCU21g2QapUsbLlhv3+a7wS+Q==" - }, - "node_modules/@types/triple-beam": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", - "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==" - }, - "node_modules/@ungap/promise-all-settled": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", - "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", - "dev": true - }, - "node_modules/acorn": { - "version": "5.7.4", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", - "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", - "integrity": "sha512-AU7pnZkguthwBjKgCg6998ByQNIMjbuDQZ8bb78QAFZwPfmKia8AIzgY/gWgqCjnht8JLdXmB4YxA0KaV60ncQ==", - "dev": true, - "dependencies": { - "acorn": "^3.0.4" - } - }, - "node_modules/acorn-jsx/node_modules/acorn": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", - "integrity": "sha512-OLUyIIZ7mF5oaAUT1w0TFqQS81q3saT46x8t7ukpPjMNk+nbs4ZHhs7ToV8EWnLYLepjETXd4XaCE4uxkMeqUw==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/ajv": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", - "integrity": "sha512-Ajr4IcMXq/2QmMkEmSvxqfLN5zGmJ92gHXAeOXq1OekoH2rfDNsgdDoL2f7QaRCy7G/E6TpxBVdRuNraMztGHw==", - "dev": true, - "dependencies": { - "co": "^4.6.0", - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" - } - }, - "node_modules/ajv-keywords": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz", - "integrity": "sha512-ZFztHzVRdGLAzJmpUT9LNFLe1YiVOEylcaNpEutM26PVTCtOD919IMfD01CgbRouB42Dd9atjx1HseC15DgOZA==", - "dev": true, - "peerDependencies": { - "ajv": "^5.0.0" - } - }, - "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/ansi-regex": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", - "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/append-transform": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-1.0.0.tgz", - "integrity": "sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==", - "dev": true, - "dependencies": { - "default-require-extensions": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/archy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", - "dev": true - }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/array-from": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", - "integrity": "sha512-GQTc6Uupx1FCavi5mPzBvVT7nEOeWMmUA9P95wpfpW1XwMSKs+KaymD5C2Up7KAUKg/mYwbsUYzdZWcoajlNZg==", - "dev": true - }, - "node_modules/assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/async": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", - "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" - }, - "node_modules/babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha512-XqYMR2dfdGMW+hd0IUZ2PwK+fGeFkOxZJ0wY+JaQAHzt1Zx8LcvpiZD2NiGkEG8qx0CfkAOr5xt76d1e8vG90g==", - "dev": true, - "dependencies": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" - } - }, - "node_modules/babel-code-frame/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/babel-code-frame/node_modules/ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/babel-code-frame/node_modules/chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", - "dev": true, - "dependencies": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/babel-code-frame/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/babel-code-frame/node_modules/supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "node_modules/caching-transform": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-3.0.2.tgz", - "integrity": "sha512-Mtgcv3lh3U0zRii/6qVgQODdPA4G3zhG+jtbCWj39RXuUFTMzH0vcdMtaJS1jPowd+It2Pqr6y3NJMQqOqCE2w==", - "dev": true, - "dependencies": { - "hasha": "^3.0.0", - "make-dir": "^2.0.0", - "package-hash": "^3.0.0", - "write-file-atomic": "^2.4.2" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/caller-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", - "integrity": "sha512-UJiE1otjXPF5/x+T3zTnSFiTOEmJoGTD9HmBoxnCUwho61a2eSNn/VwtwuIBDAo2SEOv1AJ7ARI5gCmohFLu/g==", - "dev": true, - "dependencies": { - "callsites": "^0.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/callsites": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", - "integrity": "sha512-Zv4Dns9IbXXmPkgRRUjAaJQgfN4xX5p6+RQFhWUqscdvvK2xK/ZL8b3IXIJsj+4sD+f24NwnWy2BY8AJ82JB0A==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/chai": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz", - "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==", - "dev": true, - "dependencies": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.3", - "deep-eql": "^4.1.3", - "get-func-name": "^2.0.2", - "loupe": "^2.3.6", - "pathval": "^1.1.1", - "type-detect": "^4.0.8" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chai-as-promised": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.2.tgz", - "integrity": "sha512-aBDHZxRzYnUYuIAIPBH2s511DjlKPzXNlXSGFC8CwmroWQLfrW0LtE1nK3MAwwNhJPa9raEjNCmRoFpG0Hurdw==", - "dev": true, - "dependencies": { - "check-error": "^1.0.2" - }, - "peerDependencies": { - "chai": ">= 2.1.2 < 6" - } - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chardet": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", - "integrity": "sha512-j/Toj7f1z98Hh2cYo2BVr85EpIRWqUi7rtRSGxh/cqUjqrnJe9l9UE7IUGd2vQ2p+kSHLkSzObQPZPLUC6TQwg==", - "dev": true - }, - "node_modules/check-error": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", - "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", - "dev": true, - "dependencies": { - "get-func-name": "^2.0.2" - }, - "engines": { - "node": "*" - } - }, - "node_modules/chokidar": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", - "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", - "dev": true, - "dependencies": { - "anymatch": "~3.1.1", - "braces": "~3.0.2", - "glob-parent": "~5.1.0", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.5.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.1" - } - }, - "node_modules/circular-json": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", - "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", - "deprecated": "CircularJSON is in maintenance only, flatted is its successor.", - "dev": true - }, - "node_modules/class-transformer": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.4.0.tgz", - "integrity": "sha512-ETWD/H2TbWbKEi7m9N4Km5+cw1hNcqJSxlSYhsLsNjQzWWiZIYA1zafxpK9PwVfaZ6AqR5rrjPVUBGESm5tQUA==" - }, - "node_modules/cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==", - "dev": true, - "dependencies": { - "restore-cursor": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/cli-width": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", - "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", - "dev": true - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/cliui/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", - "dev": true, - "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" - } - }, - "node_modules/color": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", - "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", - "dependencies": { - "color-convert": "^1.9.3", - "color-string": "^1.6.0" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "node_modules/color-string": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", - "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", - "dependencies": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } - }, - "node_modules/colorspace": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", - "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", - "dependencies": { - "color": "^3.1.3", - "text-hex": "1.0.x" - } - }, - "node_modules/commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "dev": true, - "engines": [ - "node >= 0.8" - ], - "dependencies": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true - }, - "node_modules/cp-file": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/cp-file/-/cp-file-6.2.0.tgz", - "integrity": "sha512-fmvV4caBnofhPe8kOcitBwSn2f39QLjnAnGq3gO9dfd75mUytzKNZB1hde6QHunW2Rt+OwuBOMc3i1tNElbszA==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "make-dir": "^2.0.0", - "nested-error-stacks": "^2.0.0", - "pify": "^4.0.1", - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==", - "dev": true, - "dependencies": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/deep-eql": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", - "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", - "dev": true, - "dependencies": { - "type-detect": "^4.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/default-require-extensions": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-2.0.0.tgz", - "integrity": "sha512-B0n2zDIXpzLzKeoEozorDSa1cHc1t0NjmxP0zuAxbizNU2MBqYJJKYXrrFdKuQliojXynrxgd7l4ahfg/+aA5g==", - "dev": true, - "dependencies": { - "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "node_modules/enabled": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", - "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es6-error": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", - "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", - "dev": true - }, - "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/eslint": { - "version": "4.19.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz", - "integrity": "sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ==", - "dev": true, - "dependencies": { - "ajv": "^5.3.0", - "babel-code-frame": "^6.22.0", - "chalk": "^2.1.0", - "concat-stream": "^1.6.0", - "cross-spawn": "^5.1.0", - "debug": "^3.1.0", - "doctrine": "^2.1.0", - "eslint-scope": "^3.7.1", - "eslint-visitor-keys": "^1.0.0", - "espree": "^3.5.4", - "esquery": "^1.0.0", - "esutils": "^2.0.2", - "file-entry-cache": "^2.0.0", - "functional-red-black-tree": "^1.0.1", - "glob": "^7.1.2", - "globals": "^11.0.1", - "ignore": "^3.3.3", - "imurmurhash": "^0.1.4", - "inquirer": "^3.0.6", - "is-resolvable": "^1.0.0", - "js-yaml": "^3.9.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.4", - "minimatch": "^3.0.2", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "optionator": "^0.8.2", - "path-is-inside": "^1.0.2", - "pluralize": "^7.0.0", - "progress": "^2.0.0", - "regexpp": "^1.0.1", - "require-uncached": "^1.0.3", - "semver": "^5.3.0", - "strip-ansi": "^4.0.0", - "strip-json-comments": "~2.0.1", - "table": "4.0.2", - "text-table": "~0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-scope": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.3.tgz", - "integrity": "sha512-W+B0SvF4gamyCTmUc+uITPY0989iXVfKvhwtmJocTaYoc/3khEHmEmvfY/Gn9HA9VV75jrQECsHizkNw1b68FA==", - "dev": true, - "dependencies": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/espree": { - "version": "3.5.4", - "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", - "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", - "dev": true, - "dependencies": { - "acorn": "^5.5.0", - "acorn-jsx": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/external-editor": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", - "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", - "dev": true, - "dependencies": { - "chardet": "^0.4.0", - "iconv-lite": "^0.4.17", - "tmp": "^0.0.33" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/fabric-contract-api": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/fabric-contract-api/-/fabric-contract-api-2.5.6.tgz", - "integrity": "sha512-AosGb8tA+Jgt+pqMEgYNB3/J/P5QuWOC7yhXbhDmAAwUzn4Sc7pdWDICH1YyrFGZNFxMGQmqJmLVWUX8BKHy0w==", - "dependencies": { - "class-transformer": "^0.4.0", - "fabric-shim-api": "2.5.6", - "fast-safe-stringify": "^2.1.1", - "get-params": "^0.1.2", - "reflect-metadata": "^0.1.13", - "winston": "^3.7.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/fabric-shim": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/fabric-shim/-/fabric-shim-2.5.6.tgz", - "integrity": "sha512-4Y8WNFhYuQ9QYSEgPXWdlXnrXjwOlM10sQQzE4kJ7cDh8a4LX0rn44FxtxTCB18lnzrSLMZ8/8Cr5m0c9NeXWA==", - "dependencies": { - "@fidm/x509": "^1.2.1", - "@grpc/grpc-js": "~1.10.9", - "@hyperledger/fabric-protos": "~0.2.1", - "@types/node": "^16.11.1", - "ajv": "^6.12.2", - "fabric-contract-api": "2.5.6", - "fabric-shim-api": "2.5.6", - "fast-safe-stringify": "^2.1.1", - "long": "^5.2.3", - "reflect-metadata": "^0.1.13", - "winston": "^3.7.2", - "yargs": "^17.4.0", - "yargs-parser": "^21.0.1" - }, - "bin": { - "fabric-chaincode-node": "cli.js" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/fabric-shim-api": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/fabric-shim-api/-/fabric-shim-api-2.5.6.tgz", - "integrity": "sha512-1L0nO7CJ31/gEOWKWHEeCqgB5HkqPVfRbpcS7L9eTscT7tffjg2OkZISvC+a7RiqihL0iyrXNBgBg5MwlSSN9g==", - "engines": { - "eslint": "^6.6.0", - "node": ">=18" - } - }, - "node_modules/fabric-shim/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/fabric-shim/node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "node_modules/fabric-shim/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "node_modules/fast-deep-equal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", - "integrity": "sha512-fueX787WZKCV0Is4/T2cyAdM4+x1S3MXXOAhavE1ys/W42SHAPacLTQhucja22QBYrfGw50M2sRiXPtTGv9Ymw==", - "dev": true - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fast-safe-stringify": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", - "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==" - }, - "node_modules/fecha": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", - "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" - }, - "node_modules/figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/file-entry-cache": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", - "integrity": "sha512-uXP/zGzxxFvFfcZGgBIwotm+Tdc55ddPAzF7iHshP4YGaXMww7rSF9peD9D1sui5ebONg5UobsZv+FfgEpGv/w==", - "dev": true, - "dependencies": { - "flat-cache": "^1.2.1", - "object-assign": "^4.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-cache-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", - "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", - "dev": true, - "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^2.0.0", - "pkg-dir": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true, - "bin": { - "flat": "cli.js" - } - }, - "node_modules/flat-cache": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz", - "integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==", - "dev": true, - "dependencies": { - "circular-json": "^0.3.1", - "graceful-fs": "^4.1.2", - "rimraf": "~2.6.2", - "write": "^0.2.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fn.name": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", - "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" - }, - "node_modules/foreground-child": { - "version": "1.5.6", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-1.5.6.tgz", - "integrity": "sha512-3TOY+4TKV0Ml83PXJQY+JFQaHNV38lzQDIzzXYg1kWdBLenGgoZhAs0CKgzI31vi2pWEpQMq/Yi4bpKwCPkw7g==", - "dev": true, - "dependencies": { - "cross-spawn": "^4", - "signal-exit": "^3.0.0" - } - }, - "node_modules/foreground-child/node_modules/cross-spawn": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", - "integrity": "sha512-yAXz/pA1tD8Gtg2S98Ekf/sewp3Lcp3YoFKJ4Hkp5h5yLWnKVTDU0kwjKJ8NDCYcfTLfyGkzTikst+jWypT1iA==", - "dev": true, - "dependencies": { - "lru-cache": "^4.0.1", - "which": "^1.2.9" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", - "dev": true - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-func-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", - "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/get-params": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/get-params/-/get-params-0.1.2.tgz", - "integrity": "sha512-41eOxtlGgHQRbFyA8KTH+w+32Em3cRdfBud7j67ulzmIfmaHX9doq47s0fa4P5o9H64BZX9nrYI6sJvk46Op+Q==" - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/google-protobuf": { - "version": "3.21.2", - "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.21.2.tgz", - "integrity": "sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA==" - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true - }, - "node_modules/growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", - "dev": true, - "engines": { - "node": ">=4.x" - } - }, - "node_modules/has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-ansi/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/hasha": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hasha/-/hasha-3.0.0.tgz", - "integrity": "sha512-w0Kz8lJFBoyaurBiNrIvxPqr/gJ6fOfSkpAPOepN3oECqGJag37xPbOv57izi/KP8auHgNYxn5fXtAb+1LsJ6w==", - "dev": true, - "dependencies": { - "is-stream": "^1.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, - "bin": { - "he": "bin/he" - } - }, - "node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ignore": { - "version": "3.3.10", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", - "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", - "dev": true - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/inquirer": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", - "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", - "dev": true, - "dependencies": { - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.0", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^2.0.4", - "figures": "^2.0.0", - "lodash": "^4.3.0", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rx-lite": "^4.0.8", - "rx-lite-aggregates": "^4.0.8", - "string-width": "^2.1.0", - "strip-ansi": "^4.0.0", - "through": "^2.3.6" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", - "dev": true, - "dependencies": { - "hasown": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-resolvable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", - "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", - "dev": true - }, - "node_modules/is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/istanbul-lib-coverage": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", - "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/istanbul-lib-hook": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-2.0.7.tgz", - "integrity": "sha512-vrRztU9VRRFDyC+aklfLoeXyNdTfga2EI3udDGn4cZ6fpSXpHLV9X6CHvfoMCPtggg8zvDDmC4b9xfu0z6/llA==", - "dev": true, - "dependencies": { - "append-transform": "^1.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/istanbul-lib-instrument": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz", - "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==", - "dev": true, - "dependencies": { - "@babel/generator": "^7.4.0", - "@babel/parser": "^7.4.3", - "@babel/template": "^7.4.0", - "@babel/traverse": "^7.4.3", - "@babel/types": "^7.4.0", - "istanbul-lib-coverage": "^2.0.5", - "semver": "^6.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/istanbul-lib-report": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz", - "integrity": "sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==", - "dev": true, - "dependencies": { - "istanbul-lib-coverage": "^2.0.5", - "make-dir": "^2.1.0", - "supports-color": "^6.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/istanbul-lib-report/node_modules/supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", - "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^2.0.5", - "make-dir": "^2.1.0", - "rimraf": "^2.6.3", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/istanbul-lib-source-maps/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/istanbul-lib-source-maps/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/istanbul-reports": { - "version": "2.2.7", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.7.tgz", - "integrity": "sha512-uu1F/L1o5Y6LzPVSVZXNOoD/KXpJue9aeLRd0sM9uMXfZvzomB0WxVamWb5ue8kA2vVWEmW7EG+A5n3f1kqHKg==", - "dev": true, - "dependencies": { - "html-escaper": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha512-RjTcuD4xjtthQkaWH7dFlH85L+QaVtSoOyGdZ3g6HFhS9dFNDfLyqgm2NFe2X6cQpeFmt0452FJjFG5UameExg==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha512-4JD/Ivzg7PoW8NzdrBSr3UFwC9mHgvI7Z6z3QGBsSHgKaRTUDmyZAAKJo2UbG1kUVfS9WS8bi36N49U1xw43DA==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/just-extend": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz", - "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==", - "dev": true - }, - "node_modules/kuler": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", - "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" - }, - "node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", - "dev": true, - "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/load-json-file/node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "node_modules/lodash.camelcase": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" - }, - "node_modules/lodash.flattendeep": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", - "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==", - "dev": true - }, - "node_modules/lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", - "dev": true - }, - "node_modules/log-symbols": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", - "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/log-symbols/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/log-symbols/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/log-symbols/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/log-symbols/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/log-symbols/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/log-symbols/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/logform": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.0.tgz", - "integrity": "sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ==", - "dependencies": { - "@colors/colors": "1.6.0", - "@types/triple-beam": "^1.3.2", - "fecha": "^4.2.0", - "ms": "^2.1.1", - "safe-stable-stringify": "^2.3.1", - "triple-beam": "^1.3.0" - }, - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/lolex": { - "version": "2.7.5", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.7.5.tgz", - "integrity": "sha512-l9x0+1offnKKIzYVjyXU2SiwhXDLekRzKyhnbyldPHvC7BvLPVpdNUNR2KeMAiCN2D/kLNttZgQD5WjSxuBx3Q==", - "dev": true - }, - "node_modules/long": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", - "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" - }, - "node_modules/loupe": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", - "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", - "dev": true, - "dependencies": { - "get-func-name": "^2.0.1" - } - }, - "node_modules/lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dev": true, - "dependencies": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "node_modules/make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, - "dependencies": { - "pify": "^4.0.1", - "semver": "^5.6.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/merge-source-map": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", - "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", - "dev": true, - "dependencies": { - "source-map": "^0.6.1" - } - }, - "node_modules/mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dev": true, - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/mocha": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.4.0.tgz", - "integrity": "sha512-hJaO0mwDXmZS4ghXsvPVriOhsxQ7ofcpQdm8dE+jISUOKopitvnXFQmpRR7jd2K6VBG6E26gU3IAbXXGIbu4sQ==", - "dev": true, - "dependencies": { - "@ungap/promise-all-settled": "1.1.2", - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.1", - "debug": "4.3.1", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.1.6", - "growl": "1.10.5", - "he": "1.2.0", - "js-yaml": "4.0.0", - "log-symbols": "4.0.0", - "minimatch": "3.0.4", - "ms": "2.1.3", - "nanoid": "3.1.20", - "serialize-javascript": "5.0.1", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "which": "2.0.2", - "wide-align": "1.1.3", - "workerpool": "6.1.0", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha" - }, - "engines": { - "node": ">= 10.12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mochajs" - } - }, - "node_modules/mocha/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/mocha/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/mocha/node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/mocha/node_modules/debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/mocha/node_modules/debug/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/mocha/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mocha/node_modules/glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/mocha/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/mocha/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/mocha/node_modules/js-yaml": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", - "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/mocha/node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/mocha/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/mocha/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/mocha/node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mocha/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/mocha/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/mocha/node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mocha/node_modules/yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "node_modules/mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha512-r65nCZhrbXXb6dXOACihYApHw2Q6pV0M3V0PSxd74N0+D8nzAdEAITq2oAjA1jVnKI+tGvEBUpqiMh0+rW6zDQ==", - "dev": true - }, - "node_modules/nanoid": { - "version": "3.1.20", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.20.tgz", - "integrity": "sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw==", - "dev": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/nested-error-stacks": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.1.tgz", - "integrity": "sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw==", - "dev": true - }, - "node_modules/nise": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/nise/-/nise-1.5.3.tgz", - "integrity": "sha512-Ymbac/94xeIrMf59REBPOv0thr+CJVFMhrlAkW/gjCIE58BGQdCj0x7KRCb3yz+Ga2Rz3E9XXSvUyyxqqhjQAQ==", - "dev": true, - "dependencies": { - "@sinonjs/formatio": "^3.2.1", - "@sinonjs/text-encoding": "^0.7.1", - "just-extend": "^4.0.2", - "lolex": "^5.0.1", - "path-to-regexp": "^1.7.0" - } - }, - "node_modules/nise/node_modules/lolex": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-5.1.2.tgz", - "integrity": "sha512-h4hmjAvHTmd+25JSwrtTIuwbKdwg5NzZVRMLn9saij4SZaepCrTCxPr35H/3bjwfMJtN+t3CX8672UIkglz28A==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^1.7.0" - } - }, - "node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nyc": { - "version": "14.1.1", - "resolved": "https://registry.npmjs.org/nyc/-/nyc-14.1.1.tgz", - "integrity": "sha512-OI0vm6ZGUnoGZv/tLdZ2esSVzDwUC88SNs+6JoSOMVxA+gKMB8Tk7jBwgemLx4O40lhhvZCVw1C+OYLOBOPXWw==", - "dev": true, - "dependencies": { - "archy": "^1.0.0", - "caching-transform": "^3.0.2", - "convert-source-map": "^1.6.0", - "cp-file": "^6.2.0", - "find-cache-dir": "^2.1.0", - "find-up": "^3.0.0", - "foreground-child": "^1.5.6", - "glob": "^7.1.3", - "istanbul-lib-coverage": "^2.0.5", - "istanbul-lib-hook": "^2.0.7", - "istanbul-lib-instrument": "^3.3.0", - "istanbul-lib-report": "^2.0.8", - "istanbul-lib-source-maps": "^3.0.6", - "istanbul-reports": "^2.2.4", - "js-yaml": "^3.13.1", - "make-dir": "^2.1.0", - "merge-source-map": "^1.1.0", - "resolve-from": "^4.0.0", - "rimraf": "^2.6.3", - "signal-exit": "^3.0.2", - "spawn-wrap": "^1.4.2", - "test-exclude": "^5.2.3", - "uuid": "^3.3.2", - "yargs": "^13.2.2", - "yargs-parser": "^13.0.0" - }, - "bin": { - "nyc": "bin/nyc.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/nyc/node_modules/ansi-regex": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", - "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/nyc/node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/nyc/node_modules/cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", - "dev": true, - "dependencies": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - } - }, - "node_modules/nyc/node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nyc/node_modules/emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "node_modules/nyc/node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/nyc/node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/nyc/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/nyc/node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/nyc/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/nyc/node_modules/string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "dependencies": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/nyc/node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "dependencies": { - "ansi-regex": "^4.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/nyc/node_modules/wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/nyc/node_modules/y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "dev": true - }, - "node_modules/nyc/node_modules/yargs": { - "version": "13.3.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", - "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", - "dev": true, - "dependencies": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.2" - } - }, - "node_modules/nyc/node_modules/yargs-parser": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", - "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", - "dev": true, - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/one-time": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", - "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", - "dependencies": { - "fn.name": "1.x.x" - } - }, - "node_modules/onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==", - "dev": true, - "dependencies": { - "mimic-fn": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/package-hash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-3.0.0.tgz", - "integrity": "sha512-lOtmukMDVvtkL84rJHI7dpTYq+0rli8N2wlnqUcBuDWCfVhRUfOmnR9SsoHFMLpACvEV60dX7rd0rFaYDZI+FA==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.15", - "hasha": "^3.0.0", - "lodash.flattendeep": "^4.4.0", - "release-zalgo": "^1.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", - "dev": true, - "dependencies": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", - "dev": true - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/path-to-regexp": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", - "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", - "dev": true, - "dependencies": { - "isarray": "0.0.1" - } - }, - "node_modules/path-to-regexp/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - }, - "node_modules/path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "dependencies": { - "pify": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/path-type/node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/picocolors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "dev": true, - "dependencies": { - "find-up": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-dir/node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-dir/node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-dir/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pkg-dir/node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-dir/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/pluralize": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", - "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/protobufjs": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.3.2.tgz", - "integrity": "sha512-RXyHaACeqXeqAKGLDl68rQKbmObRsTIn4TYVUUug1KfS47YWCo5MacGITEryugIgZqORCvJWEk4l449POg5Txg==", - "hasInstallScript": true, - "dependencies": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/node": ">=13.7.0", - "long": "^5.0.0" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", - "dev": true - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==", - "dev": true, - "dependencies": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg-up": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", - "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", - "dev": true, - "dependencies": { - "find-up": "^3.0.0", - "read-pkg": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/read-pkg-up/node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/read-pkg-up/node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/read-pkg-up/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/read-pkg-up/node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/read-pkg-up/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/readable-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/readdirp": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", - "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/reflect-metadata": { - "version": "0.1.14", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.14.tgz", - "integrity": "sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A==" - }, - "node_modules/regexpp": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz", - "integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==", - "dev": true, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/release-zalgo": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", - "integrity": "sha512-gUAyHVHPPC5wdqX/LG4LWtRYtgjxyX78oanFNTMMyFEfOqdC54s3eE82imuWKbOeqYht2CrNf64Qb8vgmmtZGA==", - "dev": true, - "dependencies": { - "es6-error": "^4.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, - "node_modules/require-uncached": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", - "integrity": "sha512-Xct+41K3twrbBHdxAgMoOS+cNcoqIjfM2/VxBF4LL2hVph7YsF8VSKyQ3BDFZwEVbok9yeDl2le/qo0S77WG2w==", - "dev": true, - "dependencies": { - "caller-path": "^0.1.0", - "resolve-from": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-uncached/node_modules/resolve-from": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", - "integrity": "sha512-kT10v4dhrlLNcnO084hEjvXCI1wUG9qZLoz2RogxqDQQYy7IxjI/iMUkOtQTNEh6rzHxvdQWHsJyel1pKOVCxg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dev": true, - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==", - "dev": true, - "dependencies": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/rx-lite": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", - "integrity": "sha512-Cun9QucwK6MIrp3mry/Y7hqD1oFqTYLQ4pGxaHTjIdaFDWRGGLikqp6u8LcWJnzpoALg9hap+JGk8sFIUuEGNA==", - "dev": true - }, - "node_modules/rx-lite-aggregates": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz", - "integrity": "sha512-3xPNZGW93oCjiO7PtKxRK6iOVYBWBvtf9QHDfU23Oc+dLIQmAV//UnyXV/yihv81VS/UqoQPk4NegS8EFi55Hg==", - "dev": true, - "dependencies": { - "rx-lite": "*" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/safe-stable-stringify": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", - "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", - "engines": { - "node": ">=10" - } - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/serialize-javascript": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", - "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", - "dev": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "dev": true - }, - "node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", - "dev": true, - "dependencies": { - "shebang-regex": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", - "dependencies": { - "is-arrayish": "^0.3.1" - } - }, - "node_modules/simple-swizzle/node_modules/is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" - }, - "node_modules/sinon": { - "version": "6.3.5", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-6.3.5.tgz", - "integrity": "sha512-xgoZ2gKjyVRcF08RrIQc+srnSyY1JDJtxu3Nsz07j1ffjgXoY6uPLf/qja6nDBZgzYYEovVkFryw2+KiZz11xQ==", - "deprecated": "16.1.1", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^1.0.2", - "@sinonjs/formatio": "^3.0.0", - "@sinonjs/samsam": "^2.1.2", - "diff": "^3.5.0", - "lodash.get": "^4.4.2", - "lolex": "^2.7.5", - "nise": "^1.4.5", - "supports-color": "^5.5.0", - "type-detect": "^4.0.8" - } - }, - "node_modules/sinon-chai": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/sinon-chai/-/sinon-chai-3.7.0.tgz", - "integrity": "sha512-mf5NURdUaSdnatJx3uhoBOrY9dtL19fiOtAdT1Azxg3+lNJFiuN0uzaU3xX1LeAfL17kHQhTAJgpsfhbMJMY2g==", - "dev": true, - "peerDependencies": { - "chai": "^4.0.0", - "sinon": ">=4.0.0" - } - }, - "node_modules/sinon/node_modules/diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/slice-ansi": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", - "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", - "dev": true, - "dependencies": { - "is-fullwidth-code-point": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/spawn-wrap": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-1.4.3.tgz", - "integrity": "sha512-IgB8md0QW/+tWqcavuFgKYR/qIRvJkRLPJDFaoXtLLUaVcCDK0+HeFTkmQHj3eprcYhc+gOl0aEA1w7qZlYezw==", - "dev": true, - "dependencies": { - "foreground-child": "^1.5.6", - "mkdirp": "^0.5.0", - "os-homedir": "^1.0.1", - "rimraf": "^2.6.2", - "signal-exit": "^3.0.2", - "which": "^1.3.0" - } - }, - "node_modules/spdx-correct": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", - "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", - "dev": true, - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", - "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", - "dev": true - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.18", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.18.tgz", - "integrity": "sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ==", - "dev": true - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, - "node_modules/stack-trace": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", - "engines": { - "node": "*" - } - }, - "node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/string_decoder/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "dependencies": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", - "dev": true, - "dependencies": { - "ansi-regex": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/table": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz", - "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==", - "dev": true, - "dependencies": { - "ajv": "^5.2.3", - "ajv-keywords": "^2.1.0", - "chalk": "^2.1.0", - "lodash": "^4.17.4", - "slice-ansi": "1.0.0", - "string-width": "^2.1.1" - } - }, - "node_modules/test-exclude": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz", - "integrity": "sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g==", - "dev": true, - "dependencies": { - "glob": "^7.1.3", - "minimatch": "^3.0.4", - "read-pkg-up": "^4.0.0", - "require-main-filename": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/text-hex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", - "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true - }, - "node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "dependencies": { - "os-tmpdir": "~1.0.2" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/triple-beam": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", - "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/tweetnacl": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", - "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" - }, - "node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", - "dev": true, - "dependencies": { - "prelude-ls": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", - "dev": true - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", - "dev": true, - "bin": { - "uuid": "bin/uuid" - } - }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/which-module": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", - "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", - "dev": true - }, - "node_modules/wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", - "dev": true, - "dependencies": { - "string-width": "^1.0.2 || 2" - } - }, - "node_modules/winston": { - "version": "3.13.0", - "resolved": "https://registry.npmjs.org/winston/-/winston-3.13.0.tgz", - "integrity": "sha512-rwidmA1w3SE4j0E5MuIufFhyJPBDG7Nu71RkZor1p2+qHvJSZ9GYDA81AyleQcZbh/+V6HjeBdfnTZJm9rSeQQ==", - "dependencies": { - "@colors/colors": "^1.6.0", - "@dabh/diagnostics": "^2.0.2", - "async": "^3.2.3", - "is-stream": "^2.0.0", - "logform": "^2.4.0", - "one-time": "^1.0.0", - "readable-stream": "^3.4.0", - "safe-stable-stringify": "^2.3.1", - "stack-trace": "0.0.x", - "triple-beam": "^1.3.0", - "winston-transport": "^4.7.0" - }, - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/winston-transport": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.7.0.tgz", - "integrity": "sha512-ajBj65K5I7denzer2IYW6+2bNIVqLGDHqDw3Ow8Ohh+vdW+rv4MZ6eiDvHoKhfJFZ2auyN8byXieDDJ96ViONg==", - "dependencies": { - "logform": "^2.3.2", - "readable-stream": "^3.6.0", - "triple-beam": "^1.3.0" - }, - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/winston-transport/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/winston/node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/winston/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/workerpool": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.0.tgz", - "integrity": "sha512-toV7q9rWNYha963Pl/qyeZ6wG+3nnsyvolaNUS8+R5Wtw6qJPTxIlOP1ZSvcGhEJw+l3HMMmtiNo9Gl61G4GVg==", - "dev": true - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/wrap-ansi/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "node_modules/write": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", - "integrity": "sha512-CJ17OoULEKXpA5pef3qLj5AxTJ6mSt7g84he2WIskKwqFO4T97d5V7Tadl0DYDk7qyUOQD5WlUlOMChaYrhxeA==", - "dev": true, - "dependencies": { - "mkdirp": "^0.5.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/write-file-atomic": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", - "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.2" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", - "dev": true - }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dev": true, - "dependencies": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - } -} diff --git a/token-erc-721/chaincode-javascript/package.json b/token-erc-721/chaincode-javascript/package.json deleted file mode 100644 index 6e5d6afb..00000000 --- a/token-erc-721/chaincode-javascript/package.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "name": "token-erc721", - "version": "0.0.1", - "description": "Token-ERC721 contract implemented in JavaScript", - "main": "index.js", - "engines": { - "node": ">=12", - "npm": ">=5" - }, - "scripts": { - "lint": "eslint .", - "pretest": "npm run lint", - "test": "nyc mocha --recursive", - "mocha": "mocha --recursive", - "start": "fabric-chaincode-node start" - }, - "engineStrict": true, - "author": "Hyperledger", - "license": "Apache-2.0", - "dependencies": { - "fabric-contract-api": "~2.5", - "fabric-shim": "~2.5" - }, - "devDependencies": { - "chai": "^4.1.2", - "chai-as-promised": "^7.1.1", - "eslint": "^4.19.1", - "mocha": "^8.0.1", - "nyc": "^14.1.1", - "sinon": "^6.0.0", - "sinon-chai": "^3.2.0" - }, - "nyc": { - "exclude": [ - "coverage/**", - "test/**", - "index.js", - ".eslintrc.js" - ], - "reporter": [ - "text-summary", - "html" - ], - "all": true, - "check-coverage": false, - "statements": 100, - "branches": 100, - "functions": 100, - "lines": 100 - } -} diff --git a/token-erc-721/chaincode-javascript/test/tokenERC721.test.js b/token-erc-721/chaincode-javascript/test/tokenERC721.test.js deleted file mode 100644 index 489e8cf0..00000000 --- a/token-erc-721/chaincode-javascript/test/tokenERC721.test.js +++ /dev/null @@ -1,338 +0,0 @@ -/* -SPDX-License-Identifier: Apache-2.0 -*/ - -'use strict'; - -const { Context } = require('fabric-contract-api'); -const { ChaincodeStub, ClientIdentity } = require('fabric-shim'); - -const { tokenERC721Contract } = require('..'); - -const chai = require('chai'); -const chaiAsPromised = require('chai-as-promised'); -const sinon = require('sinon'); -const expect = chai.expect; - -chai.should(); -chai.use(chaiAsPromised); - -class MockIterator { - constructor(data) { - this.array = data; - this.cur = 0; - } - next() { - if (this.cur < this.array.length) { - const value = this.array[this.cur]; - this.cur++; - return Promise.resolve({ value: value }); - } else { - return Promise.resolve({ done: true }); - } - } - close() { - return Promise.resolve(); - } -} - -describe('Chaincode', () => { - let sandbox; - let token; - let ctx; - let mockStub; - let mockClientIdentity; - - beforeEach('Sandbox creation', () => { - sandbox = sinon.createSandbox(); - token = new tokenERC721Contract('token-erc721'); - - ctx = sinon.createStubInstance(Context); - mockStub = sinon.createStubInstance(ChaincodeStub); - ctx.stub = mockStub; - mockClientIdentity = sinon.createStubInstance(ClientIdentity); - ctx.clientIdentity = mockClientIdentity; - }); - - afterEach('Sandbox restoration', () => { - sandbox.restore(); - }); - - describe('#BalanceOf', () => { - it('should work', async () => { - const mockResponse = [ - { key: 'balance_Alice_101', value: Buffer.from('\u0000') }, - { key: 'balance_Alice_102', value: Buffer.from('\u0000') } - ]; - mockStub.getStateByPartialCompositeKey.resolves(new MockIterator(mockResponse)); - - const response = await token.BalanceOf(ctx, 'Alice'); - expect(response).to.equals(2); - }); - }); - - describe('#OwnerOf', () => { - it('should work', async () => { - const nft = { - tokenId: 101, - owner: 'Alice' - }; - sinon.stub(token, '_readNFT').resolves(nft); - - const response = await token.OwnerOf(ctx, '101'); - expect(response).to.equal('Alice'); - }); - }); - - describe('#TransferFrom', () => { - let currentNft; - let updatedNft; - - beforeEach('Set up test parameters', () => { - currentNft = { - tokenId: 101, - owner: 'Alice', - approved: 'Charlie' - }; - - updatedNft = { - tokenId: 101, - owner: 'Bob', - approved: '' - }; - - sinon.stub(token, '_readNFT').resolves(currentNft); - mockStub.createCompositeKey.withArgs('nft', ['101']).returns('nft_101'); - mockStub.createCompositeKey.withArgs('balance', ['Alice', '101']).returns('balance_Alice_101'); - mockStub.createCompositeKey.withArgs('balance', ['Bob', '101']).returns('balance_Bob_101'); - }); - - it('should work when a sender is the current owner', async () => { - mockClientIdentity.getID.returns('Alice'); - sinon.stub(token, 'IsApprovedForAll').resolves(false); - - const response = await token.TransferFrom(ctx, 'Alice', 'Bob', '101'); - sinon.assert.calledWith(mockStub.putState, 'nft_101', Buffer.from(JSON.stringify(updatedNft))); - expect(response).to.equals(true); - }); - - it('should work when a sender is the approved client for this token', async () => { - mockClientIdentity.getID.returns('Charlie'); - sinon.stub(token, 'IsApprovedForAll').resolves(false); - - const response = await token.TransferFrom(ctx, 'Alice', 'Bob', '101'); - sinon.assert.calledWith(mockStub.putState, 'nft_101', Buffer.from(JSON.stringify(updatedNft))); - expect(response).to.equals(true); - }); - - it('should work when a sender is an authorized operator', async () => { - mockClientIdentity.getID.returns('Dave'); - sinon.stub(token, 'IsApprovedForAll').resolves(true); - - const response = await token.TransferFrom(ctx, 'Alice', 'Bob', '101'); - sinon.assert.calledWith(mockStub.putState, 'nft_101', Buffer.from(JSON.stringify(updatedNft))); - expect(response).to.equals(true); - }); - - it('should throw an error when a sender is invalid', async () => { - mockClientIdentity.getID.returns('Eve'); - sinon.stub(token, 'IsApprovedForAll').resolves(false); - - await expect(token.TransferFrom(ctx, 'Alice', 'Bob', '101')) - .to.be.rejectedWith(Error, 'The sender is not allowed to transfer the non-fungible token'); - }); - - it('should throw an error when a current owner does not match', async () => { - mockClientIdentity.getID.returns('Dave'); - sinon.stub(token, 'IsApprovedForAll').resolves(true); - - await expect(token.TransferFrom(ctx, 'Charlie', 'Bob', '101')) - .to.be.rejectedWith(Error, 'The from is not the current owner.'); - }); - - }); - - describe('#Approve', () => { - it('should work with the token owner', async () => { - mockClientIdentity.getID.returns('Alice'); - const currentNft = { - tokenId: 101, - owner: 'Alice', - }; - sinon.stub(token, '_readNFT').resolves(currentNft); - sinon.stub(token, 'IsApprovedForAll').resolves(false); - mockStub.createCompositeKey.withArgs('nft', ['101']).returns('nft_101'); - - const response = await token.Approve(ctx, 'Bob', '101'); - const updatedNft = { - tokenId: 101, - owner: 'Alice', - approved: 'Bob' - }; - sinon.assert.calledWith(mockStub.putState, 'nft_101', Buffer.from(JSON.stringify(updatedNft))); - expect(response).to.equals(true); - }); - }); - - describe('#SetApprovalForAll', () => { - it('should work', async () => { - mockClientIdentity.getID.returns('Alice'); - mockStub.createCompositeKey.withArgs('approval', ['Alice', 'Bob']).returns('approval_Alice_Bob'); - - const response = await token.SetApprovalForAll(ctx, 'Bob', true); - const approval = { - owner: 'Alice', - operator: 'Bob', - approved: true - }; - sinon.assert.calledWith(mockStub.putState, 'approval_Alice_Bob', Buffer.from(JSON.stringify(approval))); - expect(response).to.equals(true); - }); - }); - - describe('#GetApproved', () => { - it('should work', async () => { - const nft = { - tokenId: 101, - owner: 'Alice', - approved: 'Bob', - }; - sinon.stub(token, '_readNFT').resolves(nft); - - const response = await token.GetApproved(ctx, '101'); - expect(response).to.equals('Bob'); - }); - }); - - describe('#IsApprovedForAll', () => { - it('should work', async () => { - mockStub.createCompositeKey.withArgs('approval', ['Alice', 'Bob']).returns('approval_Alice_Bob'); - const approval = { - owner: 'Alice', - operator: 'Bob', - approved: true - }; - mockStub.getState.withArgs('approval_Alice_Bob').resolves(Buffer.from(JSON.stringify(approval))); - - const response = await token.IsApprovedForAll(ctx, 'Alice', 'Bob'); - expect(response).to.equals(true); - }); - }); - - describe('#Name', () => { - it('should work', async () => { - mockStub.getState.resolves('some state'); - - const response = await token.Name(ctx); - expect(response).to.equals('some state'); - }); - }); - - describe('#Symbol', () => { - it('should work', async () => { - mockStub.getState.resolves('some state'); - - const response = await token.Symbol(ctx); - expect(response).to.equals('some state'); - }); - }); - - describe('#TokenURI', () => { - it('should work', async () => { - const nft = { - tokenId: 101, - owner: 'Alice', - tokenURI: 'DummyURI' - }; - sinon.stub(token, '_readNFT').resolves(nft); - - const response = await token.TokenURI(ctx, '101'); - expect(response).to.equal('DummyURI'); - }); - }); - - describe('#TotalSupply', () => { - it('should work', async () => { - const mockResponse = [ - { key: 'nft_101', value: Buffer.from(JSON.stringify({ tokenId: 101, owner: 'Alice' })) }, - { key: 'nft_102', value: Buffer.from(JSON.stringify({ tokenId: 102, owner: 'Bob' })) } - ]; - mockStub.getStateByPartialCompositeKey.resolves(new MockIterator(mockResponse)); - - const response = await token.TotalSupply(ctx); - expect(response).to.equals(2); - }); - }); - - describe('#MintWithTokenURI', () => { - it('should work with a new token', async () => { - mockClientIdentity.getMSPID.returns('Org1MSP'); - mockClientIdentity.getID.returns('Alice'); - sinon.stub(token, '_nftExists').resolves(false); - mockStub.createCompositeKey.withArgs('nft', ['101']).returns('nft_101'); - mockStub.createCompositeKey.withArgs('balance', ['Alice', '101']).returns('balance_Alice_101'); - - const response = await token.MintWithTokenURI(ctx, '101', 'DummyURI'); - const nft = { tokenId: 101, owner: 'Alice', tokenURI: 'DummyURI'}; - sinon.assert.calledWith(mockStub.putState.getCall(0), 'nft_101', Buffer.from(JSON.stringify(nft))); - sinon.assert.calledWith(mockStub.putState.getCall(1), 'balance_Alice_101', Buffer.from('\u0000')); - expect(response).to.deep.equal(nft); - }); - - it('should throw an error when a tokenId alreay exists', async () => { - mockClientIdentity.getMSPID.returns('Org1MSP'); - mockClientIdentity.getID.returns('Alice'); - sinon.stub(token, '_nftExists').resolves(true); - - await expect(token.MintWithTokenURI(ctx, 'mytoken1', 'DummyURI')) - .to.be.rejectedWith(Error, 'The token mytoken1 is already minted.'); - }); - - it('should throw an error when a tokenId is not an integer', async () => { - mockClientIdentity.getMSPID.returns('Org1MSP'); - mockClientIdentity.getID.returns('Alice'); - sinon.stub(token, '_nftExists').resolves(false); - - await expect(token.MintWithTokenURI(ctx, 'mytoken1', 'DummyURI')) - .to.be.rejectedWith(Error, 'The tokenId mytoken1 is invalid. tokenId must be an integer'); - }); - - }); - - describe('#Burn', () => { - it('should work', async () => { - mockClientIdentity.getID.returns('Bob'); - - const nft = { - tokenId: 101, - owner: 'Bob', - }; - sinon.stub(token, '_readNFT').resolves(nft); - - mockStub.createCompositeKey.withArgs('nft', ['101']).returns('nft_101'); - mockStub.createCompositeKey.withArgs('balance', ['Bob', '101']).returns('balance_Bob_101'); - - const response = await token.Burn(ctx, '101'); - sinon.assert.calledWith(mockStub.deleteState.getCall(0), 'nft_101'); - sinon.assert.calledWith(mockStub.deleteState.getCall(1), 'balance_Bob_101'); - expect(response).to.equals(true); - }); - }); - - describe('#_readNFT', () => { - it('should work', async () => { - mockStub.createCompositeKey.returns('nft_101'); - const nft = { - tokenId: 101, - owner: 'Alice', - approved: 'Bob', - tokenURI: 'DummyURI' - }; - mockStub.getState.resolves(Buffer.from(JSON.stringify(nft))); - - const response = await token._readNFT(ctx, '101'); - expect(response).to.deep.equal(nft); - }); - }); - -});