This repository has been archived by the owner on Dec 15, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 25
/
Copy pathcontract.ts
103 lines (85 loc) · 3.13 KB
/
contract.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
/*
* Copyright IBM Corp. All Rights Reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
import { CommitError, Contract, StatusCode } from '@hyperledger/fabric-gateway';
import { TextDecoder } from 'util';
const RETRIES = 2;
const utf8Decoder = new TextDecoder();
export interface Asset {
ID: string;
Color: string;
Size: number;
Owner: string;
AppraisedValue: number;
}
export type AssetCreate = Omit<Asset, 'Owner'> & Partial<Asset>;
export type AssetUpdate = Pick<Asset, 'ID'> & Partial<Omit<Asset, 'Owner'>>;
/**
* AssetTransfer presents the smart contract in a form appropriate to the business application. Internally it uses the
* Fabric Gateway client API to invoke transaction functions, and deals with the translation between the business
* application and API representation of parameters and return values.
*/
export class AssetTransfer {
readonly #contract: Contract;
constructor(contract: Contract) {
this.#contract = contract;
}
async createAsset(asset: AssetCreate): Promise<void> {
await this.#contract.submit('CreateAsset', {
arguments: [JSON.stringify(asset)],
});
}
async getAllAssets(): Promise<Asset[]> {
const result = await this.#contract.evaluate('GetAllAssets');
if (result.length === 0) {
return [];
}
return JSON.parse(utf8Decoder.decode(result)) as Asset[];
}
async readAsset(id: string): Promise<Asset> {
const result = await this.#contract.evaluate('ReadAsset', {
arguments: [id],
});
return JSON.parse(utf8Decoder.decode(result)) as Asset;
}
async updateAsset(asset: AssetUpdate): Promise<void> {
await submitWithRetry(() => this.#contract.submit('UpdateAsset', {
arguments: [JSON.stringify(asset)],
}));
}
async deleteAsset(id: string): Promise<void> {
await submitWithRetry(() => this.#contract.submit('DeleteAsset', {
arguments: [id],
}));
}
async assetExists(id: string): Promise<boolean> {
const result = await this.#contract.evaluate('AssetExists', {
arguments: [id],
});
return utf8Decoder.decode(result).toLowerCase() === 'true';
}
async transferAsset(id: string, newOwner: string, newOwnerOrg: string): Promise<void> {
// TODO: Implement me!
// Submit a 'TransferAsset' transaction, which requires [id, newOwner, newOwnerOrg] arguments.
}
}
async function submitWithRetry<T>(submit: () => Promise<T>): Promise<T> {
let lastError: unknown | undefined;
for (let retryCount = 0; retryCount < RETRIES; retryCount++) {
try {
return await submit();
} catch (err: unknown) {
lastError = err;
if (err instanceof CommitError) {
// Transaction failed validation and did not update the ledger. Handle specific transaction validation codes.
if (err.code === StatusCode.MVCC_READ_CONFLICT) {
continue; // Retry
}
}
break; // Failure -- don't retry
}
}
throw lastError;
}