koperasi/services/smartcontract/contracts/ProjectToken.sol
2025-08-08 14:12:40 +07:00

798 lines
24 KiB
Solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
contract ProjectToken is ERC20 {
using Counters for Counters.Counter;
using Strings for uint256;
struct TokenDetail {
string tokenId;
string idProjek;
string idUser;
int256 nilai; // Changed to int256
}
struct Transaksi {
string idUser;
string namaUser;
string idProjek;
string judulProjek;
string ownerProjek;
int256 jumlahToken; // Changed to int256
int256 totalNominal; // Changed to int256
}
struct ChartToken {
string chartTokenId;
string idUser;
string idProjek;
int256 nominal; // Changed to int256
uint256 createdAt;
}
struct HistoryToken {
string historyTokenId;
string chartTokenId;
int256 totalNilai; // Changed to int256
uint256 createdAt;
}
struct Agreement {
string idProjek;
string idUser;
string namaProyek;
string namaPetugas;
string alamatPetugas;
string namaPemilikProyek;
string nik;
string noHp;
string alamat;
string signature;
string tandaTangan;
int256 nominalDisetujui; // Changed to int256
uint256 createdAt;
}
struct DividenProfit {
string idProjek;
int256 pelaksana; // Changed to int256
int256 pemilik; // Changed to int256
int256 koperasi; // Changed to int256
int256 pendana; // Changed to int256
}
mapping(uint256 => Agreement) public agreements;
uint256 public agreementCount;
event AgreementCreated(
string idProjek,
string idUser,
string namaProyek,
string namaPetugas,
string alamatPetugas,
string namaPemilikProyek,
string nik,
string noHp,
string alamat,
string signature,
string tandaTangan,
int256 nominalDisetujui,
uint256 createdAt
);
mapping(string => TokenDetail) public tokenDetails;
mapping(string => ChartToken) public chartTokens;
mapping(string => HistoryToken) public historyTokens;
mapping(string => DividenProfit) public dividenProfit;
Counters.Counter private tokenIdCounter;
Counters.Counter private chartTokenIdCounter;
Counters.Counter private historyTokenIdCounter;
string[] public allTokenIds;
event TokenCreated(
string indexed tokenId,
string idProjek,
string idUser,
int256 nilai
);
event TokenUserUpdated(string indexed tokenId, string newIdUser);
event ChartTokenCreated(
string indexed chartTokenId,
string idUser,
string idProjek,
int256 nominal,
uint256 createdAt
);
event HistoryTokenCreated(
string indexed historyTokenId,
string chartTokenId,
int256 totalNilai,
uint256 createdAt
);
event TokenNominalReset(string indexed tokenId);
event DividenProfitAdded(
string idProjek,
int256 pelaksana,
int256 pemilik,
int256 koperasi,
int256 pendana
);
event DividenProfitUpdated(
string idProjek,
int256 pelaksana,
int256 pemilik,
int256 koperasi,
int256 pendana
);
constructor() ERC20("ProjectToken", "PTKN") {}
Transaksi[] public transaksiList;
function generateUniqueId() private returns (string memory) {
tokenIdCounter.increment();
uint256 counter = tokenIdCounter.current();
return
string(
abi.encodePacked(
"TKN-",
block.timestamp.toString(),
"-",
counter.toString()
)
);
}
function createToken(
string memory idProjek,
string memory idUser,
int256 nilai
) public {
string memory tokenId = generateUniqueId();
_mint(msg.sender, uint256(nilai >= 0 ? nilai : -nilai));
tokenDetails[tokenId] = TokenDetail(tokenId, idProjek, idUser, nilai);
allTokenIds.push(tokenId);
emit TokenCreated(tokenId, idProjek, idUser, nilai);
}
function updateTokenUser(
string memory tokenId,
string memory newIdUser
) public {
require(
bytes(tokenDetails[tokenId].tokenId).length > 0,
"Project Token not found"
);
tokenDetails[tokenId].idUser = newIdUser;
emit TokenUserUpdated(tokenId, newIdUser);
}
function getAllTokens() public view returns (TokenDetail[] memory) {
TokenDetail[] memory tokens = new TokenDetail[](allTokenIds.length);
for (uint256 i = 0; i < allTokenIds.length; i++) {
tokens[i] = tokenDetails[allTokenIds[i]];
}
return tokens;
}
function getTokenById(
string memory tokenId
) public view returns (TokenDetail memory) {
require(
bytes(tokenDetails[tokenId].tokenId).length > 0,
"Project Token not found"
);
return tokenDetails[tokenId];
}
function getTokenByProjectId(
string memory idProjek
) public view returns (TokenDetail[] memory) {
uint256 count = 0;
for (uint256 i = 0; i < allTokenIds.length; i++) {
if (
keccak256(bytes(tokenDetails[allTokenIds[i]].idProjek)) ==
keccak256(bytes(idProjek))
) {
count++;
}
}
TokenDetail[] memory projekTokens = new TokenDetail[](count);
uint256 index = 0;
for (uint256 i = 0; i < allTokenIds.length; i++) {
if (
keccak256(bytes(tokenDetails[allTokenIds[i]].idProjek)) ==
keccak256(bytes(idProjek))
) {
projekTokens[index] = tokenDetails[allTokenIds[i]];
index++;
}
}
return projekTokens;
}
function getTokenByUserAndProject(
string memory idUser,
string memory idProjek
) public view returns (TokenDetail[] memory) {
uint256 count = 0;
for (uint256 i = 0; i < allTokenIds.length; i++) {
if (
keccak256(bytes(tokenDetails[allTokenIds[i]].idUser)) ==
keccak256(bytes(idUser)) &&
keccak256(bytes(tokenDetails[allTokenIds[i]].idProjek)) ==
keccak256(bytes(idProjek))
) {
count++;
}
}
TokenDetail[] memory filteredTokens = new TokenDetail[](count);
uint256 index = 0;
for (uint256 i = 0; i < allTokenIds.length; i++) {
if (
keccak256(bytes(tokenDetails[allTokenIds[i]].idUser)) ==
keccak256(bytes(idUser)) &&
keccak256(bytes(tokenDetails[allTokenIds[i]].idProjek)) ==
keccak256(bytes(idProjek))
) {
filteredTokens[index] = tokenDetails[allTokenIds[i]];
index++;
}
}
return filteredTokens;
}
function getTotalTokens() public view returns (uint256) {
return allTokenIds.length;
}
function resetTokenNominal(string memory tokenId) public {
require(
bytes(tokenDetails[tokenId].tokenId).length > 0,
"Project Token not found"
);
int256 currentValue = tokenDetails[tokenId].nilai;
tokenDetails[tokenId].nilai = 0;
_burn(msg.sender, uint256(currentValue >= 0 ? currentValue : -currentValue));
emit TokenNominalReset(tokenId);
}
function addTransaction(
string memory idUser,
string memory namaUser,
string memory idProjek,
string memory judulProjek,
string memory ownerProjek,
int256 jumlahToken,
int256 totalNominal
) public {
transaksiList.push(
Transaksi({
idUser: idUser,
namaUser: namaUser,
idProjek: idProjek,
judulProjek: judulProjek,
ownerProjek: ownerProjek,
jumlahToken: jumlahToken,
totalNominal: totalNominal
})
);
}
function getAllTransaction() public view returns (Transaksi[] memory) {
return transaksiList;
}
function getTransactionByUserId(
string memory idUser
) public view returns (Transaksi[] memory) {
uint256 count = 0;
for (uint256 i = 0; i < transaksiList.length; i++) {
if (
keccak256(bytes(transaksiList[i].idUser)) ==
keccak256(bytes(idUser))
) {
count++;
}
}
Transaksi[] memory userTransactions = new Transaksi[](count);
uint256 index = 0;
for (uint256 i = 0; i < transaksiList.length; i++) {
if (
keccak256(bytes(transaksiList[i].idUser)) ==
keccak256(bytes(idUser))
) {
userTransactions[index] = transaksiList[i];
index++;
}
}
return userTransactions;
}
function getTransactionByProjectId(
string memory idProjek
) public view returns (Transaksi[] memory) {
uint256 count = 0;
for (uint256 i = 0; i < transaksiList.length; i++) {
if (
keccak256(bytes(transaksiList[i].idProjek)) ==
keccak256(bytes(idProjek))
) {
count++;
}
}
Transaksi[] memory projectTransactions = new Transaksi[](count);
uint256 index = 0;
for (uint256 i = 0; i < transaksiList.length; i++) {
if (
keccak256(bytes(transaksiList[i].idProjek)) ==
keccak256(bytes(idProjek))
) {
projectTransactions[index] = transaksiList[i];
index++;
}
}
return projectTransactions;
}
function createAgreementLetter(
string memory _idProjek,
string memory _idUser,
string memory _namaProyek,
string memory _namaPetugas,
string memory _alamatPetugas,
string memory _namaPemilikProyek,
string memory _nik,
string memory _noHp,
string memory _alamat,
string memory _signature,
string memory _tandaTangan,
int256 _nominalDisetujui
) public {
agreementCount++;
agreements[agreementCount] = Agreement({
idProjek: _idProjek,
idUser: _idUser,
namaProyek: _namaProyek,
namaPetugas: _namaPetugas,
alamatPetugas: _alamatPetugas,
namaPemilikProyek: _namaPemilikProyek,
nik: _nik,
noHp: _noHp,
alamat: _alamat,
signature: _signature,
tandaTangan: _tandaTangan,
nominalDisetujui: _nominalDisetujui,
createdAt: block.timestamp
});
emit AgreementCreated(
_idProjek,
_idUser,
_namaProyek,
_namaPetugas,
_alamatPetugas,
_namaPemilikProyek,
_nik,
_noHp,
_alamat,
_signature,
_tandaTangan,
_nominalDisetujui,
block.timestamp
);
}
function getAllAgreement() public view returns (Agreement[] memory) {
Agreement[] memory allAgreements = new Agreement[](agreementCount);
for (uint256 i = 1; i <= agreementCount; i++) {
allAgreements[i - 1] = agreements[i];
}
return allAgreements;
}
function getAgreementByProjectId(
string memory idProjek
) public view returns (Agreement[] memory) {
uint256 count = 0;
for (uint256 i = 1; i <= agreementCount; i++) {
if (
keccak256(bytes(agreements[i].idProjek)) ==
keccak256(bytes(idProjek))
) {
count++;
}
}
Agreement[] memory projectAgreements = new Agreement[](count);
uint256 index = 0;
for (uint256 i = 1; i <= agreementCount; i++) {
if (
keccak256(bytes(agreements[i].idProjek)) ==
keccak256(bytes(idProjek))
) {
projectAgreements[index] = agreements[i];
index++;
}
}
return projectAgreements;
}
string[] public allChartTokenIds;
string[] public allHistoryTokenIds;
function addChartToken(
string memory idUser,
string memory idProjek,
int256 nominal,
int256 totalNilai
) public returns (string memory chartTokenId) {
chartTokenIdCounter.increment();
chartTokenId = string(
abi.encodePacked(
"CTK-",
block.timestamp.toString(),
"-",
chartTokenIdCounter.current().toString()
)
);
chartTokens[chartTokenId] = ChartToken({
chartTokenId: chartTokenId,
idUser: idUser,
idProjek: idProjek,
nominal: nominal,
createdAt: block.timestamp
});
allChartTokenIds.push(chartTokenId);
emit ChartTokenCreated(chartTokenId, idUser, idProjek, nominal, block.timestamp);
historyTokenIdCounter.increment();
string memory historyTokenId = string(
abi.encodePacked(
"HTK-",
block.timestamp.toString(),
"-",
historyTokenIdCounter.current().toString()
)
);
historyTokens[historyTokenId] = HistoryToken({
historyTokenId: historyTokenId,
chartTokenId: chartTokenId,
totalNilai: totalNilai,
createdAt: block.timestamp
});
allHistoryTokenIds.push(historyTokenId);
emit HistoryTokenCreated(historyTokenId, chartTokenId, totalNilai, block.timestamp);
return chartTokenId;
}
function getChartTokensByUserIdAndProjectId(
string memory idUser,
string memory idProjek
) public view returns (ChartToken[] memory) {
uint256 count = 0;
for (uint256 i = 0; i < allChartTokenIds.length; i++) {
if (
keccak256(bytes(chartTokens[allChartTokenIds[i]].idUser)) ==
keccak256(bytes(idUser)) &&
keccak256(bytes(chartTokens[allChartTokenIds[i]].idProjek)) ==
keccak256(bytes(idProjek))
) {
count++;
}
}
ChartToken[] memory userChartTokens = new ChartToken[](count);
uint256 index = 0;
for (uint256 i = 0; i < allChartTokenIds.length; i++) {
if (
keccak256(bytes(chartTokens[allChartTokenIds[i]].idUser)) ==
keccak256(bytes(idUser)) &&
keccak256(bytes(chartTokens[allChartTokenIds[i]].idProjek)) ==
keccak256(bytes(idProjek))
) {
userChartTokens[index] = chartTokens[allChartTokenIds[i]];
index++;
}
}
return userChartTokens;
}
function getAllChartTokensByUserId(
string memory idUser
) public view returns (ChartToken[] memory) {
uint256 count = 0;
for (uint256 i = 0; i < allChartTokenIds.length; i++) {
if (
keccak256(bytes(chartTokens[allChartTokenIds[i]].idUser)) ==
keccak256(bytes(idUser))
) {
count++;
}
}
ChartToken[] memory userChartTokens = new ChartToken[](count);
uint256 index = 0;
for (uint256 i = 0; i < allChartTokenIds.length; i++) {
if (
keccak256(bytes(chartTokens[allChartTokenIds[i]].idUser)) ==
keccak256(bytes(idUser))
) {
userChartTokens[index] = chartTokens[allChartTokenIds[i]];
index++;
}
}
return userChartTokens;
}
function extractTimestamp(
string memory chartTokenId
) internal pure returns (uint256) {
bytes memory idBytes = bytes(chartTokenId);
uint256 firstDash;
uint256 secondDash;
for (uint256 i = 0; i < idBytes.length; i++) {
if (idBytes[i] == "-") {
if (firstDash == 0) {
firstDash = i;
} else {
secondDash = i;
break;
}
}
}
uint256 timestamp = 0;
for (uint256 i = firstDash + 1; i < secondDash; i++) {
timestamp = timestamp * 10 + (uint256(uint8(idBytes[i])) - 48);
}
return timestamp;
}
function getLatestChartTokenByUserIdAndProjectId(
string memory idUser,
string memory idProjek
) public view returns (ChartToken memory) {
ChartToken memory latestChartToken;
uint256 latestTimestamp = 0;
for (uint256 i = 0; i < allChartTokenIds.length; i++) {
string memory chartTokenId = allChartTokenIds[i];
ChartToken memory currentToken = chartTokens[chartTokenId];
if (
keccak256(bytes(currentToken.idUser)) ==
keccak256(bytes(idUser)) &&
keccak256(bytes(currentToken.idProjek)) ==
keccak256(bytes(idProjek))
) {
uint256 currentTimestamp = extractTimestamp(chartTokenId);
if (currentTimestamp > latestTimestamp) {
latestTimestamp = currentTimestamp;
latestChartToken = currentToken;
}
}
}
return latestChartToken;
}
function getLatestChartTokensByProjectId(
string memory idProjek
) public view returns (ChartToken[] memory) {
ChartToken[] memory latestChartTokens = new ChartToken[](allChartTokenIds.length);
uint256 uniqueUserCount = 0;
for (uint256 i = 0; i < allChartTokenIds.length; i++) {
string memory chartTokenId = allChartTokenIds[i];
ChartToken memory currentToken = chartTokens[chartTokenId];
if (
keccak256(bytes(currentToken.idProjek)) ==
keccak256(bytes(idProjek))
) {
uint256 currentTimestamp = extractTimestamp(chartTokenId);
bool isNewUser = true;
for (uint256 j = 0; j < uniqueUserCount; j++) {
if (
keccak256(bytes(latestChartTokens[j].idUser)) ==
keccak256(bytes(currentToken.idUser))
) {
isNewUser = false;
if (
currentTimestamp >
extractTimestamp(latestChartTokens[j].chartTokenId)
) {
latestChartTokens[j] = currentToken;
}
break;
}
}
if (isNewUser) {
latestChartTokens[uniqueUserCount] = currentToken;
uniqueUserCount++;
}
}
}
ChartToken[] memory result = new ChartToken[](uniqueUserCount);
for (uint256 i = 0; i < uniqueUserCount; i++) {
result[i] = latestChartTokens[i];
}
return result;
}
function getHistoryTokensByUserIdAndProjectId(
string memory idUser,
string memory idProjek
) public view returns (HistoryToken[] memory) {
HistoryToken[] memory tempTokens = new HistoryToken[](
allChartTokenIds.length
);
uint256 count = 0;
for (uint256 i = 0; i < allChartTokenIds.length; i++) {
if (
keccak256(bytes(chartTokens[allChartTokenIds[i]].idUser)) ==
keccak256(bytes(idUser)) &&
keccak256(bytes(chartTokens[allChartTokenIds[i]].idProjek)) ==
keccak256(bytes(idProjek))
) {
string memory chartTokenId = allChartTokenIds[i];
tempTokens[count] = historyTokens[chartTokenId];
count++;
}
}
HistoryToken[] memory userHistoryTokens = new HistoryToken[](count);
for (uint256 j = 0; j < count; j++) {
userHistoryTokens[j] = tempTokens[j];
}
return userHistoryTokens;
}
function getHistoryTokenByChartTokenId(
string memory chartTokenId
) public view returns (HistoryToken memory) {
for (uint256 i = 0; i < allHistoryTokenIds.length; i++) {
if (
keccak256(
bytes(historyTokens[allHistoryTokenIds[i]].chartTokenId)
) == keccak256(bytes(chartTokenId))
) {
return historyTokens[allHistoryTokenIds[i]];
}
}
revert("HistoryToken not found for given ChartTokenId");
}
function getTotalNominalToken(
string memory idUser,
string memory idProjek
) public view returns (int256) { // Changed to int256
int256 totalNominal = 0; // Changed to int256
for (uint256 i = 0; i < allTokenIds.length; i++) {
TokenDetail memory tokenDetail = tokenDetails[allTokenIds[i]];
if (
keccak256(bytes(tokenDetail.idUser)) ==
keccak256(bytes(idUser)) &&
keccak256(bytes(tokenDetail.idProjek)) ==
keccak256(bytes(idProjek))
) {
totalNominal += tokenDetail.nilai;
}
}
return totalNominal;
}
function addDividenProfit(
string memory idProjek,
int256 pelaksana, // Changed to int256
int256 pemilik, // Changed to int256
int256 koperasi, // Changed to int256
int256 pendana // Changed to int256
) public {
DividenProfit memory newDividenProfit = DividenProfit({
idProjek: idProjek,
pelaksana: pelaksana,
pemilik: pemilik,
koperasi: koperasi,
pendana: pendana
});
dividenProfit[idProjek] = newDividenProfit;
emit DividenProfitAdded(
idProjek,
pelaksana,
pemilik,
koperasi,
pendana
);
}
function updateDividenProfit(
string memory idProjek,
int256 newPelaksana, // Changed to int256
int256 newPemilik, // Changed to int256
int256 newKoperasi, // Changed to int256
int256 newPendana // Changed to int256
) public {
require(
bytes(dividenProfit[idProjek].idProjek).length > 0,
"Dividen Profit not found"
);
dividenProfit[idProjek].pelaksana = newPelaksana;
dividenProfit[idProjek].pemilik = newPemilik;
dividenProfit[idProjek].koperasi = newKoperasi;
dividenProfit[idProjek].pendana = newPendana;
emit DividenProfitUpdated(
idProjek,
newPelaksana,
newPemilik,
newKoperasi,
newPendana
);
}
function getDividenProfitByProjectId(
string memory idProjek
) public view returns (DividenProfit memory) {
require(
bytes(dividenProfit[idProjek].idProjek).length > 0,
"Dividen Profit not found"
);
return dividenProfit[idProjek];
}
}