From 26adef2c708f2791deb86d25f1549382540c5662 Mon Sep 17 00:00:00 2001 From: neila <40727091+neila@users.noreply.github.com> Date: Mon, 22 Jan 2024 14:30:57 +0900 Subject: [PATCH] add completed example contracts --- contracts/Government.sol | 140 ++++++++++++++++++++++++++ contracts/Medical.sol | 190 ++++++++++++++++++++++++++++++++++++ contracts/SocialNetwork.sol | 116 ++++++++++++++++++++++ 3 files changed, 446 insertions(+) create mode 100644 contracts/Government.sol create mode 100644 contracts/Medical.sol create mode 100644 contracts/SocialNetwork.sol diff --git a/contracts/Government.sol b/contracts/Government.sol new file mode 100644 index 0000000..032be5b --- /dev/null +++ b/contracts/Government.sol @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.17; + +import "hardhat/console.sol"; +import "./interfaces/IGovernment.sol"; + +contract Government is IGovernment { + // イベント定義 + event NewCandidate( + address candidate, + uint256 timestamp, + uint256 numOfVotes + ); + event NewVote(address voter, address candidate); + + // 立候補情報の構造体定義 + struct Candidate { + address candidate; // 立候補者のウォレットアドレス + uint256 timestamp; // 立候補した瞬間のタイムスタンプ + uint256 numOfVotes; // 得票数 + } + + Candidate[] private _candidates; + + // 二重立候補の防止 + mapping(address => bool) public isCandidate; + + // 二重投票の防止 + mapping(address => bool) public isVoter; + + constructor() { + console.log("This is SmartGovernment contract!"); + } + + function runForCandidate() external { + // 既に立候補済みかどうかを確認 + require(isCandidate[msg.sender] != true, "You already run for!"); + if (startTimeStamp == 0) { + startTimeStamp = block.timestamp; + endTimeStamp = startTimeStamp + 2 weeks; + } + // 選挙終了時刻以降に立候補の関数を呼び出した場合はエラー処理 + if (startTimeStamp != 0) { + require( + endTimeStamp > block.timestamp, + "You are too late to run for!" + ); + } + // 立候補フラグを建てる + isCandidate[msg.sender] = true; + // 配列に立候補情報を格納 + _candidates.push(Candidate(msg.sender, block.timestamp, 0)); + // フロントエンド側に新たな立候補情報を通知 + emit NewCandidate(msg.sender, block.timestamp, 0); + } + + // 立候補の内容をすべて取得する関数 + function getAllCandidates() public view returns (Candidate[] memory) { + return _candidates; + } + + // 開始時間の取得 + uint256 public startTimeStamp; + + // 終了時間の取得 + uint256 public endTimeStamp; + + function vote(address _candidateAddress) external { + uint256 candidateid; + for (uint256 index = 0; index < _candidates.length; index++) { + if (_candidateAddress == _candidates[index].candidate) { + candidateid = index; + } + } + // 立候補者は投票できないよう制限 + require(isCandidate[msg.sender] != true, "Candidates can't vote!"); + // 既に投票もしくは棄権した場合は投票できないよう制限 + require(isVoter[msg.sender] != true, "You already vote or abstain!"); + if (startTimeStamp != 0) { + require( + endTimeStamp > block.timestamp, + "You are too late to vote!" + ); + } + // 投票者・棄権者フラグを建てる + isVoter[msg.sender] = true; + // 投票された立候補者の得票数を1増やす + _candidates[candidateid].numOfVotes += 1; + // フロントエンド側に新たな投票情報を通知 + emit NewVote(msg.sender, _candidates[candidateid].candidate); + } + + // 棄権する関数 + function abstain() external { + // 既に投票もしくは棄権した場合は棄権できないよう制限 + require(isVoter[msg.sender] != true, "You already vote or abstain!"); + if (startTimeStamp != 0) { + require( + endTimeStamp > block.timestamp, + "You are too late to vote!" + ); + } + isVoter[msg.sender] = true; + } + + address private _winner; + + // 新会長を選出する関数 + function determinePresident() external { + require(endTimeStamp <= block.timestamp, "not yet timestamp!"); + uint256 chairmanIndex; + // 全立候補者のうち、最も得票数の多い立候補者のNoを探索 + require(_candidates.length > 0, "There are no _candidates yet"); + for (uint256 i; i < _candidates.length - 1; i++) { + (_candidates[chairmanIndex].numOfVotes > + _candidates[i + 1].numOfVotes + ? chairmanIndex = i + : chairmanIndex = i + 1); + } + _winner = _candidates[chairmanIndex].candidate; + } + + function getPresident() external view returns (address) { + return _winner; + } + + function numberOfVotes(address _candidateAddress) + external + view + returns (uint256) + { + for (uint256 i = 0; i < _candidates.length; i++) { + if (_candidates[i].candidate == _candidateAddress) { + return _candidates[i].numOfVotes; + } + } + return 0; + } +} diff --git a/contracts/Medical.sol b/contracts/Medical.sol new file mode 100644 index 0000000..ef0728b --- /dev/null +++ b/contracts/Medical.sol @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.17; +import "hardhat/console.sol"; +import "./interfaces/IMedical.sol"; + +contract Medical is IMedical { + //受診者データの構造体を作成 + struct Patient { + address ownerAddress; //構造体の作成者(本人であることを判定する) + string name; //名前 + string bloodType; //血液型 + uint256 lastUpdate; //最終更新日 + address doctorAddress; //担当医師のアドレス + uint256 id; //ID + } + + //医師データの構造体を作成 + struct Doctor { + address ownerAddress; //構造体の作成者(本人であることを判定する) + string name; //名前 + uint256 id; //ID + } + + uint256 private _patientId = 1; //受診者のID + uint256 private _doctorId = 1; //医師のID + + Patient[] public patients; + Doctor[] public doctors; + + mapping(address => uint256) private _patientAddressToId; //受診者のオーナーアドレスからIDをマッピング + mapping(uint256 => address) private _idToDoctorAddress; //IDから医師のアドレスをマッピング + mapping(address => uint256) private _doctorAddressToId; //医師のオーナーアドレスからIDをマッピング + mapping(address => string) private _doctorAddressToName; //医師のオーナーアドレスから名前をマッピング + + function register(string memory _name, string memory _bloodType) external { + require(_patientAddressToId[msg.sender] == 0, "already exist."); //未作成時のみ実行可能 + address _initialAddress; //医師の初期値アドレス + Patient memory _newPatient = Patient( + msg.sender, + _name, + _bloodType, + block.timestamp, + _initialAddress, + _patientId + ); + patients.push(_newPatient); + _patientAddressToId[msg.sender] = _patientId; + _patientId++; + } + + function updateName(string memory _name) external { + require(_patientAddressToId[msg.sender] > 0, "not registered yet"); + uint256 _ownerId = _patientAddressToId[msg.sender] - 1; + patients[_ownerId].name = _name; + patients[_ownerId].lastUpdate = block.timestamp; + } + + function updateBloodType(string memory _bloodType) external { + require(_patientAddressToId[msg.sender] > 0, "not registered yet"); + uint256 _ownerId = _patientAddressToId[msg.sender] - 1; + patients[_ownerId].bloodType = _bloodType; + patients[_ownerId].lastUpdate = block.timestamp; + } + + // 医師の登録も実装されている + function updateDoctorInfo(address _doctorAddress, string memory _name) + external + { + require(_doctorAddressToId[_doctorAddress] == 0, "already exist."); //未作成時のみ実行可能 + Doctor memory _newDoctor = Doctor(_doctorAddress, _name, _doctorId); + doctors.push(_newDoctor); + _doctorAddressToId[_doctorAddress] = _doctorId; + _doctorId++; + _doctorAddressToName[_doctorAddress] = _name; //医師の名前をマッピングで登録 + } + + function getMedicalData(address _patientAddress) + external + view + returns ( + string memory name, + string memory bloodType, + uint256 lastUpdatedtime + ) + { + require(_patientAddressToId[_patientAddress] > 0, "not registered yet"); + uint256 _ownerId = _patientAddressToId[_patientAddress] - 1; + require( + patients[_ownerId].doctorAddress == msg.sender || + patients[_ownerId].ownerAddress == msg.sender, + "not owner or doctor" + ); + return ( + patients[_ownerId].name, + patients[_ownerId].bloodType, + patients[_ownerId].lastUpdate + ); + } + + function provideViewingAccess(address _doctorAddress) external { + require(_patientAddressToId[msg.sender] > 0, "not registered yet"); + uint256 _ownerId = _patientAddressToId[msg.sender] - 1; + patients[_ownerId].doctorAddress = _doctorAddress; + _idToDoctorAddress[_ownerId] = _doctorAddress; + } + + function isViewingAccessGranted( + address _patientAddress, + address _medicalProviderAddress + ) external view returns (bool) { + uint256 _ownerId = _patientAddressToId[_patientAddress] - 1; + return patients[_ownerId].doctorAddress == _medicalProviderAddress; + } + + //受診者が自分の情報を確認するための関数。 + function viewPatientProfile() + external + view + returns ( + string memory, + string memory, + uint256, + address, + string memory + ) + { + require(_patientAddressToId[msg.sender] > 0, "not registered yet"); + uint256 _ownerId = _patientAddressToId[msg.sender] - 1; + address _doctorAddress = patients[_ownerId].doctorAddress; + string memory _doctorName = _doctorAddressToName[_doctorAddress]; //医師の名前をマッピングから取得 + return ( + patients[_ownerId].name, + patients[_ownerId].bloodType, + patients[_ownerId].lastUpdate, + patients[_ownerId].ownerAddress, + _doctorName + ); + } + + //医師が自分の情報を確認するための関数。 + function viewDoctorProfile() + external + view + returns ( + string memory, + uint256, + address + ) + { + require(_doctorAddressToId[msg.sender] > 0, " not registered yet"); + uint256 _ownerId = _doctorAddressToId[msg.sender] - 1; + return ( + doctors[_ownerId].name, + _ownerId, + doctors[_ownerId].ownerAddress + ); + } + + //受診者が医師を削除するための関数。 + function deleteDoctor() external { + require(_patientAddressToId[msg.sender] > 0, "Y not registered yet"); + uint256 _ownerId = _patientAddressToId[msg.sender] - 1; + address _initialAddress; //医師の初期値アドレス + patients[_ownerId].doctorAddress = _initialAddress; + _idToDoctorAddress[_ownerId] = _initialAddress; + } + + //医師に紐づく受診者を取得 + function viewClientsList() external view returns (Patient[] memory) { + uint256 count = 0; + for (uint256 i = 0; i < patients.length; i++) { + if (_idToDoctorAddress[i] == msg.sender) { + count++; + } + } + Patient[] memory result = new Patient[](count); + for (uint256 i = 0; i < patients.length; i++) { + if (_idToDoctorAddress[i] == msg.sender) { + result[i] = patients[i]; + } + } + return result; + } + + //医師全員を取得 + function viewAllDoctors() external view returns (Doctor[] memory) { + return doctors; + } +} diff --git a/contracts/SocialNetwork.sol b/contracts/SocialNetwork.sol new file mode 100644 index 0000000..ed7d5d0 --- /dev/null +++ b/contracts/SocialNetwork.sol @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.8.17; +import "@openzeppelin/contracts/utils/Counters.sol"; +import "hardhat/console.sol"; +import "./interfaces/ISocialNetwork.sol"; + +contract SocialNetwork is ISocialNetwork { + // postオブジェクト定義 + struct Post { + uint256 id; + uint256 timestamp; + uint256 totalLikes; + string message; + address user; + address[] likes; + } + + // postの配列 + Post[] public posts; + + // postのIdに使うカウンター定義 + using Counters for Counters.Counter; + Counters.Counter private _postIds; + + // グローバルタイムラインへのpostの追加 + function post(string memory _message) public { + Post memory newPost; + newPost.id = _postIds.current(); + newPost.user = msg.sender; + newPost.message = _message; + newPost.timestamp = uint256(block.timestamp); + + posts.push(newPost); + + _postIds.increment(); + } + + // likeの追加/削除 + function like(uint256 _postId) public { + // 削除した場合のフラグ + bool _deleted; + + // like対象のpost構造体を抽出 + for (uint256 i = 0; i < posts.length; i++) { + // 対象のpostでない場合は次へ + if (posts[i].id != _postId) { + continue; + } + + // like配列に対象のアドレスが含まれるか判定し、含まれる場合は削除する + address[] storage likes = posts[i].likes; + for (uint256 j = 0; j < likes.length; j++) { + // 対象でない場合は次へ + if (likes[j] != msg.sender) { + continue; + } + // deleteでは要素の値が0になるだけで削除されない + // delete posts[i].likes[j]; + // 削除したい要素が2の場合以下のようになる + // ex [1,2,3,4] -> [1,0,3,4] + + // 削除したい要素に最後の要素を設定し、最後の要素をpopすることで削除する + // ex [1,2,3,4]の2を削除 + // [1,2,3,4] -> [1,4,3,4] -> [1,4,3] + // ただし、要素のindexが変わってしまう + likes[j] = likes[likes.length - 1]; + likes.pop(); + posts[i].totalLikes--; + _deleted = true; + break; + } + // like配列にアドレスが含まれていない場合はアドレスを追加する + if (!_deleted) { + posts[i].likes.push(msg.sender); + posts[i].totalLikes++; + break; + } + } + } + + function unlike(uint256 _postId) public { + like(_postId); + } + + function getLastPostId() public view returns (uint256) { + return posts[posts.length - 1].id; + } + + function getPost(uint256 _postId) + external + view + returns ( + string memory message, + uint256 totalLikes, + uint256 time + ) + { + for (uint256 i = 0; i < posts.length; i++) { + if (posts[i].id == _postId) { + return ( + posts[i].message, + posts[i].totalLikes, + posts[i].timestamp + ); + } + } + Post memory emptyPost; + return (emptyPost.message, emptyPost.totalLikes, emptyPost.timestamp); + } + + // 全てのpostを取得 + function getAllPosts() public view returns (Post[] memory) { + return posts; + } +}