Skip to content

Commit

Permalink
added listening for events for testnet tests; made verification proce…
Browse files Browse the repository at this point in the history
…ss more robust
  • Loading branch information
PatrickAlphaC committed Feb 4, 2022
1 parent 8efc3d9 commit 7acf170
Show file tree
Hide file tree
Showing 10 changed files with 136 additions and 57 deletions.
60 changes: 30 additions & 30 deletions brownie-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ dependencies:
compiler:
solc:
remappings:
- '@chainlink=smartcontractkit/[email protected]'
- '@openzeppelin=OpenZeppelin/[email protected]'
- "@chainlink=smartcontractkit/[email protected]"
- "@openzeppelin=OpenZeppelin/[email protected]"
# automatically fetch contract sources from Etherscan
autofetch_sources: True
# Uncomment to use the .env file
Expand All @@ -19,58 +19,58 @@ autofetch_sources: True
networks:
default: development
development:
keyhash: '0x6c3699283bda56ad74f6b855546325b68d482e983852a7a82979cc4807b641f4'
keyhash: "0x6c3699283bda56ad74f6b855546325b68d482e983852a7a82979cc4807b641f4"
fee: 100000000000000000
jobId: '29fa9aa13bf1468788b7cc4a500a45b8'
jobId: "29fa9aa13bf1468788b7cc4a500a45b8"
update_interval: 60
verify: False
kovan:
vrf_coordinator: '0xdD3782915140c8f3b190B5D67eAc6dc5760C46E9'
link_token: '0xa36085F69e2889c224210F603D836748e7dC0088'
keyhash: '0x6c3699283bda56ad74f6b855546325b68d482e983852a7a82979cc4807b641f4'
vrf_coordinator: "0xdD3782915140c8f3b190B5D67eAc6dc5760C46E9"
link_token: "0xa36085F69e2889c224210F603D836748e7dC0088"
keyhash: "0x6c3699283bda56ad74f6b855546325b68d482e983852a7a82979cc4807b641f4"
fee: 100000000000000000
oracle: '0xc57b33452b4f7bb189bb5afae9cc4aba1f7a4fd8'
jobId: 'd5270d1c311941d0b08bead21fea7747'
eth_usd_price_feed: '0x9326BFA02ADD2366b30bacB125260Af641031331'
oracle: "0xc57b33452b4f7bb189bb5afae9cc4aba1f7a4fd8"
jobId: "d5270d1c311941d0b08bead21fea7747"
eth_usd_price_feed: "0x9326BFA02ADD2366b30bacB125260Af641031331"
# Change to True if you have an Etherscan API key and want to verify
verify: False
verify: True
update_interval: 60
ganache:
keyhash: '0x6c3699283bda56ad74f6b855546325b68d482e983852a7a82979cc4807b641f4'
keyhash: "0x6c3699283bda56ad74f6b855546325b68d482e983852a7a82979cc4807b641f4"
fee: 100000000000000000
jobId: '29fa9aa13bf1468788b7cc4a500a45b8'
jobId: "29fa9aa13bf1468788b7cc4a500a45b8"
update_interval: 60
verify: False
rinkeby:
vrf_coordinator: '0xb3dCcb4Cf7a26f6cf6B120Cf5A73875B7BBc655B'
link_token: '0x01be23585060835e02b77ef475b0cc51aa1e0709'
keyhash: '0x2ed0feb3e7fd2022120aa84fab1945545a9f2ffc9076fd6156fa96eaff4c1311'
vrf_coordinator: "0xb3dCcb4Cf7a26f6cf6B120Cf5A73875B7BBc655B"
link_token: "0x01be23585060835e02b77ef475b0cc51aa1e0709"
keyhash: "0x2ed0feb3e7fd2022120aa84fab1945545a9f2ffc9076fd6156fa96eaff4c1311"
fee: 100000000000000000
oracle: '0xc57b33452b4f7bb189bb5afae9cc4aba1f7a4fd8'
jobId: '6b88e0402e5d415eb946e528b8e0c7ba'
eth_usd_price_feed: '0x8A753747A1Fa494EC906cE90E9f37563A8AF630e'
oracle: "0xc57b33452b4f7bb189bb5afae9cc4aba1f7a4fd8"
jobId: "6b88e0402e5d415eb946e528b8e0c7ba"
eth_usd_price_feed: "0x8A753747A1Fa494EC906cE90E9f37563A8AF630e"
# Change to True if you have an Etherscan API key and want to verify
verify: False
fuji:
link_token: '0x0b9d5D9136855f6FEc3c0993feE6E9CE8a297846'
link_token: "0x0b9d5D9136855f6FEc3c0993feE6E9CE8a297846"
fee: 100000000000000000
oracle: '0xcc80934eaf22b2c8dbf7a69e8e0d356a7cac5754'
jobId: '5ca4fa9b2d64462290abfbda84e38cf4'
oracle: "0xcc80934eaf22b2c8dbf7a69e8e0d356a7cac5754"
jobId: "5ca4fa9b2d64462290abfbda84e38cf4"
mumbai:
eth_usd_price_feed: '0x0715A7794a1dc8e42615F059dD6e406A6594651A'
link_token: '0x326C977E6efc84E512bB9C30f76E30c160eD06FB'
vrf_coordinator: '0x8C7382F9D8f56b33781fE506E897a4F1e2d17255'
keyhash: '0x6e75b569a01ef56d18cab6a8e71e6600d6ce853834d4a5748b720d06f878b3a4'
eth_usd_price_feed: "0x0715A7794a1dc8e42615F059dD6e406A6594651A"
link_token: "0x326C977E6efc84E512bB9C30f76E30c160eD06FB"
vrf_coordinator: "0x8C7382F9D8f56b33781fE506E897a4F1e2d17255"
keyhash: "0x6e75b569a01ef56d18cab6a8e71e6600d6ce853834d4a5748b720d06f878b3a4"
fee: 1000000000000000000
binance:
# link_token: ??
eth_usd_price_feed: '0x9ef1B8c0E4F7dc8bF5719Ea496883DC6401d5b2e'
eth_usd_price_feed: "0x9ef1B8c0E4F7dc8bF5719Ea496883DC6401d5b2e"
binance-fork:
eth_usd_price_feed: '0x9ef1B8c0E4F7dc8bF5719Ea496883DC6401d5b2e'
eth_usd_price_feed: "0x9ef1B8c0E4F7dc8bF5719Ea496883DC6401d5b2e"
mainnet-fork:
eth_usd_price_feed: '0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419'
eth_usd_price_feed: "0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419"
matic-fork:
eth_usd_price_feed: '0xF9680D99D6C9589e2a93a78A04A279e509205945'
eth_usd_price_feed: "0xF9680D99D6C9589e2a93a78A04A279e509205945"
wallets:
from_key: ${PRIVATE_KEY}
from_mnemonic: ${MNEMONIC}
Expand Down
10 changes: 6 additions & 4 deletions contracts/APIConsumer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ import "@chainlink/contracts/src/v0.8/ChainlinkClient.sol";
contract APIConsumer is ChainlinkClient {
using Chainlink for Chainlink.Request;
uint256 public volume;

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

event DataFullfilled(uint256 volume);

/**
* Network: Kovan
Expand Down Expand Up @@ -66,6 +67,7 @@ contract APIConsumer is ChainlinkClient {
function fulfill(bytes32 _requestId, uint256 _volume) public recordChainlinkFulfillment(_requestId)
{
volume = _volume;
emit DataFullfilled(volume);
}

// function stringToBytes32(string memory source) public pure returns (bytes32 result) {
Expand Down
3 changes: 3 additions & 0 deletions contracts/VRFConsumer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ contract VRFConsumer is VRFConsumerBase {
uint256 internal fee;

uint256 public randomResult;
event ReturnedRandomness(uint256 randomNumber);


/**
* Constructor inherits VRFConsumerBase
Expand Down Expand Up @@ -42,5 +44,6 @@ contract VRFConsumer is VRFConsumerBase {
*/
function fulfillRandomness(bytes32 requestId, uint256 randomness) internal override {
randomResult = randomness;
emit ReturnedRandomness(randomResult);
}
}
6 changes: 5 additions & 1 deletion scripts/chainlink_api_scripts/01_deploy_api_consumer.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,12 @@ def deploy_api_consumer():
fee,
link_token,
{"from": account},
publish_source=config["networks"][network.show_active()].get("verify", False),
)
if (config["networks"][network.show_active()].get("verify", False)):
api_consumer.tx.wait(BLOCK_CONFIRMATIONS_FOR_VERIFICATION)
APIConsumer.publish_source(api_consumer)
else:
api_consumer.tx.wait(1)
print(f"API Consumer deployed to {api_consumer.address}")
return api_consumer

Expand Down
40 changes: 38 additions & 2 deletions scripts/helpful_scripts.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,18 @@
MockOracle,
VRFCoordinatorMock,
Contract,
web3
)
from web3 import Web3
import time

NON_FORKED_LOCAL_BLOCKCHAIN_ENVIRONMENTS = ["hardhat", "development", "ganache"]
LOCAL_BLOCKCHAIN_ENVIRONMENTS = NON_FORKED_LOCAL_BLOCKCHAIN_ENVIRONMENTS + [
"mainnet-fork",
"binance-fork",
"matic-fork",
]
# Etherscan usually takes a few blocks to register the contract has been deployed
BLOCK_CONFIRMATIONS_FOR_VERIFICATION = 6

contract_to_mock = {
"link_token": LinkToken,
Expand All @@ -25,7 +28,7 @@
}

DECIMALS = 18
INITIAL_VALUE = Web3.toWei(2000, "ether")
INITIAL_VALUE = web3.toWei(2000, "ether")


def get_account(index=None, id=None):
Expand Down Expand Up @@ -114,3 +117,36 @@ def deploy_mocks(decimals=DECIMALS, initial_value=INITIAL_VALUE):
mock_oracle = MockOracle.deploy(link_token.address, {"from": account})
print(f"Deployed to {mock_oracle.address}")
print("Mocks Deployed!")


def listen_for_event(brownie_contract, event, timeout=200, poll_interval=2):
"""Listen asyncronously for an event to be fired from a contract.
We are waiting for the event to return, so this function is blocking.
Args:
brownie_contract ([brownie.network.contract.ProjectContract]):
A brownie contract of some kind.
event ([string]): The event you'd like to listen for.
timeout (int, optional): The max amount in seconds you'd like to
wait for that event to fire. Defaults to 200 seconds.
poll_interval ([int]): How often to call your node to check for events.
Defaults to 2 seconds.
"""
web3_contract = web3.eth.contract(
address=brownie_contract.address, abi=brownie_contract.abi
)
start_time = time.time()
current_time = time.time()
event_filter = web3_contract.events[event].createFilter(fromBlock="latest")
while current_time - start_time < timeout:
for event_response in event_filter.get_new_entries():
if event in event_response.event:
print("Found event!")
return event_response
time.sleep(poll_interval)
current_time = time.time()
print("Timeout reached, no event found.")
return { "event": None }
7 changes: 6 additions & 1 deletion scripts/price_feed_scripts/01_deploy_price_consumer_v3.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from scripts.helpful_scripts import (
get_account,
get_contract,
BLOCK_CONFIRMATIONS_FOR_VERIFICATION
)


Expand All @@ -12,8 +13,12 @@ def deploy_price_feed_consumer():
price_feed = PriceFeedConsumer.deploy(
eth_usd_price_feed_address,
{"from": account},
publish_source=config["networks"][network.show_active()].get("verify", False),
)
if (config["networks"][network.show_active()].get("verify", False)):
price_feed.tx.wait(BLOCK_CONFIRMATIONS_FOR_VERIFICATION)
PriceFeedConsumer.publish_source(price_feed)
else:
price_feed.tx.wait(1)
print(f"The current price of ETH is {price_feed.getLatestPrice()}")
return price_feed

Expand Down
9 changes: 7 additions & 2 deletions scripts/vrf_scripts/01_deploy_vrf.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,20 @@ def depoly_vrf():
vrf_coordinator = get_contract("vrf_coordinator")
link_token = get_contract("link_token")

return VRFConsumer.deploy(
vrf_consumer = VRFConsumer.deploy(
keyhash,
vrf_coordinator,
link_token,
fee,
{"from": account},
publish_source=config["networks"][network.show_active()].get("verify", False),
)

if (config["networks"][network.show_active()].get("verify", False)):
vrf_consumer.tx.wait(BLOCK_CONFIRMATIONS_FOR_VERIFICATION)
VRFConsumer.publish_source(vrf_consumer)
else:
vrf_consumer.tx.wait(1)


def main():
depoly_vrf()
10 changes: 8 additions & 2 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from scripts.helpful_scripts import (
LOCAL_BLOCKCHAIN_ENVIRONMENTS,
)
from web3 import Web3


@pytest.fixture
Expand All @@ -24,7 +25,7 @@ def get_job_id():
if network.show_active() in LOCAL_BLOCKCHAIN_ENVIRONMENTS:
return 0
if network.show_active() in config["networks"]:
return config["networks"][network.show_active()]["jobId"]
return Web3.toHex(text=config["networks"][network.show_active()]["jobId"])
else:
pytest.skip("Invalid network/link token specified")

Expand All @@ -46,7 +47,12 @@ def node_account():

@pytest.fixture
def chainlink_fee():
return 1000000000000000000
if network.show_active() in LOCAL_BLOCKCHAIN_ENVIRONMENTS:
return 1000000000000000000
if network.show_active() in config["networks"]:
return config["networks"][network.show_active()]["fee"]
else:
pytest.skip("Invalid network/link token specified ")


@pytest.fixture
Expand Down
32 changes: 23 additions & 9 deletions tests/test_api_consumer.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import time

import pytest
from brownie import APIConsumer, network
from scripts.helpful_scripts import LOCAL_BLOCKCHAIN_ENVIRONMENTS, get_account
from scripts.helpful_scripts import get_contract
from brownie import APIConsumer, network, config
from scripts.helpful_scripts import (
LOCAL_BLOCKCHAIN_ENVIRONMENTS,
get_account,
listen_for_event,
get_contract,
fund_with_link
)


@pytest.fixture
Expand All @@ -16,6 +21,10 @@ def deploy_api_contract(get_job_id, chainlink_fee):
get_contract("link_token").address,
{"from": get_account()},
)
block_confirmations=6
if network.show_active() in LOCAL_BLOCKCHAIN_ENVIRONMENTS:
block_confirmations=1
api_consumer.tx.wait(block_confirmations)
# Assert
assert api_consumer is not None
return api_consumer
Expand Down Expand Up @@ -43,20 +52,25 @@ def test_send_api_request_local(
assert isinstance(api_contract.volume(), int)
assert api_contract.volume() > 0


def test_send_api_request_testnet(deploy_api_contract, chainlink_fee):
# Arrange
if network.show_active() not in ["kovan", "rinkeby", "mainnet"]:
pytest.skip("Only for local testing")
api_contract = deploy_api_contract
get_contract("link_token").transfer(
api_contract.address, chainlink_fee * 2, {"from": get_account()}

if (config["networks"][network.show_active()].get("verify", False)):
APIConsumer.publish_source(api_contract)

tx = fund_with_link(
api_contract.address, amount=chainlink_fee
)
tx.wait(1)
# Act
transaction = api_contract.requestVolumeData({"from": get_account()})
transaction.wait(1)

# Assert
assert transaction is not None
transaction.wait(2)
time.sleep(35)
event_response = listen_for_event(api_contract, "DataFullfilled")
assert event_response.event is not None
assert isinstance(api_contract.volume(), int)
assert api_contract.volume() > 0
Loading

0 comments on commit 7acf170

Please sign in to comment.