Skip to content

Commit

Permalink
Merge branch 'main' into chainlink
Browse files Browse the repository at this point in the history
  • Loading branch information
rgottleber authored Apr 12, 2022
2 parents 6c251f3 + 2083738 commit de62281
Show file tree
Hide file tree
Showing 31 changed files with 789 additions and 344 deletions.
5 changes: 3 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
KOVAN_RPC_URL='https://kovan.infura.io/v3/1234567890'
RINKEBY_RPC_URL='https://alchemy.infura.io/v3/1234567890'
RINKEBY_RPC_URL='https://rinkeby.infura.io/v3/1234567890'
POLYGON_MAINNET_RPC_URL='https://rpc-mainnet.maticvigil.com'
PRIVATE_KEY='abcdefg'
ALCHEMY_MAINNET_RPC_URL="https://eth-mainnet.alchemyapi.io/v2/your-api-key"
REPORT_GAS=true
COINMARKETCAP_API_KEY="YOUR_KEY"
AUTO_FUND=true
AUTO_FUND=true
VRF_SUBSCRIPTION_ID=YOUR_SUBSCRIPTION_ID
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -98,4 +98,6 @@ lint/outputs/
lint/tmp/
# lint/reports/

gas-report.txt
gas-report.txt

contracts/test/fuzzing/crytic-export
2 changes: 1 addition & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"tabWidth": 2,
"tabWidth": 4,
"useTabs": false,
"semi": false,
"singleQuote": false,
Expand Down
3 changes: 3 additions & 0 deletions .solcover.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
skipFiles: ['test/fuzzing/KeepersCounterEchidnaTest.sol', 'test/LinkToken.sol', 'test/MockOracle.sol', 'test/MockV3Aggregator.sol', 'test/VRFCoordinatorV2Mock.sol'],
};
116 changes: 86 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,16 @@

[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/smartcontractkit/hardhat-starter-kit)


- [Chainlink Hardhat Box](#chainlink-hardhat-box)
- [Chainlink Hardhat Starter Kit](#chainlink-hardhat-starter-kit)
- [Getting Started](#getting-started)
- [Requirements](#requirements)
- [Quickstart](#quickstart)
- [Typescript](#typescript)
- [Useage](#useage)
- [Usage](#usage)
- [Deploying Contracts](#deploying-contracts)
- [Run a Local Network](#run-a-local-network)
- [Using a Testnet or Live Network (like Mainnet or Polygon)](#using-a-testnet-or-live-network-like-mainnet-or-polygon)
- [Kovan Ethereum Testnet Setup](#kovan-ethereum-testnet-setup)
- [Rinkeby Ethereum Testnet Setup](#rinkeby-ethereum-testnet-setup)
- [Forking](#forking)
- [Auto-Funding](#auto-funding)
- [Test](#test)
Expand All @@ -32,11 +31,13 @@
- [Linting](#linting)
- [Code Formating](#code-formating)
- [Estimaging Gas](#estimaging-gas)
- [Code Coverage](#code-coverage)
- [Fuzzing](#fuzzing)
- [Contributing](#contributing)
- [Thank You!](#thank-you)
- [Resources](#resources)

# Chainlink Hardhat Box
# Chainlink Hardhat Starter Kit
Implementation of the following 4 Chainlink features using the [Hardhat](https://hardhat.org/) development environment:
- [Chainlink Price Feeds](https://docs.chain.link/docs/using-chainlink-reference-contracts)
- [Chainlink VRF](https://docs.chain.link/docs/chainlink-vrf)
Expand All @@ -59,6 +60,8 @@ It's recommended that you've gone through the [hardhat getting started documenta
- `yarn --version` And get an output like: `x.x.x`
- You might need to install it with npm

> If you're familiar with `npx` and `npm` instead of `yarn`, you can use `npx` for execution and `npm` for installing dependencies.
## Quickstart

1. Clone and install dependencies
Expand Down Expand Up @@ -88,7 +91,7 @@ yarn hardhat test
or

```
npx hardhat test
yarn hardhat test
```

### Typescript
Expand All @@ -100,7 +103,7 @@ git checkout typescript
yarn
```

# Useage
# Usage

If you run `yarn hardhat --help` you'll get an output of all the tasks you can run.

Expand Down Expand Up @@ -140,15 +143,15 @@ To interact with a live or test network, you'll need:
2. A Private Key
3. ETH & LINK token (either testnet or real)

Let's look at an example of setting these up using the Kovan testnet.
Let's look at an example of setting these up using the Rinkeby testnet.

### Kovan Ethereum Testnet Setup
### Rinkeby Ethereum Testnet Setup

First, we will need to set environment variables. We can do so by setting them in our `.env` file (create it if it's not there). You can also read more about [environment variables](https://www.twilio.com/blog/2017/01/how-to-set-environment-variables.html) from the linked twilio blog. You'll find a sample of what this file will look like in `.env.example`

> IMPORTANT: MAKE SURE YOU'D DONT EXPOSE THE KEYS YOU PUT IN THIS `.env` FILE. By that, I mean don't push them to a public repo, and please try to keep them keys you use in development not associated with any real funds.
1. Set your `KOVAN_RPC_URL` [environment variable.](https://www.twilio.com/blog/2017/01/how-to-set-environment-variables.html)
1. Set your `RINKEBY_RPC_URL` [environment variable.](https://www.twilio.com/blog/2017/01/how-to-set-environment-variables.html)

You can get one for free from [Alchmey](https://www.alchemy.com/), [Infura](https://infura.io/), or [Moralis](https://moralis.io/speedy-nodes/). This is your connection to the blockchain.

Expand All @@ -164,53 +167,60 @@ Don't commit and push any changes to .env files that may contain sensitive infor

`.env` example:
```
KOVAN_RPC_URL='www.infura.io/asdfadsfafdadf'
RINKEBY_RPC_URL='www.infura.io/asdfadsfafdadf'
PRIVATE_KEY='abcdef'
```
`bash` example
```
export KOVAN_RPC_URL='www.infura.io/asdfadsfafdadf'
export RINKEBY_RPC_URL='www.infura.io/asdfadsfafdadf'
export PRIVATE_KEY='abcdef'
```

> You can also use a `MNEMONIC` instead of a `PRIVATE_KEY` environment variable by uncommenting the section in the `hardhat.config.js`, and commenting out the `PRIVATE_KEY` line. However this is not recommended.
For other networks like mainnet and polygon, you can use different environment variables for your RPC URL and your private key. See the `hardhat.config.js` to learn more.

3. Get some Kovan Testnet ETH and LINK
3. Get some Rinkeby Testnet ETH and LINK

Head over to the [Chainlink faucets](https://faucets.chain.link/) and get some ETH and LINK. Please follow [the chainlink documentation](https://docs.chain.link/docs/acquire-link/) if unfamiliar.

4. Running commands
4. Create VRF V2 subscription

Head over to [VRF Subscription Page](https://vrf.chain.link/rinkeby) and create the new subscription. Save your subscription ID and put it in `.env` file as `VRF_SUBSCRIPTION_ID`

5. Running commands

You should now be all setup! You can run any command and just pass the `--network kovan` now!
You should now be all setup! You can run any command and just pass the `--network rinkeby` now!

To deploy contracts:

```
yarn hardhat deploy --network kovan
yarn hardhat deploy --network rinkeby
```

To run staging testnet tests
```
yarn hardhat test --network kovan
yarn hardhat test --network rinkeby
```

## Forking

If you'd like to run tests or on a network that is a [forked network](https://hardhat.org/hardhat-network/guides/mainnet-forking.html)
1. Set a `MAINNET_RPC_URL` environment variable that connects to the mainnet.
2. Uncomment the section in your `hardhat.config.js`
2. Choose a block number to select a state of the network you are forking and set it as `FORKING_BLOCK_NUMBER` environment variable. If ignored, it will use the latest block each time which can lead to test inconsistency.
3. Set `enabled` flag to `true`/`false` to enable/disable forking feature
```
// forking: {
// url: MAINNET_RPC_URL
// }
forking: {
url: MAINNET_RPC_URL,
blockNumber: FORKING_BLOCK_NUMBER,
enabled: false,
}
```


## Auto-Funding

This Starter Kit is configured by default to attempt to auto-fund any newly deployed contract that uses Any-API or Chainlink VRF, to save having to manually fund them after each deployment. The amount in LINK to send as part of this process can be modified in the [Starter Kit Config](helper-hardhat-config.js), and are configurable per network.
This Starter Kit is configured by default to attempt to auto-fund any newly deployed contract that uses Any-API, to save having to manually fund them after each deployment. The amount in LINK to send as part of this process can be modified in the [Starter Kit Config](helper-hardhat-config.js), and are configurable per network.

| Parameter | Description | Default Value |
| ---------- | :------------------------------------------------ | :------------ |
Expand All @@ -227,7 +237,7 @@ To run unit tests:
```bash
yarn test
```
Or
or
```
yarn hardhat test
```
Expand All @@ -241,13 +251,25 @@ yarn test-integration
or

```
yarn hardhat test --network kovan
yarn hardhat test --network rinkeby
```

## Performance optimizations

Since all tests are written in a way to be independent from each other, you can save time by running them in parallel. Make sure that `AUTO_FUND=false` inside `.env` file. There are some limitations with parallel testing, read more about them [here](https://hardhat.org/guides/parallel-tests.html)

To run tests in parallel:
```
yarn test --parallel
```
or
```
yarn hardhat test --parallel
```

# Interacting with Deployed Contracts

After deploying your contracts.
The deployment output will give you the contract addresses as they are deployed. You can then use these contract addresses in conjunction with Hardhat tasks to perform operations on each contract.
After deploying your contracts, the deployment output will give you the contract addresses as they are deployed. You can then use these contract addresses in conjunction with Hardhat tasks to perform operations on each contract.


## Chainlink Price Feeds
Expand Down Expand Up @@ -277,13 +299,19 @@ yarn hardhat read-data --contract insert-contract-address-here --network network


## VRF Get a random number
The VRFConsumer contract has two tasks, one to request a random number, and one to read the result of the random number request. This contract needs to be funded with link first:
The VRFConsumer contract has two tasks, one to request a random number, and one to read the result of the random number request. To start, go to [VRF Subscription Page](https://vrf.chain.link/rinkeby) and create the new subscription. Save your subscription ID and put it in `.env` file as `VRF_SUBSCRIPTION_ID`:

```bash
yarn hardhat fund-link --contract insert-contract-address-here --network network
VRF_SUBSCRIPTION_ID=subscription_id
```

Once it's funded, you can perform a VRF request with the request-random-number task:
Then, deploy your VRF V2 contract consumer to the network of your recent subscription using subscription id as constructor argument.

```bash
yarn hardhat deploy --network network
```

Finally, you need to go to your subscription page one more time and add the address of deployed contract as a new consumer. Once that's done, you can perform a VRF request with the request-random-number task:

```bash
yarn hardhat request-random-number --contract insert-contract-address-here --network network
Expand Down Expand Up @@ -313,7 +341,7 @@ yarn hardhat verify --network <NETWORK> <CONTRACT_ADDRESS> <CONSTRUCTOR_PARAMETE
example:

```
yarn hardhat verify --network kovan 0x9279791897f112a41FfDa267ff7DbBC46b96c296 "0x9326BFA02ADD2366b30bacB125260Af641031331"
yarn hardhat verify --network rinkeby 0x9279791897f112a41FfDa267ff7DbBC46b96c296 "0x9326BFA02ADD2366b30bacB125260Af641031331"
```

# View Contracts Size
Expand Down Expand Up @@ -348,6 +376,34 @@ yarn hardhat test

If you'd like to see the gas prices in USD or other currency, add a `COINMARKETCAP_API_KEY` from [Coinmarketcap](https://coinmarketcap.com/api/documentation/v1/).

# Code coverage

To see a measure in percent of the degree to which the smart contract source code is executed when a particular test suite is run, type
```
yarn coverage
```

# Fuzzing

We are going to use Echidna as a Fuzz testing tool. You need to have [Docker](https://www.docker.com/) installed with at least 8GB virtual memory allocated (To update this parameter go to _Settings->Resources->Advanced->Memory_).

To start Echidna instance run

```
yarn fuzzing
```

If you are using it for the first time, you will need to wait for Docker to download [eth-security-toolbox](https://hub.docker.com/r/trailofbits/eth-security-toolbox) image for us.

To start Fuzzing run
```
echidna-test /src/contracts/test/fuzzing/KeepersCounterEchidnaTest.sol --contract KeepersCounterEchidnaTest --config /src/contracts/test/fuzzing/config.yaml
```

To exit Echidna type
```bash
exit
```

# Contributing

Expand Down
48 changes: 32 additions & 16 deletions contracts/APIConsumer.sol
Original file line number Diff line number Diff line change
@@ -1,50 +1,56 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;

import "@chainlink/contracts/src/v0.8/ChainlinkClient.sol";

/**
* THIS IS AN EXAMPLE CONTRACT WHICH USES HARDCODED VALUES FOR CLARITY.
* PLEASE DO NOT USE THIS CODE IN PRODUCTION.
* @title The APIConsumer contract
* @notice An API Consumer contract that makes GET requests to obtain 24h trading volume of ETH in USD
*/
contract APIConsumer is ChainlinkClient {
using Chainlink for Chainlink.Request;

uint256 public volume;
address private oracle;
bytes32 private jobId;
uint256 private fee;
address private immutable oracle;
bytes32 private immutable jobId;
uint256 private immutable fee;

event DataFullfilled(uint256 volume);

/**
* Network: Kovan
* Oracle: 0xc57B33452b4F7BB189bB5AfaE9cc4aBa1f7a4FD8 (Chainlink Devrel
* Node)
* Job ID: d5270d1c311941d0b08bead21fea7747
* @notice Executes once when a contract is created to initialize state variables
*
* @param _oracle - address of the specific Chainlink node that a contract makes an API call from
* @param _jobId - specific job for :_oracle: to run; each job is unique and returns different types of data
* @param _fee - node operator price per API call / data request
* @param _link - LINK token address on the corresponding network
*
* Network: Rinkeby
* Oracle: 0xc57b33452b4f7bb189bb5afae9cc4aba1f7a4fd8
* Job ID: 6b88e0402e5d415eb946e528b8e0c7ba
* Fee: 0.1 LINK
*/
constructor(
address _oracle,
bytes32 _jobId,
uint256 _fee,
address _link
) public {
) {
if (_link == address(0)) {
setPublicChainlinkToken();
} else {
setChainlinkToken(_link);
}
// oracle = 0x2f90A6D021db21e1B2A077c5a37B3C7E75D15b7e;
// jobId = "29fa9aa13bf1468788b7cc4a500a45b8";
// fee = 0.1 * 10 ** 18; // 0.1 LINK
oracle = _oracle;
jobId = _jobId;
fee = _fee;
}

/**
* Create a Chainlink request to retrieve API response, find the target
* @notice Creates a Chainlink request to retrieve API response, find the target
* data, then multiply by 1000000000000000000 (to remove decimal places from data).
*
* @return requestId - id of the request
*/
function requestVolumeData() public returns (bytes32 requestId) {
Chainlink.Request memory request = buildChainlinkRequest(
Expand All @@ -66,7 +72,8 @@ contract APIConsumer is ChainlinkClient {
// }
// }
// }
request.add("path", "RAW.ETH.USD.VOLUME24HOUR");
// request.add("path", "RAW.ETH.USD.VOLUME24HOUR"); // Chainlink nodes prior to 1.0.0 support this format
request.add("path", "RAW,ETH,USD,VOLUME24HOUR"); // Chainlink nodes 1.0.0 and later support this format

// Multiply the result by 1000000000000000000 to remove decimals
int256 timesAmount = 10**18;
Expand All @@ -77,7 +84,10 @@ contract APIConsumer is ChainlinkClient {
}

/**
* Receive the response in the form of uint256
* @notice Receives the response in the form of uint256
*
* @param _requestId - id of the request
* @param _volume - response; requested 24h trading volume of ETH in USD
*/
function fulfill(bytes32 _requestId, uint256 _volume)
public
Expand All @@ -86,4 +96,10 @@ contract APIConsumer is ChainlinkClient {
volume = _volume;
emit DataFullfilled(volume);
}

/**
* @notice Witdraws LINK from the contract
* @dev Implement a withdraw function to avoid locking your LINK in the contract
*/
function withdrawLink() external {}
}
Loading

0 comments on commit de62281

Please sign in to comment.