Initialize Project

This commit is contained in:
matze 2022-09-17 21:02:05 +02:00
parent 4b91e2921a
commit 7c31f3ba49
39 changed files with 31487 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
frontend/node_modules
truffle/node_modules

98
Contract/code.sol Normal file
View File

@ -0,0 +1,98 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
/**
* @title Storage
* @dev Store & retrieve value in a variable
* @custom:dev-run-script ./scripts/deploy_with_ethers.ts
*/
contract inheritance {
uint id;
mapping(uint => WILL) public wills;
mapping(address => uint[]) public wills_testator;
mapping(address => uint[]) public wills_beneficiary;
enum Status {
INITIATED_BY_TESTATOR,
WITHDRAWN_BY_BENEFICIARY,
AMOUNT_CHANGED,
DATE_CHANGED
}
struct WILL {
uint withdrawDate;
uint amount;
address testator;
address beneficiary;
Status status;
}
constructor() {
id = 0;
}
function deposit(address _beneficiary, uint _withdrawDate) public payable{
wills[id] = WILL({
beneficiary: _beneficiary,
amount: msg.value,
withdrawDate: _withdrawDate,
testator: msg.sender,
status: Status.INITIATED_BY_TESTATOR
});
wills_testator[msg.sender].push(id);
wills_beneficiary[_beneficiary].push(id);
id++;
}
function currentDate() public view returns (uint) {
return block.timestamp;
}
function withdrawBeneficiary(uint _id) public {
require(msg.sender == wills[_id].beneficiary, "You are not the beneficiary!");
require(wills[_id].amount > 0, "No founds available");
require(wills[_id].withdrawDate<block.timestamp, "Withdraw date is not reached.");
payable(msg.sender).transfer(wills[_id].amount);
wills[_id].amount = 0;
wills[_id].status = Status.WITHDRAWN_BY_BENEFICIARY;
}
function depositmore(uint _id) public payable{
require(msg.sender == wills[_id].testator, "You are not the testator");
wills[_id].amount = wills[_id].amount + uint256(msg.value);
wills[_id].status = Status.AMOUNT_CHANGED;
}
function withdrawTestator(uint _id) public payable{
require(msg.sender == wills[_id].testator, "You are not the testator");
wills[_id].amount = wills[_id].amount - uint256(msg.value);
payable(msg.sender).transfer(wills[_id].amount);
wills[_id].status = Status.AMOUNT_CHANGED;
}
function changeWithdrawDate(uint _id, uint _newWithdrawDate) public{
require(msg.sender == wills[_id].testator, "You are not the testator");
wills[_id].withdrawDate = _newWithdrawDate;
wills[_id].status = Status.DATE_CHANGED;
}
function get_amount(uint _id) public view returns (uint) {
return wills[_id].amount;
}
function get_wills_testator(address testatorAddress) public view returns (uint[] memory) {
return wills_testator[testatorAddress) ];
}
function get_wills_beneficiary(address beneficiaryAddress) public view returns (uint[] memory){
return wills_beneficiary[beneficiaryAddress) ];
}
}

13
frontend/index.html Executable file
View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>

3746
frontend/package-lock.json generated Executable file

File diff suppressed because it is too large Load Diff

23
frontend/package.json Executable file
View File

@ -0,0 +1,23 @@
{
"name": "frontend",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite --host",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"ethers": "^5.7.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.3.0"
},
"devDependencies": {
"@types/react": "^18.0.17",
"@types/react-dom": "^18.0.6",
"@vitejs/plugin-react": "^2.0.1",
"vite": "^3.0.7"
}
}

1
frontend/public/vite.svg Executable file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

9
frontend/src/App.css Executable file
View File

@ -0,0 +1,9 @@
#root {
/* max-width: 1280px;
margin: 0 auto;
padding: 2rem;
text-align: center; */
height: 100vh;
background: rgb(255,243,255);
background: linear-gradient(0deg, rgba(255,243,255,1) 0%, rgba(245,247,255,1) 41%, rgba(255,255,255,1) 100%);
}

35
frontend/src/App.jsx Executable file
View File

@ -0,0 +1,35 @@
import { useState, useEffect } from 'react'
import {BrowserRouter, Routes, Route} from 'react-router-dom';
import reactLogo from './assets/react.svg'
import './App.css'
import Tasse from "./components/Tasse.jsx"
import Banner from "./components/Banner.jsx"
import New from "./components/New.jsx"
import Beneficiary from "./components/Beneficiary.jsx"
import Testator from "./components/Testator.jsx"
import eth from "./eth/eth.js"
function App() {
useEffect(() => {
if(window.ethereum.selectedAddress) {
eth.init()
}
},[])
return (
<>
<BrowserRouter>
<Banner/>
<Routes>
<Route path="/*" element={<New/>} />
<Route path="/new" element={<New/>} />
<Route path="/beneficiary" element={<Beneficiary/>} />
<Route path="/Testator" element={<Testator/>} />
</Routes>
</BrowserRouter>
</>
)
}
export default App

1
frontend/src/assets/react.svg Executable file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@ -0,0 +1,56 @@
import { useState, useEffect} from 'react'
import "../css/Banner.css"
import {NavLink} from 'react-router-dom';
import eth from "../eth/eth.js"
function Banner() {
const [count, setCount] = useState(0)
const [address, setAddress] = useState("")
//functions
useEffect(() => {
if(window.ethereum.selectedAddress){
setAddress(window.ethereum.selectedAddress);
}
},[])
function addCount() {
var newValue = count + 1;
setCount(newValue);
}
async function connect(){
await eth.init();
setAddress(window.ethereum.selectedAddress);
}
return (
<div className="Banner">
<div className="BannerContainer">
<div>Logo</div>
<div className="navigation">
<NavLink to="/new" className={({ isActive }) => (isActive ? 'activeListItem' : 'listItem')}>
<div className="nav-el">New</div>
</NavLink>
<NavLink to="/beneficiary" className={({ isActive }) => (isActive ? 'activeListItem' : 'listItem')}>
<div className="nav-el">Beneficiary</div>
</NavLink>
<NavLink to="/testator" className={({ isActive }) => (isActive ? 'activeListItem' : 'listItem')}>
<div className="nav-el">Testator</div>
</NavLink>
</div>
{address ?
<>
{address}
</>
:
<>
<button onClick={connect}>Connect</button>
</>
}
</div>
</div>
)
}
export default Banner

View File

@ -0,0 +1,88 @@
import { useState, useEffect } from 'react'
import "../css/Banner.css";
import "../css/Beneficiary.css";
import CardBeneficiary from "./CardBeneficiary.jsx";
import eth from "../eth/eth.js"
import {ethers} from "ethers";
function Beneficiary() {
const [will_beneficiary, setwill_beneficiary] = useState([
])
useEffect(() => {
getBeneficiaries();
},[])
async function wait(time) {
return new Promise(resolve => setTimeout(resolve, time));
}
async function waitForInit() {
while(!eth.contractWithSigner) {
console.log("Waiting for 1s")
await wait(1000);
console.log("1s over");
}
}
async function getBeneficiaries() {
await waitForInit();
console.log(window.ethereum.selectedAddress);
console.log(eth.contractWithSigner);
var response = await eth.contractWithSigner.get_wills_beneficiary(window.ethereum.selectedAddress);
console.log(response);
console.log(response.length);
var myBeneficiary = [];
for(var i=0; i<response.length; i++) {
var will_beneficiary = await eth.contractWithSigner.wills(response[i].toNumber());
//console.log(response[i].toNumber());
var withdrawdateNew = timeConverter(will_beneficiary.withdrawDate.toNumber());
var myWill = {
id: response[i].toNumber(),
amount: ethers.utils.formatEther(will_beneficiary.amount),
testator: will_beneficiary.testator,
beneficiary: will_beneficiary.beneficiary,
withdrawDate: withdrawdateNew
}
console.log(myWill)
myBeneficiary.push(myWill);
}
setwill_beneficiary(myBeneficiary);
}
function timeConverter(withdrawDate){
var a = new Date(withdrawDate * 1000);
var year = a.getFullYear();
var month = a.getMonth()+1;
var date = a.getDate();
var hour = a.getHours();
var min = a.getMinutes();
var sec = a.getSeconds();
if(sec<10){
sec= '0' + sec;
}
if(month<10){
month= '0' + month;
}
var time = date + '.' + month + '.' + year + ' ' + hour + ':' + min + ':' + sec ;
return time;
}
return (
<div className="Beneficiary">
<div className="BeneficiaryContainer">
{(will_beneficiary).map((item, index) =>
<CardBeneficiary id={item.id} testator={item.testator} beneficiary={item.beneficiary} withdrawDate={item.withdrawDate} amount={item.amount} key={index}/>
)}
</div>
</div>
)
}
export default Beneficiary

View File

@ -0,0 +1,50 @@
import { useState } from 'react'
import "../css/Banner.css"
import "../css/Card.css";
import "../css/Buttons.css";
import eth from "../eth/eth.js"
function CardBeneficiary(props) {
async function withdraw(){
console.log(props.id);
var response = await eth.contractWithSigner.withdrawBeneficiary(props.id);
}
return (
<div className="CardBeneficiary">
<div>
<h1>ID: {props.id}</h1>
<hr/>
</div>
<table>
<thead></thead>
<tbody>
<tr>
<td>Testator</td>
<td>{props.testator}</td>
</tr>
<tr>
<td>Beneficiary</td>
<td>{props.beneficiary}</td>
</tr>
<tr>
<td>Withdraw Date</td>
<td>{props.withdrawDate}</td>
</tr>
<tr>
<td>Amount</td>
<td>{props.amount}</td>
</tr>
</tbody>
</table>
<br/>
<div className="btnArea">
<button className="withdrawBtn" onClick={withdraw}>Withdraw</button>
</div>
</div>
)
}
export default CardBeneficiary

View File

@ -0,0 +1,47 @@
import { useState } from 'react'
import "../css/Banner.css"
import "../css/Card.css";
import "../css/Buttons.css";
function CardTestator(props) {
return (
<div className="CardTestator">
<div>
<h1>ID: {props.id}</h1>
<hr/>
</div>
<table>
<thead></thead>
<tbody>
<tr>
<td>Testator</td>
<td>{props.testator}</td>
</tr>
<tr>
<td>Beneficiary</td>
<td>{props.beneficiary}</td>
</tr>
<tr>
<td>Withdraw Date</td>
<td>{props.withdrawDate}</td>
</tr>
<tr>
<td>Amount</td>
<td>{props.amount} ETH</td>
</tr>
</tbody>
</table>
<br/>
<div className="btnArea">
<button className="withdrawBtn">Withdraw</button>
<button className="extendBtn">Extend...</button>
</div>
</div>
)
}
export default CardTestator

61
frontend/src/components/New.jsx Executable file
View File

@ -0,0 +1,61 @@
import { useState } from 'react'
import "../css/New.css"
import eth from "../eth/eth.js"
import {ethers} from "ethers";
function New() {
const [beneficiary, setbeneficiary] = useState("")
const [withdrawDate, setwithdrawDate] = useState("")
const [amount, setamount] = useState("")
async function submit(){
console.log(eth.contractWithSigner);
//var contractSigner = eth.contract.connect(eth.signer);
var response = await eth.contractWithSigner.deposit(beneficiary, withdrawDate, {value: ethers.utils.parseUnits(amount)});
console.log(response);
}
function handleAddress(e){
setbeneficiary(e.target.value);
}
function handleWithdrawDate(e){
setwithdrawDate(e.target.value);
}
function handleAmount(e){
setamount(e.target.value);
}
return (
<div className="New">
<div className="NewContainer">
<h1>New Will</h1>
<table className="Table">
<tbody>
<tr>
<td>Beneficiary</td>
<td><input type="text" onChange={handleAddress}/></td>
</tr>
<tr>
<td>Withdraw Date</td>
<td><input type="text" onChange={handleWithdrawDate}/></td>
</tr>
<tr>
<td>Amount</td>
<td><input type="text" onChange={handleAmount}/></td>
</tr>
</tbody>
</table>
<button className ="Button" onClick={submit}>Create</button>
</div>
</div>
)
}
export default New

View File

@ -0,0 +1,19 @@
import { useState } from 'react'
function Tasse() {
const [count, setCount] = useState(0)
//functions
function addCount() {
var newValue = count + 1;
setCount(newValue);
}
return (
<div className="App">
Ich bin eine Tasse.
</div>
)
}
export default Tasse

View File

@ -0,0 +1,85 @@
import { useState, useEffect } from 'react'
import "../css/Banner.css"
import "../css/Testator.css";
import CardTestator from "./CardTestator.jsx";
import eth from "../eth/eth.js"
import {ethers} from "ethers";
function Testator() {
const [will_beneficiary, setwill_beneficiary] = useState([])
useEffect(() => {
getWillsTestator();
},[])
async function wait(time) {
return new Promise(resolve => setTimeout(resolve, time));
}
async function waitForInit() {
while(!eth.contractWithSigner) {
console.log("Waiting for 1s")
await wait(1000);
console.log("1s over");
}
}
async function getWillsTestator() {
await waitForInit();
var response = await eth.contractWithSigner.get_wills_testator(window.ethereum.selectedAddress);
console.log(response);
var myWills = [];
for(var i=0; i<response.length; i++) {
console.log(response[i].toNumber());
var will_testator = await eth.contractWithSigner.wills(response[i].toNumber());
var withdrawdateNew = timeConverter(will_testator.withdrawDate.toNumber());
var myWill = {
id: response[i].toNumber(),
amount: ethers.utils.formatEther(will_testator.amount),
testator: will_testator.testator,
beneficiary: will_testator.beneficiary,
withdrawDate: withdrawdateNew
}
myWills.push(myWill);
}
setwill_beneficiary(myWills);
}
function timeConverter(withdrawDate){
var a = new Date(withdrawDate * 1000);
//var months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
var year = a.getFullYear();
var month = a.getMonth()+1;
var date = a.getDate();
var hour = a.getHours();
var min = a.getMinutes();
var sec = a.getSeconds();
if(sec<10){
sec= '0' + sec;
}
if(month<10){
month= '0' + month;
}
var time = date + '.' + month + '.' + year + ' ' + hour + ':' + min + ':' + sec ;
return time;
}
return (
<div className="Testator">
<div className="TestatorContainer">
{(will_beneficiary).map((item, index) =>
<CardTestator id={item.id} testator={item.testator} beneficiary={item.beneficiary} withdrawDate={item.withdrawDate} amount={item.amount} key={index}/>
)}
</div>
</div>
)
}
export default Testator

9710
frontend/src/contractABI.json Executable file

File diff suppressed because one or more lines are too long

36
frontend/src/css/Banner.css Executable file
View File

@ -0,0 +1,36 @@
.Banner {
//background: grey;
width: 100%;
height: 50px;
display: flex;
align-items: center;
font-size: 17px;
}
.BannerContainer {
width: 100%;
display: flex;
justify-content: space-between;
margin-left: 20px;
margin-right: 20px;
}
.navigation {
display: flex;
}
.nav-el {
margin-left: 10px;
margin-right: 10px;
}
.listItem {
text-decoration: none;
color: black;
}
.activeListItem {
text-decoration: none;
color: black;
font-weight: bold;
}

View File

@ -0,0 +1,10 @@
.Beneficiary {
margin-left: 20vh;
margin-right: 20vh;
margin-top: 5vh;
}
.BeneficiaryContainer {
display: flex;
flex-wrap: wrap;
}

28
frontend/src/css/Buttons.css Executable file
View File

@ -0,0 +1,28 @@
.withdrawBtn {
padding: 10px;
background: #6dc4ff;
color: white;
font-weight: bold;
border: none;
border-radius: 20px;
margin-right: 10px;
}
.withdrawBtn:hover {
background: #60ade0;
cursor: pointer;
}
.extendBtn {
padding: 10px;
background: #be60e0;
color: white;
font-weight: bold;
border: none;
border-radius: 20px;
}
.extendBtn:hover {
background: #a453c1;
cursor: pointer;
}

46
frontend/src/css/Card.css Executable file
View File

@ -0,0 +1,46 @@
.CardBeneficiary {
display: flex;
flex-direction: column;
justify-content: space-between;
background: #fffdf9;
color: #595959;
width: 250px;
height: 300px;
border-radius: 12px;
padding-left: 20px;
padding-right: 20px;
padding-top: 20px;
margin: 20px;
box-shadow: 0px 0px 35px -2px rgba(110,110,110,0.49);
-webkit-box-shadow: 0px 0px 35px -2px rgba(110,110,110,0.49);
-moz-box-shadow: 0px 0px 35px -2px rgba(110,110,110,0.49);
}
table td {
padding-right: 15px;
padding-bottom: 5px;
}
.btnArea {
//border: 1px solid black;
margin-bottom: 25px;
}
.CardTestator {
display: flex;
flex-direction: column;
justify-content: space-between;
background: #fffdf9;
color: #595959;
width: 250px;
height: 300px;
border-radius: 12px;
padding-left: 20px;
padding-right: 20px;
padding-top: 20px;
margin: 20px;
box-shadow: 0px 0px 35px -2px rgba(110,110,110,0.49);
-webkit-box-shadow: 0px 0px 35px -2px rgba(110,110,110,0.49);
-moz-box-shadow: 0px 0px 35px -2px rgba(110,110,110,0.49);
}

49
frontend/src/css/New.css Executable file
View File

@ -0,0 +1,49 @@
.NewContainer{
width: 350px;
height: 200px;
background-color: rgb(239, 229, 229);
display: flex;
flex-direction:column;
justify-content:space-between;
border-radius: 12px;
padding-left: 20px;
padding-right: 20px;
padding-top: 20px;
padding-bottom: 20px;
margin: 20px;
text-align: center;
box-shadow: 0px 0px 35px -2px rgba(110,110,110,0.49);
-webkit-box-shadow: 0px 0px 35px -2px rgba(110,110,110,0.49);
-moz-box-shadow: 0px 0px 35px -2px rgba(110,110,110,0.49);
}
.New{
padding-top: 30px;
display: flex;
justify-content: center;
}
.Table{
width: 50%;
height: 100%;
font-weight: bold;
margin-left: auto;
margin-right: auto;
}
.Button{
font-size: 1.3em; padding: 5px 12px;
font-family: Roboto, sans-serif;
font-weight: 300;
color: rgb(2, 25, 142);
border: 1px solid silver;
background-image: linear-gradient(to top, gainsboro 0%, white 90%);
border-radius: 20px;
margin-left:auto;
margin-right:auto;
cursor: pointer;
}
.Button:hover {
background-image: linear-gradient(to top, rgb(199, 199, 199) 0%, rgb(236, 236, 236) 90%);
}

10
frontend/src/css/Testator.css Executable file
View File

@ -0,0 +1,10 @@
.Testator {
margin-left: 20vh;
margin-right: 20vh;
margin-top: 5vh;
}
.TestatorContainer {
display: flex;
flex-wrap: wrap;
}

29
frontend/src/eth/eth.js Executable file
View File

@ -0,0 +1,29 @@
import {ethers} from "ethers";
import Legacy from "../contractABI.json";
var provider;
var signer;
var contract;
var contractAddress = "0x96623DB287A02e82685C6194abe2C5378a3F9788";
var contractWithSigner;
var contractABI = Legacy.abi;
async function init(){
var myProvider = new ethers.providers.Web3Provider(window.ethereum);
await myProvider.send("eth_requestAccounts", []);
var blockNumber = await myProvider.getBlockNumber();
console.log("blockNumber: " + blockNumber);
var mySigner = myProvider.getSigner();
var myContract = new ethers.Contract(contractAddress, contractABI, myProvider);
var myContractWithSigner = myContract.connect(mySigner);
this.contractWithSigner = myContractWithSigner;
}
export default {
init,
provider,
signer,
contract,
contractWithSigner
}

75
frontend/src/index.css Executable file
View File

@ -0,0 +1,75 @@
* {
margin: 0;
padding: 0;
}
/* :root {
font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
font-size: 16px;
line-height: 24px;
font-weight: 400;
color-scheme: light dark;
color: rgba(255, 255, 255, 0.87);
background-color: #242424;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-text-size-adjust: 100%;
}
a {
font-weight: 500;
color: #646cff;
text-decoration: inherit;
}
a:hover {
color: #535bf2;
}
body {
margin: 0;
display: flex;
place-items: center;
min-width: 320px;
min-height: 100vh;
}
h1 {
font-size: 3.2em;
line-height: 1.1;
}
button {
border-radius: 8px;
border: 1px solid transparent;
padding: 0.6em 1.2em;
font-size: 1em;
font-weight: 500;
font-family: inherit;
background-color: #1a1a1a;
cursor: pointer;
transition: border-color 0.25s;
}
button:hover {
border-color: #646cff;
}
button:focus,
button:focus-visible {
outline: 4px auto -webkit-focus-ring-color;
}
@media (prefers-color-scheme: light) {
:root {
color: #213547;
background-color: #ffffff;
}
a:hover {
color: #747bff;
}
button {
background-color: #f9f9f9;
}
} */

10
frontend/src/main.jsx Executable file
View File

@ -0,0 +1,10 @@
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import './index.css'
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<App />
</React.StrictMode>
)

7
frontend/vite.config.js Executable file
View File

@ -0,0 +1,7 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()]
})

22
truffle/LICENSE Normal file
View File

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2018 Truffle
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,11 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
// A library is like a contract with reusable code, which can be called by other contracts.
// Deploying common code can reduce gas costs.
library ConvertLib{
function convert(uint amount, uint conversionRate) public pure returns (uint convertedAmount)
{
return amount * conversionRate;
}
}

View File

@ -0,0 +1,98 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.13;
/**
* @title Storage
* @dev Store & retrieve value in a variable
* @custom:dev-run-script ./scripts/deploy_with_ethers.ts
*/
contract Legacy {
uint id;
mapping(uint => WILL) public wills;
mapping(address => uint[]) public wills_testator;
mapping(address => uint[]) public wills_beneficiary;
enum Status {
INITIATED_BY_TESTATOR,
WITHDRAWN_BY_BENEFICIARY,
AMOUNT_CHANGED,
DATE_CHANGED
}
struct WILL {
uint withdrawDate;
uint amount;
address testator;
address beneficiary;
Status status;
}
constructor() {
id = 0;
}
function deposit(address _beneficiary, uint _withdrawDate) public payable{
wills[id] = WILL({
beneficiary: _beneficiary,
amount: msg.value,
withdrawDate: _withdrawDate,
testator: msg.sender,
status: Status.INITIATED_BY_TESTATOR
});
wills_testator[msg.sender].push(id);
wills_beneficiary[_beneficiary].push(id);
id++;
}
function currentDate() public view returns (uint) {
return block.timestamp;
}
function withdrawBeneficiary(uint _id) public {
require(msg.sender == wills[_id].beneficiary, "You are not the beneficiary!");
require(wills[_id].amount > 0, "No founds available");
require(wills[_id].withdrawDate<block.timestamp, "Withdraw date is not reached.");
payable(msg.sender).transfer(wills[_id].amount);
wills[_id].amount = 0;
wills[_id].status = Status.WITHDRAWN_BY_BENEFICIARY;
}
function depositmore(uint _id) public payable{
require(msg.sender == wills[_id].testator, "You are not the testator");
wills[_id].amount = wills[_id].amount + uint256(msg.value);
wills[_id].status = Status.AMOUNT_CHANGED;
}
function withdrawTestator(uint _id) public payable{
require(msg.sender == wills[_id].testator, "You are not the testator");
wills[_id].amount = wills[_id].amount - uint256(msg.value);
payable(msg.sender).transfer(wills[_id].amount);
wills[_id].status = Status.AMOUNT_CHANGED;
}
function changeWithdrawDate(uint _id, uint _newWithdrawDate) public{
require(msg.sender == wills[_id].testator, "You are not the testator");
wills[_id].withdrawDate = _newWithdrawDate;
wills[_id].status = Status.DATE_CHANGED;
}
function get_amount(uint _id) public view returns (uint) {
return wills[_id].amount;
}
function get_wills_testator(address testatorAddress) public view returns (uint[] memory) {
return wills_testator[testatorAddress];
}
function get_wills_beneficiary(address beneficiaryAddress) public view returns (uint[] memory){
return wills_beneficiary[beneficiaryAddress];
}
}

View File

@ -0,0 +1,35 @@
// SPDX-License-Identifier: MIT
// Tells the Solidity compiler to compile only from v0.8.13 to v0.9.0
pragma solidity ^0.8.13;
import "./ConvertLib.sol";
// This is just a simple example of a coin-like contract.
// It is not ERC20 compatible and cannot be expected to talk to other
// coin/token contracts.
contract MetaCoin {
mapping (address => uint) balances;
event Transfer(address indexed _from, address indexed _to, uint256 _value);
constructor() {
balances[tx.origin] = 10000;
}
function sendCoin(address receiver, uint amount) public returns(bool sufficient) {
if (balances[msg.sender] < amount) return false;
balances[msg.sender] -= amount;
balances[receiver] += amount;
emit Transfer(msg.sender, receiver, amount);
return true;
}
function getBalanceInEth(address addr) public view returns(uint){
return ConvertLib.convert(getBalance(addr),2);
}
function getBalance(address addr) public view returns(uint) {
return balances[addr];
}
}

View File

@ -0,0 +1,8 @@
const ConvertLib = artifacts.require("ConvertLib");
const Legacy = artifacts.require("Legacy");
module.exports = function(deployer) {
deployer.deploy(ConvertLib);
deployer.link(ConvertLib, Legacy);
deployer.deploy(Legacy);
};

5736
truffle/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

5
truffle/package.json Normal file
View File

@ -0,0 +1,5 @@
{
"dependencies": {
"@truffle/hdwallet-provider": "^2.0.14"
}
}

View File

@ -0,0 +1,27 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
// These files are dynamically created at test time
import "truffle/Assert.sol";
import "truffle/DeployedAddresses.sol";
import "../contracts/MetaCoin.sol";
contract TestMetaCoin {
function testInitialBalanceUsingDeployedContract() public {
MetaCoin meta = MetaCoin(DeployedAddresses.MetaCoin());
uint expected = 10000;
Assert.equal(meta.getBalance(tx.origin), expected, "Owner should have 10000 MetaCoin initially");
}
function testInitialBalanceWithNewMetaCoin() public {
MetaCoin meta = new MetaCoin();
uint expected = 10000;
Assert.equal(meta.getBalance(tx.origin), expected, "Owner should have 10000 MetaCoin initially");
}
}

39
truffle/test/metacoin.js Normal file
View File

@ -0,0 +1,39 @@
const MetaCoin = artifacts.require("MetaCoin");
contract('MetaCoin', (accounts) => {
it('should put 10000 MetaCoin in the first account', async () => {
const metaCoinInstance = await MetaCoin.deployed();
const balance = await metaCoinInstance.getBalance.call(accounts[0]);
assert.equal(balance.valueOf(), 10000, "10000 wasn't in the first account");
});
it('should call a function that depends on a linked library', async () => {
const metaCoinInstance = await MetaCoin.deployed();
const metaCoinBalance = (await metaCoinInstance.getBalance.call(accounts[0])).toNumber();
const metaCoinEthBalance = (await metaCoinInstance.getBalanceInEth.call(accounts[0])).toNumber();
assert.equal(metaCoinEthBalance, 2 * metaCoinBalance, 'Library function returned unexpected function, linkage may be broken');
});
it('should send coin correctly', async () => {
const metaCoinInstance = await MetaCoin.deployed();
// Setup 2 accounts.
const accountOne = accounts[0];
const accountTwo = accounts[1];
// Get initial balances of first and second account.
const accountOneStartingBalance = (await metaCoinInstance.getBalance.call(accountOne)).toNumber();
const accountTwoStartingBalance = (await metaCoinInstance.getBalance.call(accountTwo)).toNumber();
// Make transaction from first account to second.
const amount = 10;
await metaCoinInstance.sendCoin(accountTwo, amount, { from: accountOne });
// Get balances of first and second account after the transactions.
const accountOneEndingBalance = (await metaCoinInstance.getBalance.call(accountOne)).toNumber();
const accountTwoEndingBalance = (await metaCoinInstance.getBalance.call(accountTwo)).toNumber();
assert.equal(accountOneEndingBalance, accountOneStartingBalance - amount, "Amount wasn't correctly taken from the sender");
assert.equal(accountTwoEndingBalance, accountTwoStartingBalance + amount, "Amount wasn't correctly sent to the receiver");
});
});

75
truffle/truffle-config.js Normal file
View File

@ -0,0 +1,75 @@
/**
* Use this file to configure your truffle project. It's seeded with some
* common settings for different networks and features like migrations,
* compilation and testing. Uncomment the ones you need or modify
* them to suit your project as necessary.
*
* More information about configuration can be found at:
*
* https://trufflesuite.com/docs/truffle/reference/configuration
*
* To deploy via Infura you'll need a wallet provider (like @truffle/hdwallet-provider)
* to sign your transactions before they're sent to a remote public node. Infura accounts
* are available for free at: infura.io/register.
*
* You'll also need a mnemonic - the twelve word phrase the wallet uses to generate
* public/private key pairs. If you're publishing your code to GitHub make sure you load this
* phrase from a file you've .gitignored so it doesn't accidentally become public.
*
*/
// require('dotenv').config();
// const mnemonic = process.env["MNEMONIC"];
// const infuraProjectId = process.env["INFURA_PROJECT_ID"];
const HDWalletProvider = require('@truffle/hdwallet-provider');
module.exports = {
/**
* Networks define how you connect to your ethereum client and let you set the
* defaults web3 uses to send transactions. If you don't specify one truffle
* will spin up a development blockchain for you on port 9545 when you
* run `develop` or `test`. You can ask a truffle command to use a specific
* network from the command line, e.g
*
* $ truffle test --network <network-name>
*/
networks: {
// Useful for testing. The `development` name is special - truffle uses it by default
// if it's defined here and no other network is specified at the command line.
// You should run a client (like ganache, geth, or parity) in a separate terminal
// tab if you use this network and you must also set the `host`, `port` and `network_id`
// options below to some value.
//
// development: {
// host: "127.0.0.1", // Localhost (default: none)
// port: 8545, // Standard Ethereum port (default: none)
// network_id: "*", // Any network (default: none)
// },
ms101: {
provider: () => new HDWalletProvider('4397dbd437030df7c8ed3cb213f34aeea9786debd4bbd62767021eb19ae7d345', 'http://ms101.de:8545'),
host: "ms101.de",
port: 8545,
network_id: "1338",
},
//
// goerli: {
// provider: () => new HDWalletProvider(mnemonic, `https://goerli.infura.io/v3/${infuraProjectId}`),
// network_id: 5, // Goerli's id
// chain_id: 5
// }
},
// Set default mocha options here, use special reporters etc.
mocha: {
// timeout: 100000
},
// Configure your compilers
compilers: {
solc: {
version: "0.8.13", // Fetch exact version from solc-bin
}
}
};