From 815197bc861585e47abc072bd89896c8ad21f08e Mon Sep 17 00:00:00 2001 From: sapthasurendran Date: Thu, 19 May 2022 17:49:13 +0530 Subject: [PATCH] Moved contract interactions to contractWrapper Signed-off-by: sapthasurendran --- .../application-gateway-typescript/src/app.ts | 303 ++++------------- .../src/contractWrapper.ts | 314 +++++++++++++----- .../src/utils.ts | 36 +- 3 files changed, 318 insertions(+), 335 deletions(-) diff --git a/asset-transfer-secured-agreement/application-gateway-typescript/src/app.ts b/asset-transfer-secured-agreement/application-gateway-typescript/src/app.ts index cef16f7f..40e90a57 100644 --- a/asset-transfer-secured-agreement/application-gateway-typescript/src/app.ts +++ b/asset-transfer-secured-agreement/application-gateway-typescript/src/app.ts @@ -5,21 +5,18 @@ */ import { connect } from '@hyperledger/fabric-gateway'; -import crpto from 'crypto'; + import { newGrpcConnection, newIdentity, newSigner, tlsCertPathOrg1, peerEndpointOrg1, peerNameOrg1, certPathOrg1, mspIdOrg1, keyDirectoryPathOrg1, tlsCertPathOrg2, peerEndpointOrg2, peerNameOrg2, certPathOrg2, mspIdOrg2, keyDirectoryPathOrg2 } from './connect'; -import { AssetPriceJSON, AssetPropertiesJSON, GREEN, RED, RESET } from './utils'; import { ContractWrapper } from './contractWrapper'; +import { randomBytes } from './utils'; const channelName = 'mychannel'; const chaincodeName = 'secured'; //Use a random key so that we can run multiple times -const now = Date.now(); +const now = Date.now().toString(); const assetKey = `asset${now}`; -//Generate random bytes using crypto -const randomBytes = crpto.randomBytes(256).toString('hex'); - async function main(): Promise { // The gRPC client connection from org1 should be shared by all Gateway connections to this endpoint. @@ -53,119 +50,131 @@ async function main(): Promise { // Get the smart contract from the network for Org1. const contractOrg1 = gatewayOrg1.getNetwork(channelName).getContract(chaincodeName); - const contractWrapperOrg1 = new ContractWrapper(contractOrg1); + const contractWrapperOrg1 = new ContractWrapper(contractOrg1, mspIdOrg1, randomBytes); // Get the smart contract from the network for Org2. const contractOrg2 = gatewayOrg2.getNetwork(channelName).getContract(chaincodeName); - const contractWrapperOrg2 = new ContractWrapper(contractOrg2); + const contractWrapperOrg2 = new ContractWrapper(contractOrg2, mspIdOrg2, randomBytes); // Create an asset by organization Org1, this only requires the owning organization to endorse. - await createAsset(contractWrapperOrg1, mspIdOrg1); + await contractWrapperOrg1.createAsset({ AssetId: assetKey, + OwnerOrg: mspIdOrg1, + PublicDescription: `Asset ${assetKey} owned by ${mspIdOrg1} is not for sale`}, { ObjectType: 'asset_properties', Color: 'blue', Size: 35 }); // Read the public details by org1. - await readAsset(contractWrapperOrg1, assetKey, mspIdOrg1, mspIdOrg1); + await contractWrapperOrg1.readAsset(assetKey, mspIdOrg1); // Read the public details by org2. - await readAsset(contractWrapperOrg2, assetKey, mspIdOrg1, mspIdOrg2); + await contractWrapperOrg2.readAsset(assetKey, mspIdOrg1); // Org1 should be able to read the private data details of the asset. - await readPrivateAsset(contractWrapperOrg1, assetKey, mspIdOrg1); + await contractWrapperOrg1.getAssetPrivateProperties(assetKey, mspIdOrg1); // Org2 is not the owner and does not have the private details, read expected to fail. - await readPrivateAsset(contractWrapperOrg2, assetKey, mspIdOrg2); + await contractWrapperOrg2.getAssetPrivateProperties(assetKey, mspIdOrg1); // Org1 updates the assets public description. - await changePublicDescription(contractWrapperOrg1, assetKey, mspIdOrg1, `Asset ${assetKey} owned by ${mspIdOrg1} is for sale`); + await contractWrapperOrg1.changePublicDescription({AssetId: assetKey, + OwnerOrg: mspIdOrg1, + PublicDescription: `Asset ${assetKey} owned by ${mspIdOrg1} is for sale`}); // Read the public details by org1. - await readAsset(contractWrapperOrg1, assetKey, mspIdOrg1, mspIdOrg1); + await contractWrapperOrg1.readAsset(assetKey, mspIdOrg1); // Read the public details by org2. - await readAsset(contractWrapperOrg2, assetKey, mspIdOrg1, mspIdOrg2); + await contractWrapperOrg2.readAsset(assetKey, mspIdOrg1); // This is an update to the public state and requires the owner(Org1) to endorse and sent by the owner org client (Org1). // Since the client is from Org2, which is not the owner, this will fail - await changePublicDescription(contractWrapperOrg2, assetKey, mspIdOrg2, `Asset ${assetKey} owned by ${mspIdOrg2} is NOT for sale`); + await contractWrapperOrg2.changePublicDescription({AssetId: assetKey, + OwnerOrg: mspIdOrg1, + PublicDescription: `Asset ${assetKey} owned by ${mspIdOrg2} is NOT for sale`}); // Read the public details by org1. - await readAsset(contractWrapperOrg1, assetKey, mspIdOrg1, mspIdOrg1); + await contractWrapperOrg1.readAsset(assetKey, mspIdOrg1); // Read the public details by org2. - await readAsset(contractWrapperOrg2, assetKey, mspIdOrg1, mspIdOrg2); + await contractWrapperOrg2.readAsset(assetKey, mspIdOrg1); // Agree to a sell by org1. - await agreeToSell(contractWrapperOrg1, assetKey, mspIdOrg1, 110); + await contractWrapperOrg1.agreeToSell({ + AssetId: assetKey, + Price: 110, + TradeId: now, + }); // Check the private information about the asset from Org2. Org1 would have to send Org2 asset details, // so the hash of the details may be checked by the chaincode. - await verifyAssetProperties(contractWrapperOrg2, assetKey, mspIdOrg2); + await contractWrapperOrg2.verifyAssetProperties({ AssetId:assetKey, Color:'blue', Size:35}); // Agree to a buy by org2. - await agreeToBuy(contractWrapperOrg2, assetKey, mspIdOrg2, 100); + await contractWrapperOrg2.agreeToBuy( {AssetId: assetKey, + Price: 100, + TradeId: now}); - // Org1 should be able to read the sale price of this asset - await readSalePrice(contractWrapperOrg1, assetKey, mspIdOrg1); + // Org1 should be able to read the sale price of this asset. + await contractWrapperOrg1.getAssetSalesPrice(assetKey, mspIdOrg1); - // Org2 has not set a sale price and this should fail - await readSalePrice(contractWrapperOrg2, assetKey, mspIdOrg2); + // Org2 has not set a sale price and this should fail. + await contractWrapperOrg2.getAssetSalesPrice(assetKey, mspIdOrg1); - // Org1 has not agreed to buy so this should fail - await readBidPrice(contractWrapperOrg1, assetKey, mspIdOrg1); + // Org1 has not agreed to buy so this should fail. + await contractWrapperOrg1.getAssetBidPrice(assetKey, mspIdOrg2); - // Org2 should be able to see the price it has agreed - await readBidPrice(contractWrapperOrg2, assetKey, mspIdOrg2); + // Org2 should be able to see the price it has agreed. + await contractWrapperOrg2.getAssetBidPrice(assetKey, mspIdOrg2); // Org1 will try to transfer the asset to Org2 - // This will fail due to the sell price and the bid price are not the same - await transferAsset(contractWrapperOrg1, assetKey, mspIdOrg1, mspIdOrg2, 110); + // This will fail due to the sell price and the bid price are not the same. + await contractWrapperOrg1.transferAsset({ObjectType: 'asset_properties', Color: 'blue', Size: 35}, { AssetId: assetKey, Price: 110, TradeId: now}, [ mspIdOrg1, mspIdOrg2 ], mspIdOrg1, mspIdOrg2); - // Agree to a sell by Org1,the seller will agree to the bid price of Org2 - await agreeToSell(contractWrapperOrg1, assetKey, mspIdOrg1, 100); + // Agree to a sell by Org1, the seller will agree to the bid price of Org2. + await contractWrapperOrg1.agreeToSell({AssetId:assetKey, Price:100, TradeId:now}); // Read the public details by org1. - await readAsset(contractWrapperOrg1, assetKey, mspIdOrg1, mspIdOrg1); + await contractWrapperOrg1.readAsset(assetKey, mspIdOrg1); // Read the public details by org2. - await readAsset(contractWrapperOrg2, assetKey, mspIdOrg1, mspIdOrg2); + await contractWrapperOrg2.readAsset(assetKey, mspIdOrg1); // Org1 should be able to read the private data details of the asset. - await readPrivateAsset(contractWrapperOrg1, assetKey, mspIdOrg1,); + await contractWrapperOrg1.getAssetPrivateProperties(assetKey, mspIdOrg1); - // Org1 should be able to read the sale price of this asset - await readSalePrice(contractWrapperOrg1, assetKey, mspIdOrg1); + // Org1 should be able to read the sale price of this asset. + await contractWrapperOrg1.getAssetSalesPrice(assetKey, mspIdOrg1); - // Org2 should be able to see the price it has agreed - await readBidPrice(contractWrapperOrg2, assetKey, mspIdOrg2); + // Org2 should be able to see the price it has agreed. + await contractWrapperOrg2.getAssetBidPrice(assetKey, mspIdOrg2); - // Org2 user will try to transfer the asset to Org1 - // This will fail as the owner is Org1 - await transferAsset(contractWrapperOrg2, assetKey, mspIdOrg2, mspIdOrg2, 100); + // Org2 user will try to transfer the asset to Org1. + // This will fail as the owner is Org1. + await contractWrapperOrg2.transferAsset({ObjectType: 'asset_properties', Color: 'blue', Size: 35}, { AssetId: assetKey, Price: 100, TradeId: now}, [ mspIdOrg1, mspIdOrg2 ], mspIdOrg1, mspIdOrg2); - // Org1 will transfer the asset to Org2 - // This will now complete as the sell price and the bid price are the same - await transferAsset(contractWrapperOrg1, assetKey, mspIdOrg1, mspIdOrg2, 100); + // Org1 will transfer the asset to Org2. + // This will now complete as the sell price and the bid price are the same. + await contractWrapperOrg1.transferAsset({ObjectType: 'asset_properties', Color: 'blue', Size: 35}, { AssetId: assetKey, Price: 100, TradeId: now}, [ mspIdOrg1, mspIdOrg2 ], mspIdOrg1, mspIdOrg2); // Read the public details by org1. - await readAsset(contractWrapperOrg1, assetKey, mspIdOrg2, mspIdOrg1); + await contractWrapperOrg1.readAsset(assetKey, mspIdOrg2); // Read the public details by org2. - await readAsset(contractWrapperOrg2, assetKey, mspIdOrg2, mspIdOrg2); + await contractWrapperOrg2.readAsset(assetKey, mspIdOrg2); - // Org2 should be able to read the private data details of this asset - await readPrivateAssetAfterTransfer(contractWrapperOrg2, assetKey, mspIdOrg2); + // Org2 should be able to read the private data details of this asset. + await contractWrapperOrg2.getAssetPrivateProperties(assetKey, mspIdOrg2); - // Org1 should not be able to read the private data details of this asset,expected to fail - await readPrivateAssetAfterTransfer(contractWrapperOrg1, assetKey, mspIdOrg1); + // Org1 should not be able to read the private data details of this asset, expected to fail. + await contractWrapperOrg1.getAssetPrivateProperties(assetKey, mspIdOrg2); // This is an update to the public state and requires only the owner to endorse. - // Org2 wants to indicate that the items is no longer for sale - await changePublicDescriptionAfterTransfer(contractWrapperOrg2, assetKey, mspIdOrg2, `Asset ${assetKey} owned by ${mspIdOrg2} is NOT for sale`); + // Org2 wants to indicate that the items is no longer for sale. + await contractWrapperOrg2.changePublicDescription( {AssetId: assetKey, OwnerOrg: mspIdOrg2, PublicDescription: `Asset ${assetKey} owned by ${mspIdOrg2} is NOT for sale`}); - // Read the public details by org1. - await readAsset(contractWrapperOrg1, assetKey, mspIdOrg2, mspIdOrg1); + // Read the public details by org1. + await contractWrapperOrg1.readAsset(assetKey, mspIdOrg2); - // Read the public details by org2. - await readAsset(contractWrapperOrg2, assetKey, mspIdOrg2, mspIdOrg2); + // Read the public details by org2. + await contractWrapperOrg2.readAsset(assetKey, mspIdOrg2); } finally { gatewayOrg1.close(); @@ -179,179 +188,3 @@ main().catch(error => { console.error('******** FAILED to run the application:', error); process.exitCode = 1; }); - -async function createAsset(contract: ContractWrapper, org: string): Promise { - console.log(`${GREEN}--> Submit Transaction: CreateAsset, ${assetKey} as ${org} - endorsed by Org1${RESET}`); - - await contract.createAsset(org, assetKey, { objectType: 'asset_properties', assetId: assetKey, color: 'blue', size: 35, salt: randomBytes }); - - console.log(`*** Result: committed, asset ${assetKey} is owned by Org1`); -} - -async function readAsset(contract: ContractWrapper, assetKey: string, ownerOrg: string, org: string): Promise { - - console.log(`${GREEN}--> Evaluate Transactions: ReadAsset as ${org}, - ${assetKey} should be owned by ${ownerOrg}${RESET}`); - try { - const result = await contract.readAsset(assetKey); - if (result.ownerOrg === ownerOrg) { - console.log(`*** Result from ${org} - asset ${result.assetId} owned by ${result.ownerOrg} DESC:${result.publicDescription}`); - } else { - console.log(`${RED}*** Failed owner check from ${org} - asset ${result.assetId} owned by ${result.ownerOrg} DESC:${result.publicDescription}${RESET}`); - } - }catch (e) { - console.log(`${RED}*** Failed evaluateTransaction readAsset - ${e}${RESET}`); - } -} - -async function readPrivateAsset(contract: ContractWrapper, assetKey: string, org: string): Promise { - try{ - console.log(`${GREEN}--> Evaluate Transaction: GetAssetPrivateProperties, - ${assetKey} from organization ${org}${RESET}`); - if(org === mspIdOrg2){ - console.log(`${GREEN}* Expected to fail as ${org} is not the owner and does not have the private details${RESET}`); - } - const result = await contract.getAssetPrivateProperties(assetKey); - console.log('*** Result:', result); - } - catch(e){ - console.log(`${RED}*** Failed evaluateTransaction readPrivateAsset: ${e}${RESET}`); - } -} - -async function changePublicDescription(contract: ContractWrapper, assetKey: string, org: string, description: string): Promise { - try { - console.log(`${GREEN}--> Submit Transaction: ChangePublicDescription ${assetKey}, as ${org} - endorse by ${org}${RESET}`); - if (org === mspIdOrg2) { - console.log(`${GREEN}* Expected to fail as ${org} is not the owner${RESET}`); - } - await contract.changePublicDescription(assetKey, description); - console.log(`*** Result: committed, asset ${assetKey} is now for sale by ${org}`); - } catch (e) { - console.log(`${RED}*** Failed: ChangePublicDescription - ${e}${RESET}`); - } -} - -async function agreeToSell(contract: ContractWrapper, assetKey: string, org: string, price: number): Promise { - try { - console.log(`${GREEN}--> Submit Transaction: AgreeToSell, ${assetKey} as ${org} - endorsed by ${org}${RESET}`); - - await contract.agreeToSell({assetId:assetKey, price, tradeId:now.toString()}); - - console.log(`*** Result: committed, ${org} has agreed to sell asset ${assetKey} for ${price}`); - } catch (e) { - console.log(`${RED}*** Failed: AgreeToSell - ${e}${RESET}`); - } -} - -async function verifyAssetProperties(contract: ContractWrapper, assetKey: string, org: string): Promise { - try { - console.log(`${GREEN}--> Evalute: VerifyAssetProperties, ${assetKey} as ${org} - endorsed by ${org}${RESET}`); - - const result = await contract.verifyAssetProperties({objectType:'asset_properties', assetId:assetKey, color:'blue', size:35, salt:randomBytes}, org); - - if (result) { - console.log(`*** Success VerifyAssetProperties, private information about asset ${assetKey} has been verified by ${org}`); - } else { - console.log(`*** Failed: VerifyAssetProperties, private information about asset ${assetKey} has not been verified by ${org}`); - } - } catch (e) { - console.log(`${RED}*** Failed: VerifyAssetProperties - ${e}${RESET}`); - } -} - -async function agreeToBuy(contract: ContractWrapper, assetKey: string, org: string, price: number): Promise { - try { - console.log(`${GREEN}--> Submit Transaction: AgreeToBuy, ${assetKey} as ${org} - endorsed by ${org}${RESET}`); - - await contract.agreeToBuy( {assetId:assetKey, price, tradeId: now.toString()}); - - console.log(`*** Result: committed, ${org} has agreed to buy asset ${assetKey} for 100`); - } catch (e) { - console.log(`${RED}*** Failed: AgreeToBuy - ${e}${RESET}`); - } -} - -async function readSalePrice(contract: ContractWrapper, assetKey: string, org: string): Promise { - try { - console.log(`${GREEN}--> Evaluate Transaction: GetAssetSalesPrice, - ${assetKey} from organization ${org}${RESET}`); - if(org === mspIdOrg2){ - console.log(`${GREEN}* Expected to fail as ${org} has not set a sale price${RESET}`); - } - - const result = await contract.getAssetSalesPrice(assetKey); - - console.log('*** Result: GetAssetSalesPrice', result); - } catch (e) { - console.log(`${RED}*** Failed evaluateTransaction GetAssetSalesPrice: ${e}${RESET}`); - } -} - -async function readBidPrice(contract: ContractWrapper, assetKey: string, org: string): Promise { - try{ - console.log(`${GREEN}--> Evaluate Transaction: GetAssetBidPrice, - ${assetKey} from organization ${org}${RESET}`); - if(org === mspIdOrg1){ - console.log(`${GREEN}* Expected to fail as Org1 has not agreed to buy${RESET}`); - } - - const result = await contract.getAssetBidPrice(assetKey); - - console.log('*** Result: GetAssetBidPrice', result); - } catch (e) { - console.log(`${RED}*** Failed evaluateTransaction GetAssetBidPrice: ${e}${RESET}`); - } -} - -async function transferAsset(contract: ContractWrapper, assetKey: string, org: string, buyerOrgID: string, price: number): Promise { - try { - console.log(`${GREEN}--> Submit Transaction: TransferAsset, ${assetKey} as ${org} - endorsed by ${org}${RESET}`); - if(org === mspIdOrg2){ - console.log(`${GREEN}* Expected to fail as the owner is Org1${RESET}`); - }else if(price === 110){ - console.log(`${GREEN}* Expected to fail as sell price and the bid price are not the same${RESET}`); - } - - const assetProperties: AssetPropertiesJSON = - { objectType:'asset_properties', - assetId:assetKey, - color:'blue', - size:35, - salt:randomBytes - }; - const assetPrice: AssetPriceJSON = { assetId: assetKey, price, tradeId:now.toString()}; - await contract.transferAsset(buyerOrgID, assetProperties, assetPrice, [ mspIdOrg1, mspIdOrg2 ]); - - console.log(`${GREEN}*** Result: committed, ${org} has transfered the asset ${assetKey} to ${mspIdOrg2} ${RESET}`); - } catch (e) { - console.log(`${RED}*** Failed: TransferAsset - ${e}${RESET}`); - } -} - -async function readPrivateAssetAfterTransfer(contract: ContractWrapper, assetKey: string, org: string): Promise { - try{ - console.log(`${GREEN}--> Evaluate Transaction: GetAssetPrivateProperties, - ${assetKey} from organization ${org}${RESET}`); - if(org === mspIdOrg1) { - console.log(`${GREEN}* Expected to fail as ${org} is not the owner and does not have the private details${RESET}`); - } - - const result = await contract.getAssetPrivateProperties(assetKey); - - console.log('*** Result:', result); - } - catch(e){ - console.log(`${RED}*** Failed evaluateTransaction readPrivateAsset: ${e}${RESET}`); - } -} - -async function changePublicDescriptionAfterTransfer(contract: ContractWrapper, assetKey: string, org: string, description: string): Promise { - try { - console.log(`${GREEN}--> Submit Transaction: changePublicDescription ${assetKey}, as ${org} - endorse by ${org}${RESET}`); - if(org === mspIdOrg1) { - console.log(`${GREEN}* Expected to fail as ${org} is not the owner${RESET}`); - } - - await contract.changePublicDescription(assetKey, description); - - console.log(`*** Result: committed, asset ${assetKey} is now for sale by ${org}`); - } catch (e) { - console.log(`${RED}*** Failed: changePublicDescription - ${e}${RESET}`); - } -} diff --git a/asset-transfer-secured-agreement/application-gateway-typescript/src/contractWrapper.ts b/asset-transfer-secured-agreement/application-gateway-typescript/src/contractWrapper.ts index 657d1fcf..724eec6e 100644 --- a/asset-transfer-secured-agreement/application-gateway-typescript/src/contractWrapper.ts +++ b/asset-transfer-secured-agreement/application-gateway-typescript/src/contractWrapper.ts @@ -5,118 +5,260 @@ */ import { Contract } from '@hyperledger/fabric-gateway'; import { TextDecoder } from 'util'; -import { Asset, AssetJSON, AssetPrice, AssetPriceJSON, AssetProperties, AssetPropertiesJSON, parse } from './utils'; +import { Asset, AssetJSON, AssetPrice, AssetPriceJSON, AssetPrivateData, AssetProperties, AssetPropertiesJSON, GREEN, parse, RED, RESET } from './utils'; export class ContractWrapper { readonly #contract: Contract; + readonly #org: string; readonly #utf8Decoder = new TextDecoder(); + readonly #randomBytes: string; - public constructor(contract: Contract) { + public constructor(contract: Contract, org: string, randomBytes: string) { this.#contract = contract; + this.#org = org; + this.#randomBytes = randomBytes; } - public async createAsset(org: string, assetKey: string, assetProperties: AssetPropertiesJSON): Promise { - await this.#contract.submit('CreateAsset', { - arguments: [assetKey, `Asset ${assetKey} owned by ${org} is not for sale`], - transientData: { asset_properties: JSON.stringify(assetProperties)}, - }); + public async createAsset(asset: Asset, privateData: AssetPrivateData): Promise { + console.log(`${GREEN}--> Submit Transaction: CreateAsset, ${asset.AssetId} as ${asset.OwnerOrg} - endorsed by Org1${RESET}`); + try { + const assetPropertiesJSON: AssetPropertiesJSON = Object.assign({}, {objectType: 'asset_properties', + assetID: asset.AssetId, + color: privateData.Color, + size: privateData.Size, + salt: this.#randomBytes }); + + await this.#contract.submit('CreateAsset', { + arguments: [asset.AssetId, asset.PublicDescription], + transientData: { asset_properties: JSON.stringify(assetPropertiesJSON)}, + }); + + console.log(`*** Result: committed, asset ${asset.AssetId} is owned by Org1`); + }catch (e) { + console.log(`${RED}*** Failed: createAsset - ${e}${RESET}`); + } } - public async readAsset( assetKey: string): Promise { - const resultBytes = await this.#contract.evaluateTransaction('ReadAsset', assetKey); - const result = this.#utf8Decoder.decode(resultBytes); - if (result.length !== 0) { - const json = parse(result); - return { - assetId: json.assetId, - ownerOrg: json.ownerOrg, - publicDescription: json.publicDescription + public async readAsset( assetKey: string, ownerOrg: string): Promise { + console.log(`${GREEN}--> Evaluate Transactions: ReadAsset as ${this.#org}, - ${assetKey} should be owned by ${ownerOrg}${RESET}`); + try { + + const resultBytes = await this.#contract.evaluateTransaction('ReadAsset', assetKey); + + const result = this.#utf8Decoder.decode(resultBytes); + if (result.length !== 0) { + const json = parse(result); + if (json.ownerOrg === ownerOrg) { + console.log(`*** Result from ${this.#org} - asset ${json.assetID} owned by ${json.ownerOrg} DESC: ${json.publicDescription}`); + } else { + console.log(`${RED}*** Failed owner check from ${this.#org} - asset ${json.assetID} owned by ${json.ownerOrg} DESC:${json.publicDescription}${RESET}`); + } + } else { + throw new Error('No Asset Found'); } - } else { - throw new Error('No Asset Found'); + }catch (e) { + console.log(`${RED}*** Failed evaluateTransaction readAsset - ${e}${RESET}`); } } - public async getAssetPrivateProperties( assetKey: string ): Promise { - const resultBytes = await this.#contract.evaluateTransaction('GetAssetPrivateProperties', assetKey); - const result = this.#utf8Decoder.decode(resultBytes); - const json = parse(result); - return { - assetId: json.assetId, - color: json.color, - size: json.size, - } - - } - - public async changePublicDescription(assetKey: string, description: string): Promise { - await this.#contract.submit('ChangePublicDescription', { - arguments:[assetKey, description], - }); - } - - public async agreeToSell(asset_price: AssetPriceJSON): Promise { - await this.#contract.submit('AgreeToSell', { - arguments:[asset_price.assetId], - transientData: {asset_price: JSON.stringify(asset_price)} - }); - } - - public async verifyAssetProperties(assetProperties: AssetPropertiesJSON, org: string): Promise { - const resultBytes = await this.#contract.evaluate('VerifyAssetProperties', { - arguments:[assetProperties.assetId], - transientData: {asset_properties: JSON.stringify(assetProperties)}, - }); - const result = this.#utf8Decoder.decode(resultBytes); - if (result.length !== 0) { - const json = parse(result); - return { - assetId: json.assetId, - color: json.color, - size: json.size + public async getAssetPrivateProperties(assetKey: string, ownerOrg: string): Promise { + try{ + console.log(`${GREEN}--> Evaluate Transaction: GetAssetPrivateProperties, - ${assetKey} from organization ${this.#org}${RESET}`); + if(this.#org !== ownerOrg) { + console.log(`${GREEN}* Expected to fail as ${this.#org} is not the owner and does not have the private details${RESET}`); } - } else { - throw new Error(`Private information about asset ${assetProperties.assetId} has not been verified by ${org}`); + + const resultBytes = await this.#contract.evaluateTransaction('GetAssetPrivateProperties', assetKey); + + const resultString = this.#utf8Decoder.decode(resultBytes); + const json = parse(resultString); + const result: AssetProperties = { + AssetId: json.assetID, + Color: json.color, + Size: json.size, + }; + console.log('*** Result:', result); + } + catch(e){ + console.log(`${RED}*** Failed evaluateTransaction readPrivateAsset: ${e}${RESET}`); } } - public async agreeToBuy(asset_price: AssetPriceJSON): Promise { - await this.#contract.submit('AgreeToBuy', { - arguments:[asset_price.assetId], - transientData: {asset_price: JSON.stringify(asset_price)} - }); + public async changePublicDescription(asset: Asset): Promise { + try { + console.log(`${GREEN}--> Submit Transaction: ChangePublicDescription ${asset.AssetId}, as ${this.#org} - endorse by ${this.#org} ${RESET}`); + if (asset.OwnerOrg !== this.#org) { + console.log(`${GREEN}* Expected to fail as ${this.#org} is not the owner${RESET}`); + } + + await this.#contract.submit('ChangePublicDescription', { + arguments:[asset.AssetId, asset.PublicDescription], + }); + + console.log(`*** Result: committed, Desc: ${asset.PublicDescription}`); + } catch (e) { + console.log(`${RED}*** Failed: ChangePublicDescription - ${e}${RESET}`); + } + } - public async getAssetSalesPrice(assetKey: string): Promise { - const resultBytes = await this.#contract.evaluateTransaction('GetAssetSalesPrice', assetKey); - const result = this.#utf8Decoder.decode(resultBytes); - const json = parse(result); - return { - assetId: json.assetId, - ownerOrg: json.ownerOrg, - publicDescription: json.publicDescription + public async agreeToSell(assetPrice: AssetPrice): Promise { + try { + console.log(`${GREEN}--> Submit Transaction: AgreeToSell, ${assetPrice.AssetId} as ${this.#org} - endorsed by ${this.#org}${RESET}`); + const assetPriceJSON: AssetPriceJSON = { + assetID:assetPrice.AssetId, + price:assetPrice.Price, + tradeID:assetPrice.TradeId + }; + + await this.#contract.submit('AgreeToSell', { + arguments:[assetPrice.AssetId], + transientData: {asset_price: JSON.stringify(assetPriceJSON)} + }); + + console.log(`*** Result: committed, ${this.#org} has agreed to sell asset ${assetPrice.AssetId} for ${assetPrice.Price}`); + } catch (e) { + console.log(`${RED}*** Failed: AgreeToSell - ${e}${RESET}`); } } - public async getAssetBidPrice( assetKey: string): Promise { - const resultBytes = await this.#contract.evaluateTransaction('GetAssetBidPrice', assetKey); - const result = this.#utf8Decoder.decode(resultBytes); - const json = parse(result); - return { - assetId: json.assetId, - price: json.price, - tradeId: json.tradeId, + public async verifyAssetProperties(assetProperties: AssetProperties): Promise { + try { + console.log(`${GREEN}--> Evalute: VerifyAssetProperties, ${assetProperties.AssetId} as ${this.#org} - endorsed by ${this.#org}${RESET}`); + const assetPropertiesJSON: AssetPropertiesJSON = Object.assign({}, {objectType: 'asset_properties', + assetID: assetProperties.AssetId, + color: assetProperties.Color, + size: assetProperties.Size, + salt: this.#randomBytes }); + + const resultBytes = await this.#contract.evaluate('VerifyAssetProperties', { + arguments:[assetPropertiesJSON.assetID], + transientData: {asset_properties: JSON.stringify(assetPropertiesJSON)}, + }); + + const resultString = this.#utf8Decoder.decode(resultBytes); + if (resultString.length !== 0) { + const json = parse(resultString); + const result: AssetProperties = { + AssetId: json.assetID, + Color: json.color, + Size: json.size + }; + if (result) { + console.log(`*** Success VerifyAssetProperties, private information about asset ${assetProperties.AssetId} has been verified by ${this.#org}`); + } else { + console.log(`*** Failed: VerifyAssetProperties, private information about asset ${assetProperties.AssetId} has not been verified by ${this.#org}`); + } + + } else { + throw new Error(`Private information about asset ${assetProperties.AssetId} has not been verified by ${this.#org}`); + } + + } catch (e) { + console.log(`${RED}*** Failed: VerifyAssetProperties - ${e}${RESET}`); + } + + + } + + public async agreeToBuy(assetPrice: AssetPrice, ): Promise { + try { + console.log(`${GREEN}--> Submit Transaction: AgreeToBuy, ${assetPrice.AssetId} as ${this.#org} - endorsed by ${this.#org}${RESET}`); + const assetPriceJSON: AssetPriceJSON = { + assetID: assetPrice.AssetId, + price: assetPrice.Price, + tradeID: assetPrice.TradeId + }; + + await this.#contract.submit('AgreeToBuy', { + arguments:[assetPrice.AssetId], + transientData: {asset_price: JSON.stringify(assetPriceJSON)} + }); + + console.log(`*** Result: committed, ${this.#org} has agreed to buy asset ${assetPrice.AssetId} for 100`); + } catch (e) { + console.log(`${RED}*** Failed: AgreeToBuy - ${e}${RESET}`); + } + + } + + public async getAssetSalesPrice(assetKey: string, ownerOrg: string): Promise { + try { + console.log(`${GREEN}--> Evaluate Transaction: GetAssetSalesPrice, - ${assetKey} from organization ${this.#org}${RESET}`); + if(this.#org !== ownerOrg) { + console.log(`${GREEN}* Expected to fail as ${this.#org} has not set a sale price${RESET}`); + } + + const resultBytes = await this.#contract.evaluateTransaction('GetAssetSalesPrice', assetKey); + + const resultString = this.#utf8Decoder.decode(resultBytes); + const json = parse(resultString); + + const result: AssetPrice = { + AssetId: json.assetID, + Price: json.price, + TradeId: json.tradeID + }; + + console.log('*** Result: GetAssetSalesPrice', result); + } catch (e) { + console.log(`${RED}*** Failed evaluateTransaction GetAssetSalesPrice: ${e}${RESET}`); } } - public async transferAsset(buyerOrgID: string, asset_properties: AssetPropertiesJSON, asset_price: AssetPriceJSON, endorsingOrganizations: string[]): Promise { - await this.#contract.submit('TransferAsset', { - arguments:[asset_properties.assetId, buyerOrgID], - transientData: { - asset_properties: JSON.stringify(asset_properties), - asset_price: JSON.stringify(asset_price)}, - endorsingOrganizations:endorsingOrganizations - }); + public async getAssetBidPrice(assetKey: string, buyerOrgID: string): Promise { + try{ + console.log(`${GREEN}--> Evaluate Transaction: GetAssetBidPrice, - ${assetKey} from organization ${this.#org}${RESET}`); + if(this.#org !== buyerOrgID){ + console.log(`${GREEN}* Expected to fail as ${this.#org} has not agreed to buy${RESET}`); + } + + const resultBytes = await this.#contract.evaluateTransaction('GetAssetBidPrice', assetKey); + + const resultString = this.#utf8Decoder.decode(resultBytes); + const json = parse(resultString); + const result: AssetPrice = { + AssetId: json.assetID, + Price: json.price, + TradeId: json.tradeID, + }; + + console.log('*** Result: GetAssetBidPrice', result); + } catch (e) { + console.log(`${RED}*** Failed evaluateTransaction GetAssetBidPrice: ${e}${RESET}`); + } + } + + public async transferAsset( privateData: AssetPrivateData, assetPrice: AssetPrice, endorsingOrganizations: string[], ownerOrgID: string, buyerOrgID: string): Promise { + try { + console.log(`${GREEN}--> Submit Transaction: TransferAsset, ${assetPrice.AssetId} as ${this.#org } - endorsed by ${this.#org}${RESET}`); + + if (this.#org !== ownerOrgID) { + console.log(`${GREEN}* Expected to fail as the owner is ${ownerOrgID}${RESET}`); + } else if (assetPrice.Price === 110) { + console.log(`${GREEN}* Expected to fail as sell price and the bid price are not the same${RESET}`); + } + + const assetPropertiesJSON: AssetPropertiesJSON = Object.assign({}, {objectType: 'asset_properties', + assetID: assetPrice.AssetId, + color: privateData.Color, + size: privateData.Size, + salt: this.#randomBytes }); + + const assetPriceJSON: AssetPriceJSON = { assetID: assetPrice.AssetId, price:assetPrice.Price, tradeID:assetPrice.TradeId}; + + await this.#contract.submit('TransferAsset', { + arguments:[assetPropertiesJSON.assetID, buyerOrgID], + transientData: { + asset_properties: JSON.stringify(assetPropertiesJSON), + asset_price: JSON.stringify(assetPriceJSON)}, + endorsingOrganizations:endorsingOrganizations + }); + + console.log(`${GREEN}*** Result: committed, ${this.#org} has transfered the asset ${assetPrice.AssetId} to ${buyerOrgID} ${RESET}`); + } catch (e) { + console.log(`${RED}*** Failed: TransferAsset - ${e}${RESET}`); + } } } \ No newline at end of file diff --git a/asset-transfer-secured-agreement/application-gateway-typescript/src/utils.ts b/asset-transfer-secured-agreement/application-gateway-typescript/src/utils.ts index 41722624..5cc9c419 100644 --- a/asset-transfer-secured-agreement/application-gateway-typescript/src/utils.ts +++ b/asset-transfer-secured-agreement/application-gateway-typescript/src/utils.ts @@ -3,6 +3,7 @@ * * SPDX-License-Identifier: Apache-2.0 */ +import crpto from 'crypto'; export const RED = '\x1b[31m\n'; export const GREEN = '\x1b[32m\n'; @@ -10,43 +11,50 @@ export const RESET = '\x1b[0m'; export interface AssetJSON { objectType: string; - assetId: string; + assetID: string; ownerOrg: string; publicDescription: string; } export interface AssetPropertiesJSON { objectType: string; - assetId: string; + assetID: string; color: string; size: number; salt: string; } export interface AssetPriceJSON { - assetId: string; + assetID: string; price: number; - tradeId: string; + tradeID: string; } +export interface AssetPrivateData { + ObjectType: string; + Color: string; + Size: number; +} export interface Asset { - assetId: string; - ownerOrg: string; - publicDescription: string; + AssetId: string; + OwnerOrg: string; + PublicDescription: string; } export interface AssetProperties { - assetId: string; - color: string; - size: number; + AssetId: string; + Color: string; + Size: number; } export interface AssetPrice { - assetId: string; - price: number; - tradeId: string; + AssetId: string; + Price: number; + TradeId: string; } export function parse(data: string): T { return JSON.parse(data); -} \ No newline at end of file +} + +export const randomBytes = crpto.randomBytes(256).toString('hex');