Created
May 15, 2022 13:50
-
-
Save BlockmanCodes/8af5b1ca5eb653edc03ad124e0e688b7 to your computer and use it in GitHub Desktop.
Ether Donation Dapp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "client", | |
"version": "0.1.0", | |
"private": true, | |
"dependencies": { | |
"@testing-library/jest-dom": "^5.16.4", | |
"@testing-library/react": "^13.2.0", | |
"@testing-library/user-event": "^13.5.0", | |
"bootstrap": "^5.1.3", | |
"ethers": "^5.6.6", | |
"react": "^18.1.0", | |
"react-bootstrap-icons": "^1.8.2", | |
"react-dom": "^18.1.0", | |
"react-scripts": "5.0.1", | |
"web-vitals": "^2.1.4" | |
}, | |
"scripts": { | |
"start": "react-scripts start", | |
"build": "react-scripts build", | |
"test": "react-scripts test", | |
"eject": "react-scripts eject" | |
}, | |
"eslintConfig": { | |
"extends": [ | |
"react-app", | |
"react-app/jest" | |
] | |
}, | |
"browserslist": { | |
"production": [ | |
">0.2%", | |
"not dead", | |
"not op_mini all" | |
], | |
"development": [ | |
"last 1 chrome version", | |
"last 1 firefox version", | |
"last 1 safari version" | |
] | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.App { | |
text-align: center; | |
} | |
.App-logo { | |
height: 40vmin; | |
pointer-events: none; | |
} | |
@media (prefers-reduced-motion: no-preference) { | |
.App-logo { | |
animation: App-logo-spin infinite 20s linear; | |
} | |
} | |
.App-header { | |
background-color: #1799F7; | |
min-height: 100vh; | |
display: flex; | |
flex-direction: column; | |
align-items: center; | |
justify-content: center; | |
font-size: calc(10px + 2vmin); | |
color: white; | |
} | |
.App-link { | |
color: #61dafb; | |
} | |
@keyframes App-logo-spin { | |
from { | |
transform: rotate(0deg); | |
} | |
to { | |
transform: rotate(360deg); | |
} | |
} | |
.amountButton { | |
cursor: pointer; | |
color: #000; | |
background-color: #fff; | |
font-weight: 600; | |
display: inline-block; | |
text-align: center; | |
padding: .375rem .75rem; | |
font-family: -apple-system; | |
text-decoration: none; | |
width: 100%; | |
margin-left: 10px !important; | |
margin-top: 5px !important; | |
margin-bottom: 5px !important; | |
} | |
.amountButtonLeft { | |
padding-right: 5px !important; | |
} | |
.amountButtonRight { | |
padding-left: 5px !important; | |
} | |
.amountButton:hover { | |
color: #000 !important; | |
background-color: #ffe484; | |
border-color: #ffe484; | |
} | |
.amountButton:active { | |
box-shadow: 0 2px #666; | |
transform: translateY(3px); | |
} | |
.amountClicked { | |
color: #000 !important; | |
background-color: #ffe484; | |
border-color: #ffe484; | |
} | |
.donateHeader { | |
color: #ffe484; | |
font-size: 42px; | |
} | |
.dot { | |
float: left; | |
margin-top: 12px !important; | |
margin-left: 15px !important; | |
height: 15px !important; | |
width: 15px !important; | |
background-color: #bbb; | |
border-radius: 50%; | |
display: inline-block; | |
} | |
.redDot { | |
background-color: #f85520; | |
} | |
.greenDot { | |
background-color: #00FF00; | |
} | |
.donationBubbleLeft { | |
border-radius: 4em 4em / 4em 4em; | |
background-color: #fff; | |
width: 100%; | |
color: #000; | |
margin-top: 5px; | |
text-align: left; | |
padding-left: 10px; | |
} | |
.paddingLeft { | |
padding-left: 15px; | |
} | |
.byAddress { | |
font-size: 18px; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import './App.css'; | |
import { ethers } from 'ethers'; | |
import { useEffect, useState } from 'react'; | |
import { SuitHeartFill } from 'react-bootstrap-icons'; | |
import artifact from './artifacts/contracts/Donation.sol/Donation.json' | |
function App() { | |
const [provider, setProvider] = useState(undefined); | |
const [signer, setSigner] = useState(undefined); | |
const [contract, setContract] = useState(undefined); | |
const [amount, setAmount] = useState(0); | |
const [donations, setDonations] = useState([]); | |
const toString = bytes32 => ethers.utils.parseBytes32String(bytes32); | |
const toWei = ether => ethers.utils.parseEther(ether); | |
const toEther = wei => ethers.utils.formatEther(wei).toString(); | |
useEffect(() => { | |
const init = async () => { | |
const provider = await new ethers.providers.Web3Provider(window.ethereum) | |
setProvider(provider) | |
const contract = await new ethers.Contract( | |
'0x5FbDB2315678afecb367f032d93F642f64180aa3', | |
artifact.abi | |
) | |
setContract(contract) | |
contract.connect(provider).getDonations() | |
.then((result) => { | |
const donations = result.map(el => [el[0], toEther(el[1])]) | |
setDonations(donations) | |
}) | |
} | |
init(); | |
}, []) | |
const isConnected = () => (signer !== undefined) | |
const getSigner = async provider => { | |
provider.send("eth_requestAccounts", []); | |
const signer = provider.getSigner(); | |
setSigner(signer) | |
} | |
const connect = () => { | |
getSigner(provider) | |
} | |
const sendDonation = async () => { | |
const wei = toWei(amount) | |
await signer.sendTransaction({ | |
to: contract.address, | |
value: wei | |
}) | |
setAmount('0') | |
} | |
return ( | |
<div className="App"> | |
<header className="App-header"> | |
<div className="row" style={{width: '800px'}}> | |
<div className="col-md-4"> | |
<div className="row"> | |
<div className="col-md-12"> | |
<h1 className="donateHeader">Donate ETH</h1> | |
</div> | |
</div> | |
<div className="row"> | |
<div className="col-md-6 amountButtonLeft"> | |
<a | |
onClick={ () => setAmount('0.1') } | |
className={"amountButton " + (amount === '0.1' ? 'amountClicked' : '')}> | |
0.1 | |
</a> | |
</div> | |
<div className="col-md-6 amountButtonRight"> | |
<a | |
onClick={ () => setAmount('0.5') } | |
className={"amountButton " + (amount === '0.5' ? 'amountClicked' : '')}> | |
0.5 | |
</a> | |
</div> | |
</div> | |
<div className="row"> | |
<div className="col-md-6 amountButtonLeft"> | |
<a | |
onClick={ () => setAmount('1') } | |
className={"amountButton " + (amount === '1' ? 'amountClicked' : '')}> | |
1 | |
</a> | |
</div> | |
<div className="col-md-6 amountButtonRight"> | |
<a | |
onClick={ () => setAmount('2') } | |
className={"amountButton " + (amount === '2' ? 'amountClicked' : '')}> | |
2 | |
</a> | |
</div> | |
</div> | |
<div className="row"> | |
<div className="col-md-12"> | |
<a | |
onClick={ () => sendDonation() } | |
className="amountButton">Donate</a> | |
</div> | |
</div> | |
<div className="row"> | |
<div className="col-md-12"> | |
{isConnected() ? ( | |
<> | |
<span className="dot greenDot"></span> | |
<p style={{fontSize: '25px'}}>Connected</p> | |
</> | |
) : ( | |
<> | |
<span className="dot redDot"></span> | |
<p style={{fontSize: '25px'}}>Not connected</p> | |
<button onClick={connect} className="btn btn-primary">Connect Wallet</button> | |
</> | |
)} | |
</div> | |
</div> | |
</div> | |
<div className="col-md-2"> | |
</div> | |
<div className="col-md-6"> | |
<div className="row"> | |
<div className="col-md-12"> | |
<h1 className="donateHeader">Recent Donations</h1> | |
</div> | |
</div> | |
{donations.map((ds,idx) => ( | |
<> | |
<div className="donationBubbleLeft"> | |
<SuitHeartFill fill="#FF7F97" /> | |
<span className="paddingLeft"> | |
{ds[1]} ETH | |
| |
<span className="byAddress">by {ds[0]?.substring(0,14)}...</span> | |
</span> | |
</div> | |
</> | |
))} | |
</div> | |
</div> | |
</header> | |
</div> | |
); | |
} | |
export default App; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react'; | |
import ReactDOM from 'react-dom/client'; | |
import './index.css'; | |
import App from './App'; | |
import 'bootstrap/dist/css/bootstrap.css'; | |
const root = ReactDOM.createRoot(document.getElementById('root')); | |
root.render( | |
<React.StrictMode> | |
<App /> | |
</React.StrictMode> | |
); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.8.0; | |
contract Donation { | |
address owner; | |
uint256 totalDonations; | |
struct Donation { | |
address donor; | |
uint256 amount; | |
} | |
Donation donation; | |
Donation[] donations; | |
constructor() { | |
owner = msg.sender; | |
} | |
receive() external payable { | |
donation = Donation( | |
msg.sender, | |
msg.value | |
); | |
donations.push(donation); | |
totalDonations += msg.value; | |
} | |
function getDonations() external view returns (Donation[] memory) { | |
return donations; | |
} | |
function getTotalDonations() external view returns (uint256) { | |
return totalDonations; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "ether-donation-dapp", | |
"version": "1.0.0", | |
"description": "", | |
"main": "index.js", | |
"scripts": { | |
"test": "echo \"Error: no test specified\" && exit 1" | |
}, | |
"keywords": [], | |
"author": "", | |
"license": "ISC", | |
"devDependencies": { | |
"@nomiclabs/hardhat-ethers": "^2.0.6", | |
"@nomiclabs/hardhat-waffle": "^2.0.3", | |
"chai": "^4.3.6", | |
"ethereum-waffle": "^3.4.4", | |
"ethers": "^5.6.6", | |
"hardhat": "^2.9.5" | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
async function main() { | |
[signer1, signer2, signer3] = await ethers.getSigners(); | |
const Donation = await ethers.getContractFactory('Donation', signer1); | |
const donation = await Donation.deploy(); | |
console.log("Donation contract deployed to:", donation.address, "by", signer1.address); | |
await signer1.sendTransaction({ | |
to: donation.address, | |
value: ethers.utils.parseUnits('0.1', 18) | |
}); | |
await signer2.sendTransaction({ | |
to: donation.address, | |
value: ethers.utils.parseUnits('0.1', 18) | |
}); | |
await signer3.sendTransaction({ | |
to: donation.address, | |
value: ethers.utils.parseUnits('2', 18) | |
}); | |
} | |
// npx hardhat run --network localhost scripts/01_deploy.js | |
main() | |
.then(() => process.exit(0)) | |
.catch((error) => { | |
console.error(error); | |
process.exit(1); | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const { expect } = require("chai"); | |
describe('Donation', function () { | |
beforeEach(async function() { | |
[signer1, signer2, signer3] = await ethers.getSigners(); | |
Donation = await ethers.getContractFactory('Donation', signer1); | |
donation = await Donation.deploy() | |
}); | |
describe('donateEther', function () { | |
it('transfers ether to the contract', async function() { | |
const provider = waffle.provider; | |
await signer2.sendTransaction({ | |
to: donation.address, | |
value: '100' | |
}); | |
expect( | |
await provider.getBalance(donation.address) | |
).to.equal('100'); | |
}); | |
}) | |
describe('getTotalDonations', function () { | |
it('returns the sum of donations transferred to the contract', async function() { | |
const provider = waffle.provider; | |
await signer1.sendTransaction({ | |
to: donation.address, | |
value: '1' | |
}); | |
await signer2.sendTransaction({ | |
to: donation.address, | |
value: '5' | |
}); | |
await signer3.sendTransaction({ | |
to: donation.address, | |
value: '50' | |
}); | |
expect( | |
await donation.connect(provider).getTotalDonations() | |
).to.equal('56') | |
}) | |
}) | |
describe('getDonations', function () { | |
it('returns an array of donations transferred to the contract', async function() { | |
const provider = waffle.provider; | |
await signer1.sendTransaction({ | |
to: donation.address, | |
value: '10' | |
}); | |
await signer2.sendTransaction({ | |
to: donation.address, | |
value: '20' | |
}); | |
const donations = await donation.connect(provider).getDonations() | |
expect(donations[0].donor).to.equal(signer1.address); | |
expect(donations[0].amount).to.equal('10'); | |
expect(donations[1].donor).to.equal(signer2.address); | |
expect(donations[1].amount).to.equal('20'); | |
}) | |
}) | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment