Skip to content

Commit

Permalink
modify chaincode and add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
izzuddinafif committed Nov 28, 2024
1 parent b4fe53c commit 0ae3333
Show file tree
Hide file tree
Showing 5 changed files with 887 additions and 1,153 deletions.
191 changes: 158 additions & 33 deletions chaincode/zakat/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,61 +3,186 @@
## Overview
This Hyperledger Fabric chaincode manages Zakat transactions for YDSF Malang and YDSF Jatim organizations. It provides a transparent and immutable record of Zakat collection and distribution.

## Data Model

### Zakat Transaction
```go
type Zakat struct {
ID string // Format: ZKT-{ORG}-{YYYY}{MM}-{COUNTER}
Muzakki string // Zakat donor's name
Amount float64 // Amount in IDR
Type string // "fitrah" or "maal"
Status string // "collected" or "distributed"
Organization string // Collecting organization
Timestamp string // ISO 8601 format
Mustahik string // Recipient's name (if distributed)
Distribution float64 // Distributed amount
DistributedAt string // Distribution timestamp (ISO 8601)
}
```

## ID Format
The Zakat ID follows a specific format to ensure uniqueness and traceability:
- Format: `ZKT-{ORG}-{YYYY}{MM}-{COUNTER}`
- Example: `ZKT-YDSF-MLG-202311-0001`
- Components:
- `ZKT`: Fixed prefix for Zakat transactions
- `ORG`: Organization identifier (e.g., YDSF-MLG, YDSF-JTM)
- `YYYY`: 4-digit year
- `MM`: 2-digit month
- `COUNTER`: 4-digit sequential counter

## Chaincode Functions

### `InitLedger()`
- **Description**: Initializes the ledger with a sample Zakat transaction
- **Validation**:
- Checks if initial transaction already exists
- Validates all fields using standard validation functions
- Uses current timestamp in ISO 8601 format
- **Error Handling**:
- Returns descriptive errors for validation failures
- Handles GetState and PutState errors
- **Returns**: Error if initialization fails

### `AddZakat(zakatId, donorName, amount, zakatType, organization, date)`
- **Description**: Record a new Zakat donation
- **Description**: Records a new Zakat donation
- **Parameters**:
- `zakatId`: Unique identifier for the Zakat transaction
- `zakatId`: Unique identifier (must follow ID format)
- `donorName`: Name of the Zakat donor
- `amount`: Monetary amount of Zakat
- `zakatType`: Type of Zakat (e.g., maal, fitrah)
- `organization`: Receiving organization
- `date`: Date of donation
- `amount`: Monetary amount (must be positive)
- `zakatType`: Type of Zakat ("maal" or "fitrah")
- `organization`: Receiving organization (must be authorized)
- `date`: Date of donation (ISO 8601 format)
- **Validation**:
- Validates ID format
- Checks for existing transactions
- Validates amount and organization
- Verifies timestamp format
- **Returns**: Error if validation fails or transaction exists

### `QueryZakat(zakatId)`
- **Description**: Retrieve details of a specific Zakat transaction
- **Description**: Retrieves details of a specific Zakat transaction
- **Parameters**:
- `zakatId`: Unique identifier for the Zakat transaction
- **Returns**: Complete transaction details
- **Returns**: Complete transaction details or error if not found

### `GetAllZakat()`
- **Description**: Retrieves all Zakat transactions from the ledger
- **Returns**: Array of all Zakat transactions
- **Error Handling**: Returns error if retrieval fails

### `DistributeZakat(zakatId, recipientName, amount, date)`
- **Description**: Record Zakat distribution to a beneficiary
### `DistributeZakat(zakatId, mustahik, amount, timestamp)`
- **Description**: Records the distribution of a Zakat transaction
- **Parameters**:
- `zakatId`: Identifier of the original Zakat donation
- `recipientName`: Name of the Zakat recipient
- `zakatId`: Unique identifier of the Zakat to distribute
- `mustahik`: Name of the recipient
- `amount`: Amount distributed
- `date`: Date of distribution
- `timestamp`: Distribution timestamp (ISO 8601)
- **Validation**:
- Verifies Zakat exists and is not distributed
- Validates distribution amount
- Checks timestamp format
- **Returns**: Error if validation fails or Zakat not found

### `GetAllZakat()`
- **Description**: Retrieve all Zakat transactions
- **Returns**: List of all Zakat transactions
### `ZakatExists(zakatId)`
- **Description**: Checks if a Zakat transaction exists
- **Parameters**:
- `zakatId`: Unique identifier to check
- **Returns**: Boolean indicating existence and any error

## Validation Rules

### ID Validation
- Must follow the specified format
- Organization part must match authorized organizations
- Year and month must be valid

### Amount Validation
- Must be positive number
- Must be greater than zero

### Organization Validation
- Must be either "YDSF Malang" or "YDSF Jatim"

### Timestamp Validation
- Must be in ISO 8601 format
- Must be parseable as a valid date/time

### Zakat Type Validation
- Must be either "maal" or "fitrah"

## Testing
The chaincode includes comprehensive test coverage:
- Unit tests for all functions
- Error case testing
- Mock implementations for chaincode interfaces
- Validation testing
- Edge case coverage

## Error Handling
All functions include proper error handling:
- Descriptive error messages
- Proper error propagation
- Transaction rollback on errors
- Validation error details

## Dependencies
- Hyperledger Fabric Contract API
- Hyperledger Fabric Chaincode Go
- Google Protocol Buffers
- Testify (for testing)

## Development
- Go version: 1.20+
- Uses standard Go modules
- Follows Go best practices
- Implements Hyperledger Fabric chaincode interfaces

## Security Considerations
- Input validation for all parameters
- Proper error handling
- No sensitive data exposure
- Transaction integrity checks
- Organization authorization checks

## Future Improvements
- Additional validation rules
- Enhanced error reporting
- Performance optimizations
- Additional query functions
- Batch processing support

## Transaction Flow
1. Donor contributes Zakat via `AddZakat()`
2. Organization tracks donation
3. Beneficiary receives Zakat via `DistributeZakat()`
4. Full transaction history maintained

## Security and Compliance
- Multi-organization validation
- Immutable transaction records
- Transparent audit trail

## Technical Details
- **Language**: Go
- **Hyperledger Fabric Version**: 2.4.0
- **Consensus**: Raft (Crash Fault Tolerant)
- **State Database**: LevelDB

## Development
- Developed for YDSF Malang and YDSF Jatim
- Part of Islamic charitable giving blockchain solution

## Usage Example
```bash
# Add Zakat donation
peer chaincode invoke -C zakat-channel -n zakat -c '{"function":"AddZakat","Args":["zakat1", "Ahmad", "5000000", "maal", "YDSFMalang", "2024-01-15"]}'
# Format: ZKT-YDSF-{MLG|JTM}-YYYYMM-NNNN
peer chaincode invoke -C zakat-channel -n zakat -c '{"function":"AddZakat","Args":["ZKT-YDSF-MLG-202401-0001", "Ahmad", "5000000", "maal", "YDSF Malang", "2024-01-15T00:00:00Z"]}'

# Distribute Zakat
peer chaincode invoke -C zakat-channel -n zakat -c '{"function":"DistributeZakat","Args":["zakat1", "Muhammad", "1000000", "2024-01-20"]}'
peer chaincode invoke -C zakat-channel -n zakat -c '{"function":"DistributeZakat","Args":["ZKT-YDSF-MLG-202401-0001", "Muhammad", "1000000", "2024-01-20T00:00:00Z"]}'

# Query Zakat
peer chaincode query -C zakat-channel -n zakat -c '{"function":"QueryZakat","Args":["ZKT-YDSF-MLG-202401-0001"]}'

# Get All Zakat
peer chaincode query -C zakat-channel -n zakat -c '{"function":"GetAllZakat","Args":[]}'

```

Note:
- Zakat ID format: `ZKT-YDSF-{MLG|JTM}-YYYYMM-NNNN`
- MLG: YDSF Malang
- JTM: YDSF Jatim
- YYYYMM: Year and month
- NNNN: Sequential number
- Timestamp format: ISO 8601 (e.g., `2024-01-15T00:00:00Z`)
- Amount should be in IDR
- Zakat type should be either "fitrah" or "maal"
- Organization should be either "YDSF Malang" or "YDSF Jatim"
15 changes: 11 additions & 4 deletions chaincode/zakat/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,16 @@ module github.com/izzuddinafif/fabric-zakat/chaincode/zakat

go 1.20

require github.com/hyperledger/fabric-contract-api-go v1.2.1
require (
github.com/hyperledger/fabric-chaincode-go v0.0.0-20230228194215-b84622ba6a7a
github.com/hyperledger/fabric-contract-api-go v1.2.1
github.com/hyperledger/fabric-protos-go v0.3.0
github.com/stretchr/testify v1.10.0
google.golang.org/protobuf v1.28.1
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/jsonreference v0.20.0 // indirect
github.com/go-openapi/spec v0.20.8 // indirect
Expand All @@ -13,12 +20,12 @@ require (
github.com/gobuffalo/packd v1.0.1 // indirect
github.com/gobuffalo/packr v1.30.1 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/hyperledger/fabric-chaincode-go v0.0.0-20230228194215-b84622ba6a7a // indirect
github.com/hyperledger/fabric-protos-go v0.3.0 // indirect
github.com/joho/godotenv v1.4.0 // 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.8.1 // 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
Expand All @@ -27,6 +34,6 @@ require (
golang.org/x/text v0.7.0 // indirect
google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect
google.golang.org/grpc v1.53.0 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
Loading

0 comments on commit 0ae3333

Please sign in to comment.