-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit cf7b79c
Showing
10 changed files
with
357 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
*.sol linguist-language=Solidity | ||
*.vy linguist-language=Python |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
__pycache__ | ||
.env | ||
.history | ||
.hypothesis/ | ||
build/ | ||
reports/ |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
dependencies: | ||
# - <organization/repo>@<version> | ||
- smartcontractkit/[email protected] | ||
compiler: | ||
solc: | ||
remappings: | ||
- '@chainlink=smartcontractkit/[email protected]' | ||
|
||
dotenv: .env | ||
networks: | ||
goerli: | ||
eth_usd_price_feed: '0xD4a33860578De61DBAbDc8BFdb98FD742fA7028e' | ||
verify: True | ||
mainnet-fork-dev: | ||
eth_usd_price_feed: '0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419' | ||
verify: False | ||
development: | ||
verify: False | ||
ganache-local: | ||
verify: False | ||
eth_usd_price_feed: '0xD4a33860578De61DBAbDc8BFdb98FD742fA7028e' | ||
wallets: | ||
from_key: ${PRIVATE_KEY} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
|
||
// SPDX-License-Identifier: MIT | ||
|
||
// Smart contract that lets anyone deposit ETH into the contract | ||
// Only the owner of the contract can withdraw the ETH | ||
pragma solidity ^0.6.6; | ||
|
||
// Get the latest ETH/USD price from chainlink price feed | ||
|
||
// IMPORTANT: This contract has been updated to use the Goerli testnet | ||
// Please see: https://docs.chain.link/docs/get-the-latest-price/ | ||
// For more information | ||
|
||
import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol"; | ||
import "@chainlink/contracts/src/v0.6/vendor/SafeMathChainlink.sol"; | ||
|
||
contract FundMe { | ||
// safe math library check uint256 for integer overflows | ||
using SafeMathChainlink for uint256; | ||
|
||
//mapping to store which address depositeded how much ETH | ||
mapping(address => uint256) public addressToAmountFunded; | ||
// array of addresses who deposited | ||
address[] public funders; | ||
//address of the owner (who deployed the contract) | ||
address public owner; | ||
|
||
AggregatorV3Interface public priceFeed; | ||
|
||
// the first person to deploy the contract is | ||
// the owner | ||
constructor(address _priceFeed) public { | ||
priceFeed = AggregatorV3Interface(_priceFeed); | ||
owner = msg.sender; | ||
} | ||
|
||
function fund() public payable { | ||
// 18 digit number to be compared with donated amount | ||
uint256 minimumUSD = 50 * 10**18; | ||
//is the donated amount less than 50USD? | ||
require( | ||
getConversionRate(msg.value) >= minimumUSD, | ||
"You need to spend more ETH!" | ||
); | ||
//if not, add to mapping and funders array | ||
addressToAmountFunded[msg.sender] += msg.value; | ||
funders.push(msg.sender); | ||
} | ||
|
||
//function to get the version of the chainlink pricefeed | ||
function getVersion() public view returns (uint256) { | ||
return priceFeed.version(); | ||
} | ||
|
||
function getPrice() public view returns (uint256) { | ||
(, int256 answer, , , ) = priceFeed.latestRoundData(); | ||
// ETH/USD rate in 18 digit | ||
return uint256(answer * 10000000000); | ||
} | ||
|
||
// 1000000000 | ||
function getConversionRate(uint256 ethAmount) | ||
public | ||
view | ||
returns (uint256) | ||
{ | ||
uint256 ethPrice = getPrice(); | ||
uint256 ethAmountInUsd = (ethPrice * ethAmount) / 1000000000000000000; | ||
// the actual ETH/USD conversation rate, after adjusting the extra 0s. | ||
return ethAmountInUsd; | ||
} | ||
|
||
function getEntranceFee() public view returns (uint256) { | ||
// minimum USD | ||
uint256 minimumUSD = 50 * 10**18; | ||
uint256 price = getPrice(); | ||
uint256 precision = 1 * 10**18; | ||
return (minimumUSD * precision) / price; | ||
} | ||
|
||
//modifier: https://medium.com/coinmonks/solidity-tutorial-all-about-modifiers-a86cf81c14cb | ||
modifier onlyOwner() { | ||
//is the message sender owner of the contract? | ||
require(msg.sender == owner); | ||
|
||
_; | ||
} | ||
|
||
// onlyOwner modifer will first check the condition inside it | ||
// and | ||
// if true, withdraw function will be executed | ||
function withdraw() public payable onlyOwner { | ||
msg.sender.transfer(address(this).balance); | ||
|
||
//iterate through all the mappings and make them 0 | ||
//since all the deposited amount has been withdrawn | ||
for ( | ||
uint256 funderIndex = 0; | ||
funderIndex < funders.length; | ||
funderIndex++ | ||
) { | ||
address funder = funders[funderIndex]; | ||
addressToAmountFunded[funder] = 0; | ||
} | ||
//funders array will be initialized to 0 | ||
funders = new address[](0); | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.6.0; | ||
|
||
import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV2V3Interface.sol"; | ||
|
||
/** | ||
* @title MockV3Aggregator | ||
* @notice Based on the FluxAggregator contract | ||
* @notice Use this contract when you need to test | ||
* other contract's ability to read data from an | ||
* aggregator contract, but how the aggregator got | ||
* its answer is unimportant | ||
*/ | ||
contract MockV3Aggregator is AggregatorV2V3Interface { | ||
uint256 constant public override version = 0; | ||
|
||
uint8 public override decimals; | ||
int256 public override latestAnswer; | ||
uint256 public override latestTimestamp; | ||
uint256 public override latestRound; | ||
|
||
mapping(uint256 => int256) public override getAnswer; | ||
mapping(uint256 => uint256) public override getTimestamp; | ||
mapping(uint256 => uint256) private getStartedAt; | ||
|
||
constructor( | ||
uint8 _decimals, | ||
int256 _initialAnswer | ||
) public { | ||
decimals = _decimals; | ||
updateAnswer(_initialAnswer); | ||
} | ||
|
||
function updateAnswer( | ||
int256 _answer | ||
) public { | ||
latestAnswer = _answer; | ||
latestTimestamp = block.timestamp; | ||
latestRound++; | ||
getAnswer[latestRound] = _answer; | ||
getTimestamp[latestRound] = block.timestamp; | ||
getStartedAt[latestRound] = block.timestamp; | ||
} | ||
|
||
function updateRoundData( | ||
uint80 _roundId, | ||
int256 _answer, | ||
uint256 _timestamp, | ||
uint256 _startedAt | ||
) public { | ||
latestRound = _roundId; | ||
latestAnswer = _answer; | ||
latestTimestamp = _timestamp; | ||
getAnswer[latestRound] = _answer; | ||
getTimestamp[latestRound] = _timestamp; | ||
getStartedAt[latestRound] = _startedAt; | ||
} | ||
|
||
function getRoundData(uint80 _roundId) | ||
external | ||
view | ||
override | ||
returns ( | ||
uint80 roundId, | ||
int256 answer, | ||
uint256 startedAt, | ||
uint256 updatedAt, | ||
uint80 answeredInRound | ||
) | ||
{ | ||
return ( | ||
_roundId, | ||
getAnswer[_roundId], | ||
getStartedAt[_roundId], | ||
getTimestamp[_roundId], | ||
_roundId | ||
); | ||
} | ||
|
||
function latestRoundData() | ||
external | ||
view | ||
override | ||
returns ( | ||
uint80 roundId, | ||
int256 answer, | ||
uint256 startedAt, | ||
uint256 updatedAt, | ||
uint80 answeredInRound | ||
) | ||
{ | ||
return ( | ||
uint80(latestRound), | ||
getAnswer[latestRound], | ||
getStartedAt[latestRound], | ||
getTimestamp[latestRound], | ||
uint80(latestRound) | ||
); | ||
} | ||
|
||
function description() | ||
external | ||
view | ||
override | ||
returns (string memory) | ||
{ | ||
return "v0.6/tests/MockV3Aggregator.sol"; | ||
} | ||
} | ||
|
||
// MockOracle | ||
// Function signatures, event signatures, log topics |
Empty file.
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
from brownie import FundMe, MockV3Aggregator, network, config | ||
from scripts.helpful_scripts import (get_account, | ||
deploy_mocks, | ||
LOCAL_BLOCKCHAIN_ENVIRONMENTS, | ||
) | ||
|
||
|
||
def deploy_fund_me(): | ||
account = get_account() | ||
# pass the price feed address to our fundme contract | ||
|
||
# if we are on a persistent network like rinkeby, use the associated address | ||
# otherwise, deploy mocks | ||
if network.show_active() not in LOCAL_BLOCKCHAIN_ENVIRONMENTS: | ||
price_feed_address = config['networks'][network.show_active()]['eth_usd_price_feed'] | ||
else: | ||
deploy_mocks() | ||
price_feed_address = MockV3Aggregator[-1].address | ||
|
||
fund_me = FundMe.deploy( | ||
price_feed_address, | ||
{"from": account}, | ||
publish_source=config["networks"][network.show_active()].get("verify") | ||
) | ||
print(f"Contract deployed to {fund_me.address}") | ||
return fund_me | ||
|
||
|
||
def main(): | ||
deploy_fund_me() |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
from brownie import FundMe | ||
from scripts.helpful_scripts import get_account | ||
|
||
|
||
def fund(): | ||
fund_me = FundMe[-1] | ||
account = get_account() | ||
entrance_fee = fund_me.getEntranceFee() | ||
print(entrance_fee) | ||
print(f"The current entry fee is {entrance_fee}") | ||
print("funding") | ||
fund_me.fund({"from": account, "value": entrance_fee}) | ||
|
||
|
||
def withdraw(): | ||
fund_me = FundMe[-1] | ||
account = get_account() | ||
fund_me.withdraw({"from": account}) | ||
|
||
|
||
def main(): | ||
fund() |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
from brownie import accounts, config, network, MockV3Aggregator | ||
from web3 import Web3 | ||
|
||
FORKED_LOCAL_ENVIRONMENTS = ["mainnet-fork", "mainnet-fork-dev"] | ||
LOCAL_BLOCKCHAIN_ENVIRONMENTS = ["development", "ganache-local"] | ||
|
||
DECIMALS = 18 | ||
STARTING_PRICE = 2000 | ||
|
||
|
||
def get_account(): | ||
if network.show_active() in LOCAL_BLOCKCHAIN_ENVIRONMENTS\ | ||
or network.show_active() in FORKED_LOCAL_ENVIRONMENTS: | ||
return accounts[0] | ||
else: | ||
return accounts.add(config["wallets"]["from_key"]) | ||
|
||
|
||
def deploy_mocks(): | ||
print(f"The active network is {network.show_active()}") | ||
print("Deploying mocks...") | ||
if len(MockV3Aggregator) <= 0: | ||
MockV3Aggregator.deploy(DECIMALS, | ||
Web3.toWei(STARTING_PRICE, "ether"), | ||
{"from": get_account()} | ||
) | ||
print("Mocks Deployed!") |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
from scripts.helpful_scripts import get_account, LOCAL_BLOCKCHAIN_ENVIRONMENTS | ||
from scripts.deploy import deploy_fund_me | ||
from brownie import network, accounts, exceptions | ||
import pytest | ||
|
||
|
||
def test_can_fund_and_withdraw(): | ||
account = get_account() | ||
fund_me = deploy_fund_me() | ||
entrance_fee = fund_me.getEntranceFee() + 100 | ||
print("entrance_fee...", entrance_fee) | ||
tx = fund_me.fund({"from": account, "value": entrance_fee}) | ||
tx.wait(1) | ||
assert fund_me.addressToAmountFunded(account.address) == entrance_fee | ||
tx2 = fund_me.withdraw({"from": account}) | ||
tx2.wait(1) | ||
assert fund_me.addressToAmountFunded(account.address) == 0 | ||
|
||
|
||
def test_only_owner_can_withdraw(): | ||
if network.show_active() not in LOCAL_BLOCKCHAIN_ENVIRONMENTS: | ||
pytest.skip("only for local testing") | ||
|
||
fund_me = deploy_fund_me() | ||
bad_actor = accounts.add() | ||
with pytest.raises(exceptions.VirtualMachineError): | ||
fund_me.withdraw({"from": bad_actor}) |