Skip to content

Commit 1df2ff9

Browse files
committed
fixed function selectors on dynamic arrays, added scripts to "see" the whole process end to end
1 parent 1f313bb commit 1df2ff9

File tree

8 files changed

+162
-7
lines changed

8 files changed

+162
-7
lines changed

README.md

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ It shows how to use the these frameworks and languages as well as the following
3030
- [Deploy to a local or adhoc network](#deploy-to-a-local-or-adhoc-network)
3131
- [Deploy to a mainnet or test network](#deploy-to-a-mainnet-or-test-network)
3232
- [Interacting with Contracts](#interacting-with-contracts)
33+
- [Price Feed Consumer](#price-feed-consumer-1)
34+
- [VRF Consumer](#vrf-consumer)
35+
- [Keeper Consumer](#keeper-consumer)
3336
- [Miscellaneous](#miscellaneous)
3437
- [Contributing](#contributing)
3538
- [Resources](#resources)
@@ -189,6 +192,77 @@ To interact with contracts, we recommend using the console.
189192
ape console --network ethereum:rinkeby:alchemy
190193
```
191194

195+
Or, you can follow along and run the scripts to see the end-to-end functionaltiy.
196+
197+
#### Price Feed Consumer
198+
199+
1. Deploy the contract
200+
201+
```
202+
ape run scripts/deploy_price_feed_consumer.py --network ethereum:rinkeby:alchemy
203+
```
204+
205+
2. Read it
206+
207+
```
208+
ape run scripts/read_price_feed.py --network ethereum:rinkeby:alchemy
209+
```
210+
211+
212+
213+
#### VRF Consumer
214+
215+
1. Create subscription and fund it with LINK.
216+
217+
You can do that with the script, or going to the UI at [vrf.chain.link](https://vrf.chain.link)
218+
219+
```
220+
ape run scripts/create_subscription.py --network ethereum:rinkeby:alchemy
221+
```
222+
223+
2. Update your `helper_config.py` with your subscription Id.
224+
225+
3. Deploy vrf consumer
226+
227+
```
228+
ape run scripts/deploy_vrf_consumer.py --network ethereum:rinkeby:alchemy
229+
```
230+
231+
4. [Add your contract/consumer to the VRF UI](https://docs.chain.link/docs/get-a-random-number/#create-and-fund-a-subscription)
232+
233+
234+
5. Request a random number and wait for a response
235+
236+
237+
```
238+
ape run scripts/request_and_read_randomness.py --network ethereum:rinkeby:alchemy
239+
```
240+
241+
#### Keeper Consumer
242+
243+
1. Deploy the contract
244+
245+
```
246+
ape run scripts/deploy_keepers_consumer.py --network ethereum:rinkeby:alchemy
247+
```
248+
249+
2. Register your upkeep on the Keepers UI
250+
251+
You can go to [keepers.chain.link](https://keepers.chain.link/new-custom-logic)
252+
253+
3. Watch for your counter to automatically start going up!
254+
255+
After a delay, run:
256+
257+
```
258+
ape run scripts/read_counter.py --network ethereum:rinkeby:alchemy
259+
```
260+
261+
And it should be updated!
262+
263+
264+
265+
192266
# Miscellaneous
193267

194268
1. Testing and forking is a bit tricky at the moment.

contracts/KeepersConsumer.vy

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ def __init__(update_interval: uint256):
1313

1414
@external
1515
@view
16-
def checkUpkeep(checkData: Bytes[1]) -> (bool, Bytes[1]):
16+
def checkUpkeep(checkData: Bytes[32]) -> (bool, Bytes[32]):
1717
upkeep_needed: bool = (block.timestamp - self.last_time_stamp) > INTERVAL
1818
return(upkeep_needed, b"\x00")
1919

contracts/VRFConsumerV2.vy

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import interfaces.VRFCoordinatorV2 as VRFCoordinatorV2
44

55
NUM_WORDS: constant(uint32) = 1
6+
MAX_ARRAY_SIZE: constant(uint256) = 10
67
REQUEST_CONFIRMATIONS: constant(uint16) = 3
78
CALLBACK_GAS_LIMIT: constant(uint32) = 100000
89

@@ -31,13 +32,19 @@ def request_random_words():
3132
)
3233

3334
@internal
34-
def fulfillRandomWords(request_id: uint256, _random_words: uint256[NUM_WORDS]):
35-
self.random_words = _random_words
36-
log ReturnedRandomness(_random_words)
35+
def fulfillRandomWords(request_id: uint256, _random_words: DynArray[uint256, MAX_ARRAY_SIZE]):
36+
self.random_words = [_random_words[0]]
37+
log ReturnedRandomness(self.random_words)
3738

3839
# In solidity, this is the equivalent of inheriting the VRFConsumerBaseV2
3940
# Vyper doesn't have inheritance, so we just add the function here
41+
# Also, we need to use `DynArray` so our function selector is the same as the one Chainlink VRF is looking for:
42+
# Function Signature: rawFulfillRandomWords(uint256,uint256[])
43+
# Function selector: 0x1fe543e3
4044
@external
41-
def rawFulfillRandomWords(requestId: uint256, randomWords: uint256[NUM_WORDS]):
45+
def rawFulfillRandomWords(requestId: uint256, randomWords: DynArray[uint256, MAX_ARRAY_SIZE]):
4246
assert msg.sender == self.vrf_coordinator.address, "Only coordinator can fulfill!"
43-
self.fulfillRandomWords(requestId, randomWords)
47+
myBytes: Bytes[4] = b"\x00"
48+
myString: String[4] = convert(myBytes, String[4])
49+
self.fulfillRandomWords(requestId, randomWords)
50+

scripts/create_subscription.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ def create_subscription():
2929

3030
def fund_subscription(subscription_id=1):
3131
print("Funding subscription...")
32+
ecosystem = networks.active_provider.network.ecosystem.name
33+
chain_name = networks.active_provider.network.name
3234
account = get_account()
3335
fund_amount = network_config[ecosystem][chain_name].get("fund_amount", False)
3436
link_token = get_or_deploy_contract("LinkToken")

scripts/helper_config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"fund_amount": 5_000000000000000000,
1414
},
1515
"rinkeby": {
16-
"subscription_id": 0, # Add your own subscription Id here!
16+
"subscription_id": 9757, # Add your own subscription Id here!
1717
"key_hash": "0xd89b2bf150e3b9e13446986e571fb9cab24b13cea0a43ea20a6049a85cc807cc",
1818
"update_interval": 60,
1919
"fund_amount": 5_000000000000000000,

scripts/read_counter.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from ape import project, accounts, networks
2+
from scripts.helper_functions import get_account, get_or_deploy_contract
3+
4+
5+
def read_counter():
6+
account = get_account()
7+
ecosystem = networks.active_provider.network.ecosystem.name
8+
chain_name = networks.active_provider.network.name
9+
10+
keepers_consumer = project.KeepersConsumer.deployments[-1]
11+
response = keepers_consumer.counter()
12+
print(f"The current count is {response}")
13+
return keepers_consumer
14+
15+
16+
def main():
17+
read_counter()

scripts/read_price_feed.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from ape import project, accounts, networks
2+
from scripts.helper_functions import get_account, get_or_deploy_contract
3+
4+
5+
def read_price_feed():
6+
account = get_account()
7+
ecosystem = networks.active_provider.network.ecosystem.name
8+
chain_name = networks.active_provider.network.name
9+
10+
price_feed_consumer = project.PriceConsumer.deployments[-1]
11+
response = price_feed_consumer.get_latest_price()
12+
print(f"The current price of ETH is {response}")
13+
return price_feed_consumer
14+
15+
16+
def main():
17+
read_price_feed()
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
from ape import project, accounts, networks
2+
from scripts.helper_functions import get_account, get_or_deploy_contract
3+
import time
4+
5+
6+
def request_and_read_randomness():
7+
account = get_account()
8+
ecosystem = networks.active_provider.network.ecosystem.name
9+
chain_name = networks.active_provider.network.name
10+
11+
vrf_consumer = project.VRConsumerV2.deployments[-1]
12+
request_tx = vrf_consumer.request_random_words(sender=account)
13+
14+
print("Request sent! Let's wait for a response...")
15+
16+
randomness = wait_for_randomness(vrf_consumer)
17+
if randomness:
18+
print(f"The random number was {randomness}")
19+
else:
20+
print("No random number found")
21+
22+
23+
def wait_for_randomness(vrf_consumer, timeout=200, poll_interval=2):
24+
print("Waiting for random response...")
25+
start_time = time.time()
26+
current_time = time.time()
27+
while current_time - start_time < timeout:
28+
response = vrf_consumer.random_words(0)
29+
if response > 0:
30+
return response
31+
time.sleep(poll_interval)
32+
current_time = time.time()
33+
print("Done waiting!")
34+
return None
35+
36+
37+
def main():
38+
request_and_read_randomness()

0 commit comments

Comments
 (0)