From e9ddf82ebef7db9db480d9be0b799a1d87eb8374 Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Thu, 18 Mar 2021 15:02:23 -0400 Subject: [PATCH 1/3] updated for tests --- contracts/Migrations.sol | 2 +- contracts/MyContract.sol | 2 +- contracts/PriceConsumerV3.sol | 6 +-- contracts/RandomNumberConsumer.sol | 15 ++++--- contracts/mocks/MockV3Aggregator.sol | 4 ++ contracts/mocks/VRFCoordinatorMock.sol | 4 ++ migrations/3_price_consumer_v3.js | 6 ++- migrations/4_random_number_consumer.js | 15 +++---- .../get-latest-price.js | 6 +-- test/PriceConsumerV3_test.js | 15 ++++--- test/RandomNumberConsumer_test.js | 43 +++++++++++++++++++ test/RandomNumberConsumer_text.js | 26 ----------- truffle-config.js | 4 +- 13 files changed, 92 insertions(+), 56 deletions(-) create mode 100644 contracts/mocks/MockV3Aggregator.sol create mode 100644 contracts/mocks/VRFCoordinatorMock.sol create mode 100644 test/RandomNumberConsumer_test.js delete mode 100644 test/RandomNumberConsumer_text.js diff --git a/contracts/Migrations.sol b/contracts/Migrations.sol index 0dc2c26..05db001 100644 --- a/contracts/Migrations.sol +++ b/contracts/Migrations.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.6.12; +pragma solidity ^0.6.6; contract Migrations { address public owner; diff --git a/contracts/MyContract.sol b/contracts/MyContract.sol index 3042c92..00fcaf7 100644 --- a/contracts/MyContract.sol +++ b/contracts/MyContract.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.6.12; +pragma solidity ^0.6.6; import "@chainlink/contracts/src/v0.6/ChainlinkClient.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; diff --git a/contracts/PriceConsumerV3.sol b/contracts/PriceConsumerV3.sol index 9719e5d..389348c 100644 --- a/contracts/PriceConsumerV3.sol +++ b/contracts/PriceConsumerV3.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.6.12; +pragma solidity ^0.6.6; import "@chainlink/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol"; @@ -11,8 +11,8 @@ contract PriceConsumerV3 { * Aggregator: ETH/USD * Address: 0x9326BFA02ADD2366b30bacB125260Af641031331 */ - constructor() public { - priceFeed = AggregatorV3Interface(0x9326BFA02ADD2366b30bacB125260Af641031331); + constructor(address _priceFeed) public { + priceFeed = AggregatorV3Interface(_priceFeed); } /** diff --git a/contracts/RandomNumberConsumer.sol b/contracts/RandomNumberConsumer.sol index 5ffd8ef..c90cfae 100644 --- a/contracts/RandomNumberConsumer.sol +++ b/contracts/RandomNumberConsumer.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.6.12; +pragma solidity ^0.6.6; import "@chainlink/contracts/src/v0.6/VRFConsumerBase.sol"; @@ -8,6 +8,7 @@ contract RandomNumberConsumer is VRFConsumerBase { bytes32 internal keyHash; uint256 internal fee; uint256 public randomResult; + bytes32 public lastRequestId; /** * Constructor inherits VRFConsumerBase @@ -17,22 +18,24 @@ contract RandomNumberConsumer is VRFConsumerBase { * LINK token address: 0xa36085F69e2889c224210F603D836748e7dC0088 * Key Hash: 0x6c3699283bda56ad74f6b855546325b68d482e983852a7a82979cc4807b641f4 */ - constructor(address _linkTokenAddress) + constructor(address _linkTokenAddress, bytes32 _keyHash, address _vrfCoordinatorAddress, uint256 _fee) public VRFConsumerBase( - 0xdD3782915140c8f3b190B5D67eAc6dc5760C46E9, // VRF Coordinator + _vrfCoordinatorAddress, // VRF Coordinator _linkTokenAddress // LINK Token ) { - keyHash = 0x6c3699283bda56ad74f6b855546325b68d482e983852a7a82979cc4807b641f4; - fee = 0.1 * 10 ** 18; // 0.1 LINK + keyHash = _keyHash; + fee = _fee; + // fee = 0.1 * 10 ** 18; // 0.1 LINK } /** * Requests randomness from a user-provided seed */ function getRandomNumber(uint256 userProvidedSeed) public returns (bytes32 requestId) { - return requestRandomness(keyHash, fee, userProvidedSeed); + lastRequestId = requestRandomness(keyHash, fee, userProvidedSeed); + return lastRequestId; } /** diff --git a/contracts/mocks/MockV3Aggregator.sol b/contracts/mocks/MockV3Aggregator.sol new file mode 100644 index 0000000..572712f --- /dev/null +++ b/contracts/mocks/MockV3Aggregator.sol @@ -0,0 +1,4 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@chainlink/contracts/src/v0.6/tests/MockV3Aggregator.sol"; diff --git a/contracts/mocks/VRFCoordinatorMock.sol b/contracts/mocks/VRFCoordinatorMock.sol new file mode 100644 index 0000000..ab122bb --- /dev/null +++ b/contracts/mocks/VRFCoordinatorMock.sol @@ -0,0 +1,4 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + +import "@chainlink/contracts/src/v0.6/tests/VRFCoordinatorMock.sol"; diff --git a/migrations/3_price_consumer_v3.js b/migrations/3_price_consumer_v3.js index 2b0577d..bc1ea22 100644 --- a/migrations/3_price_consumer_v3.js +++ b/migrations/3_price_consumer_v3.js @@ -1,10 +1,14 @@ const PriceConsumerV3 = artifacts.require('PriceConsumerV3') +const KOVAN_ETH_USD_PRICE_FEED = '0x9326BFA02ADD2366b30bacB125260Af641031331' module.exports = async (deployer, network, [defaultAccount]) => { // Local (development) networks need their own deployment of the LINK // token and the Oracle contract + + // currently hardcoded for Kovan + let priceFeedAddress = KOVAN_ETH_USD_PRICE_FEED try { - await deployer.deploy(PriceConsumerV3, { from: defaultAccount }) + await deployer.deploy(PriceConsumerV3, KOVAN_ETH_USD_PRICE_FEED, { from: defaultAccount }) } catch (err) { console.error(err) } diff --git a/migrations/4_random_number_consumer.js b/migrations/4_random_number_consumer.js index 73537ba..560f63c 100644 --- a/migrations/4_random_number_consumer.js +++ b/migrations/4_random_number_consumer.js @@ -1,19 +1,18 @@ const RandomNumberConsumer = artifacts.require('RandomNumberConsumer') +const VRFCoordinatorMock = artifacts.require('VRFCoordinatorMock') const { LinkToken } = require('@chainlink/contracts/truffle/v0.4/LinkToken') module.exports = async (deployer, network, [defaultAccount]) => { // Local (development) networks need their own deployment of the LINK // token and the Oracle contract if (!network.startsWith('kovan')) { - LinkToken.setProvider(deployer.provider) - try { - await deployer.deploy(LinkToken, { from: defaultAccount }) - await deployer.deploy(RandomNumberConsumer, LinkToken.address) - } catch (err) { - console.error(err) - } + console.log("only for Kovan right now!") } else { // For now, this is hard coded to Kovan - deployer.deploy(RandomNumberConsumer, '0xa36085F69e2889c224210F603D836748e7dC0088') + const KOVAN_KEYHASH = '0x6c3699283bda56ad74f6b855546325b68d482e983852a7a82979cc4807b641f4' + const KOVAN_FEE = '100000000000000000' + const KOVAN_LINK_TOKEN = '0xa36085F69e2889c224210F603D836748e7dC0088' + const KOVAN_VRF_COORDINATOR = '0xdD3782915140c8f3b190B5D67eAc6dc5760C46E9' + deployer.deploy(RandomNumberConsumer, KOVAN_LINK_TOKEN, KOVAN_KEYHASH, KOVAN_VRF_COORDINATOR, KOVAN_FEE) } } diff --git a/scripts/price-consumer-scripts/get-latest-price.js b/scripts/price-consumer-scripts/get-latest-price.js index ed1f56a..4399939 100644 --- a/scripts/price-consumer-scripts/get-latest-price.js +++ b/scripts/price-consumer-scripts/get-latest-price.js @@ -6,7 +6,7 @@ const PriceConsumerV3 = artifacts.require('PriceConsumerV3') */ module.exports = async callback => { - const priceConsumerV3 = await PriceConsumerV3.deployed() - const latestPrice = await priceConsumerV3.getLatestPrice() - callback(latestPrice) + const priceConsumerV3 = await PriceConsumerV3.deployed() + const latestPrice = await priceConsumerV3.getLatestPrice() + callback(latestPrice) } diff --git a/test/PriceConsumerV3_test.js b/test/PriceConsumerV3_test.js index b681a72..970d50d 100644 --- a/test/PriceConsumerV3_test.js +++ b/test/PriceConsumerV3_test.js @@ -3,23 +3,28 @@ This repo is for testing on kovan network only. You can get truffle teams and do a forking version of these tests. - */ +const { assert } = require('chai') + contract('PriceConsumerV3', accounts => { + const MockPriceFeed = artifacts.require('MockV3Aggregator') const PriceConsumerV3 = artifacts.require('PriceConsumerV3') const defaultAccount = accounts[0] // The addresses here can be found in the chainlink docs // https://docs.chain.link/docs/ethereum-addresses - let priceConsumerV3 + let priceConsumerV3, mockPriceFeed - // TODO describe('#getLatestPrice', () => { + let price = "2000000000000000000" + beforeEach(async () => { + mockPriceFeed = await MockPriceFeed.new(8, price) + priceConsumerV3 = await PriceConsumerV3.new(mockPriceFeed.address) + }) it('returns a price', async () => { - priceConsumerV3 = await PriceConsumerV3.new() - assert(true, true) + assert.equal(await priceConsumerV3.getLatestPrice(), price) }) }) }) diff --git a/test/RandomNumberConsumer_test.js b/test/RandomNumberConsumer_test.js new file mode 100644 index 0000000..b92daed --- /dev/null +++ b/test/RandomNumberConsumer_test.js @@ -0,0 +1,43 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ +const { expectRevert } = require('@openzeppelin/test-helpers') +const { assert } = require('chai') + +contract('RandomNumberConsumer', accounts => { + const RandomNumberConsumer = artifacts.require('RandomNumberConsumer') + const VRFCoordinatorMock = artifacts.require('VRFCoordinatorMock') + const { LinkToken } = require('@chainlink/contracts/truffle/v0.4/LinkToken') + const defaultAccount = accounts[0] + let randomNumberConsumer, vrfCoordinatorMock, seed, link, keyhash, fee + + describe('#request random number', () => { + beforeEach(async () => { + keyhash = '0x6c3699283bda56ad74f6b855546325b68d482e983852a7a82979cc4807b641f4' + fee = '1000000000000000000' + link = await LinkToken.new({ from: defaultAccount }) + vrfCoordinatorMock = await VRFCoordinatorMock.new(link.address, { from: defaultAccount }) + randomNumberConsumer = await RandomNumberConsumer.new(link.address, keyhash, vrfCoordinatorMock.address, fee, { from: defaultAccount }) + seed = 1 + }) + it('reverts without LINK', async () => { + await expectRevert.unspecified( + randomNumberConsumer.getRandomNumber(seed, { + from: defaultAccount, + }), + ) + }) + it('#can request and return a random number', async () => { + await link.transfer(randomNumberConsumer.address, web3.utils.toWei('1', 'ether'), { + from: defaultAccount, + }) + let tx = await randomNumberConsumer.getRandomNumber(seed, { from: defaultAccount }) + // just checking that is has logs + // console.log(tx.receipt.rawLogs) + assert.exists(tx.receipt.rawLogs, 'The tx hasnt been made!') + let requestId = await randomNumberConsumer.lastRequestId({ from: defaultAccount }) + await vrfCoordinatorMock.callBackWithRandomness(requestId, '777', randomNumberConsumer.address, { from: defaultAccount }) + let randomNumber = await randomNumberConsumer.randomResult({ from: defaultAccount }) + assert.equal(randomNumber, 777) + }) + + }) +}) diff --git a/test/RandomNumberConsumer_text.js b/test/RandomNumberConsumer_text.js deleted file mode 100644 index 6f1b71e..0000000 --- a/test/RandomNumberConsumer_text.js +++ /dev/null @@ -1,26 +0,0 @@ -/* eslint-disable @typescript-eslint/no-var-requires */ -const { expectRevert } = require('@openzeppelin/test-helpers') -contract('RandomNumberConsumer', accounts => { - const RandomNumberConsumer = artifacts.require('RandomNumberConsumer') - const { LinkToken } = require('@chainlink/contracts/truffle/v0.4/LinkToken') - const defaultAccount = accounts[0] - let randomNumberConsumer, seed, link - - beforeEach(async () => { - link = await LinkToken.new({ from: defaultAccount }) - randomNumberConsumer = await RandomNumberConsumer.new(link.address, { from: defaultAccount }) - seed = 1 - }) - - // TODO - describe('#request random number', () => { - it('reverts without LINK', async () => { - await expectRevert.unspecified( - randomNumberConsumer.getRandomNumber(seed, { - from: defaultAccount, - }), - ) - }) - - }) -}) diff --git a/truffle-config.js b/truffle-config.js index c37780b..13f56ce 100644 --- a/truffle-config.js +++ b/truffle-config.js @@ -1,5 +1,5 @@ const HDWalletProvider = require('@truffle/hdwallet-provider') -require('dotenv').config(); +require('dotenv').config() const mnemonic = process.env.MNEMONIC const url = process.env.RPC_URL @@ -26,7 +26,7 @@ module.exports = { }, compilers: { solc: { - version: '0.6.12', + version: '0.6.6', }, }, } From 1b8e4ba7fc45bf3c21f7ece7d60ae77963c98792 Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Thu, 18 Mar 2021 21:04:19 -0400 Subject: [PATCH 2/3] added events for logging random number --- contracts/RandomNumberConsumer.sol | 10 ++++--- .../{mocks => test}/MockV3Aggregator.sol | 0 .../{mocks => test}/VRFCoordinatorMock.sol | 0 test/RandomNumberConsumer_test.js | 28 ++++++++----------- 4 files changed, 17 insertions(+), 21 deletions(-) rename contracts/{mocks => test}/MockV3Aggregator.sol (100%) rename contracts/{mocks => test}/VRFCoordinatorMock.sol (100%) diff --git a/contracts/RandomNumberConsumer.sol b/contracts/RandomNumberConsumer.sol index c90cfae..7d492d2 100644 --- a/contracts/RandomNumberConsumer.sol +++ b/contracts/RandomNumberConsumer.sol @@ -8,7 +8,7 @@ contract RandomNumberConsumer is VRFConsumerBase { bytes32 internal keyHash; uint256 internal fee; uint256 public randomResult; - bytes32 public lastRequestId; + event RequestedRandomness(bytes32 requestId); /** * Constructor inherits VRFConsumerBase @@ -18,7 +18,8 @@ contract RandomNumberConsumer is VRFConsumerBase { * LINK token address: 0xa36085F69e2889c224210F603D836748e7dC0088 * Key Hash: 0x6c3699283bda56ad74f6b855546325b68d482e983852a7a82979cc4807b641f4 */ - constructor(address _linkTokenAddress, bytes32 _keyHash, address _vrfCoordinatorAddress, uint256 _fee) + constructor(address _linkTokenAddress, bytes32 _keyHash, + address _vrfCoordinatorAddress, uint256 _fee) public VRFConsumerBase( _vrfCoordinatorAddress, // VRF Coordinator @@ -34,8 +35,9 @@ contract RandomNumberConsumer is VRFConsumerBase { * Requests randomness from a user-provided seed */ function getRandomNumber(uint256 userProvidedSeed) public returns (bytes32 requestId) { - lastRequestId = requestRandomness(keyHash, fee, userProvidedSeed); - return lastRequestId; + requestId = requestRandomness(keyHash, fee, userProvidedSeed); + emit RequestedRandomness(requestId); + return requestId; } /** diff --git a/contracts/mocks/MockV3Aggregator.sol b/contracts/test/MockV3Aggregator.sol similarity index 100% rename from contracts/mocks/MockV3Aggregator.sol rename to contracts/test/MockV3Aggregator.sol diff --git a/contracts/mocks/VRFCoordinatorMock.sol b/contracts/test/VRFCoordinatorMock.sol similarity index 100% rename from contracts/mocks/VRFCoordinatorMock.sol rename to contracts/test/VRFCoordinatorMock.sol diff --git a/test/RandomNumberConsumer_test.js b/test/RandomNumberConsumer_test.js index b92daed..89027d3 100644 --- a/test/RandomNumberConsumer_test.js +++ b/test/RandomNumberConsumer_test.js @@ -1,6 +1,5 @@ -/* eslint-disable @typescript-eslint/no-var-requires */ -const { expectRevert } = require('@openzeppelin/test-helpers') const { assert } = require('chai') +const { expectRevert } = require('@openzeppelin/test-helpers') contract('RandomNumberConsumer', accounts => { const RandomNumberConsumer = artifacts.require('RandomNumberConsumer') @@ -13,31 +12,26 @@ contract('RandomNumberConsumer', accounts => { beforeEach(async () => { keyhash = '0x6c3699283bda56ad74f6b855546325b68d482e983852a7a82979cc4807b641f4' fee = '1000000000000000000' + seed = 123 link = await LinkToken.new({ from: defaultAccount }) vrfCoordinatorMock = await VRFCoordinatorMock.new(link.address, { from: defaultAccount }) randomNumberConsumer = await RandomNumberConsumer.new(link.address, keyhash, vrfCoordinatorMock.address, fee, { from: defaultAccount }) - seed = 1 }) - it('reverts without LINK', async () => { + it('it revert without LINK', async () => { await expectRevert.unspecified( - randomNumberConsumer.getRandomNumber(seed, { - from: defaultAccount, - }), + randomNumberConsumer.getRandomNumber(seed, { from: defaultAccount }) ) }) - it('#can request and return a random number', async () => { - await link.transfer(randomNumberConsumer.address, web3.utils.toWei('1', 'ether'), { - from: defaultAccount, - }) - let tx = await randomNumberConsumer.getRandomNumber(seed, { from: defaultAccount }) - // just checking that is has logs - // console.log(tx.receipt.rawLogs) - assert.exists(tx.receipt.rawLogs, 'The tx hasnt been made!') - let requestId = await randomNumberConsumer.lastRequestId({ from: defaultAccount }) + it('returns a random number with link', async () => { + await link.transfer(randomNumberConsumer.address, web3.utils.toWei('1', 'ether'), { from: defaultAccount }) + let transaction = await randomNumberConsumer.getRandomNumber(seed, { from: defaultAccount }) + assert.exists(transaction.receipt.rawLogs) + // This is the event that is emitted + let requestId = transaction.receipt.rawLogs[3].topics[0] + // let requestId = await randomNumberConsumer.lastRequestId({ from: defaultAccount }) await vrfCoordinatorMock.callBackWithRandomness(requestId, '777', randomNumberConsumer.address, { from: defaultAccount }) let randomNumber = await randomNumberConsumer.randomResult({ from: defaultAccount }) assert.equal(randomNumber, 777) }) - }) }) From 45a3783cbff2ed9a67bd5b8d2bbb71dd1f09267e Mon Sep 17 00:00:00 2001 From: PatrickAlphaC <54278053+PatrickAlphaC@users.noreply.github.com> Date: Fri, 19 Mar 2021 14:25:40 -0400 Subject: [PATCH 3/3] removed unneeded variables --- contracts/RandomNumberConsumer.sol | 2 -- migrations/4_random_number_consumer.js | 2 -- 2 files changed, 4 deletions(-) diff --git a/contracts/RandomNumberConsumer.sol b/contracts/RandomNumberConsumer.sol index 7d492d2..0f4971a 100644 --- a/contracts/RandomNumberConsumer.sol +++ b/contracts/RandomNumberConsumer.sol @@ -28,7 +28,6 @@ contract RandomNumberConsumer is VRFConsumerBase { { keyHash = _keyHash; fee = _fee; - // fee = 0.1 * 10 ** 18; // 0.1 LINK } /** @@ -37,7 +36,6 @@ contract RandomNumberConsumer is VRFConsumerBase { function getRandomNumber(uint256 userProvidedSeed) public returns (bytes32 requestId) { requestId = requestRandomness(keyHash, fee, userProvidedSeed); emit RequestedRandomness(requestId); - return requestId; } /** diff --git a/migrations/4_random_number_consumer.js b/migrations/4_random_number_consumer.js index 560f63c..f2ac01e 100644 --- a/migrations/4_random_number_consumer.js +++ b/migrations/4_random_number_consumer.js @@ -1,6 +1,4 @@ const RandomNumberConsumer = artifacts.require('RandomNumberConsumer') -const VRFCoordinatorMock = artifacts.require('VRFCoordinatorMock') -const { LinkToken } = require('@chainlink/contracts/truffle/v0.4/LinkToken') module.exports = async (deployer, network, [defaultAccount]) => { // Local (development) networks need their own deployment of the LINK