From 5b96de44744a27217e14dc0d86fa31c4bca1f303 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Tue, 27 Jun 2023 16:38:13 +1000 Subject: [PATCH 1/5] update readme --- dapps/evm2/flipper/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dapps/evm2/flipper/README.md b/dapps/evm2/flipper/README.md index 77bd0ff..f4bc613 100644 --- a/dapps/evm2/flipper/README.md +++ b/dapps/evm2/flipper/README.md @@ -112,6 +112,12 @@ shasum -a 256 moonkey * Migrate full `truffle migrate --reset --compile-all --network moonbase` * Test * `truffle test --verbose-rpc --network moonbase` + +* Chainlink VRF https://docs.chain.link/getting-started/intermediates-tutorial + * View token balance https://sepolia.etherscan.io/address/0x1dd907abb024e17d196de0d7fe8eb507b6ccaae7 + * Create and fund a subscription https://docs.chain.link/vrf/v2/subscription/examples/get-a-random-number/#create-and-fund-a-subscription + * Prepay Subscription https://vrf.chain.link/ + * Troubleshooting * `Client network socket disconnected before secure TLS connection was established` * Try fixing by running `unset https_proxy && unset http_proxy`, but this didn't actually work for me From 3b01dd06539fb986be4403e1fdab8b694c80b24e Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Wed, 28 Jun 2023 03:38:04 +1000 Subject: [PATCH 2/5] add vrf template contracts --- .../lib/VRFRandomNumberChainlink.sol | 172 ++++++++++++++++++ .../contracts/vrf/VRFConsumerBaseV2.sol | 135 ++++++++++++++ .../interfaces/VRFCoordinatorV2Interface.sol | 114 ++++++++++++ 3 files changed, 421 insertions(+) create mode 100644 dapps/evm2/flipper/contracts/lib/VRFRandomNumberChainlink.sol create mode 100644 dapps/evm2/flipper/contracts/vrf/VRFConsumerBaseV2.sol create mode 100644 dapps/evm2/flipper/contracts/vrf/interfaces/VRFCoordinatorV2Interface.sol diff --git a/dapps/evm2/flipper/contracts/lib/VRFRandomNumberChainlink.sol b/dapps/evm2/flipper/contracts/lib/VRFRandomNumberChainlink.sol new file mode 100644 index 0000000..0a12fc9 --- /dev/null +++ b/dapps/evm2/flipper/contracts/lib/VRFRandomNumberChainlink.sol @@ -0,0 +1,172 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.7; + +import "@chainlink/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol"; +import "@chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol"; + +/** + * @notice A Chainlink VRF consumer which uses randomness to mimic the rolling + * of a 20 sided dice + */ + +/** + * Request testnet LINK and ETH here: https://faucets.chain.link/ + * Find information on LINK Token Contracts and get the latest ETH and LINK faucets here: https://docs.chain.link/docs/link-token-contracts/ + */ + +/** + * THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY. + * THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE. + * DO NOT USE THIS CODE IN PRODUCTION. + */ + +contract VRFD20 is VRFConsumerBaseV2 { + uint256 private constant ROLL_IN_PROGRESS = 42; + + VRFCoordinatorV2Interface COORDINATOR; + + // Your subscription ID. + uint64 s_subscriptionId; + + // Sepolia coordinator. For other networks, + // see https://docs.chain.link/docs/vrf-contracts/#configurations + address vrfCoordinator = 0x8103B0A8A00be2DDC778e6e7eaa21791Cd364625; + + // The gas lane to use, which specifies the maximum gas price to bump to. + // For a list of available gas lanes on each network, + // see https://docs.chain.link/docs/vrf-contracts/#configurations + bytes32 s_keyHash = + 0x474e34a077df58807dbe9c96d3c009b23b3c6d0cce433e59bbf5b34f823bc56c; + + // Depends on the number of requested values that you want sent to the + // fulfillRandomWords() function. Storing each word costs about 20,000 gas, + // so 40,000 is a safe default for this example contract. Test and adjust + // this limit based on the network that you select, the size of the request, + // and the processing of the callback request in the fulfillRandomWords() + // function. + uint32 callbackGasLimit = 40000; + + // The default is 3, but you can set this higher. + uint16 requestConfirmations = 3; + + // For this example, retrieve 1 random value in one request. + // Cannot exceed VRFCoordinatorV2.MAX_NUM_WORDS. + uint32 numWords = 1; + address s_owner; + + // map rollers to requestIds + mapping(uint256 => address) private s_rollers; + // map vrf results to rollers + mapping(address => uint256) private s_results; + + event DiceRolled(uint256 indexed requestId, address indexed roller); + event DiceLanded(uint256 indexed requestId, uint256 indexed result); + + /** + * @notice Constructor inherits VRFConsumerBaseV2 + * + * @dev NETWORK: Sepolia + * + * @param subscriptionId subscription id that this consumer contract can use + */ + constructor(uint64 subscriptionId) VRFConsumerBaseV2(vrfCoordinator) { + COORDINATOR = VRFCoordinatorV2Interface(vrfCoordinator); + s_owner = msg.sender; + s_subscriptionId = subscriptionId; + } + + /** + * @notice Requests randomness + * @dev Warning: if the VRF response is delayed, avoid calling requestRandomness repeatedly + * as that would give miners/VRF operators latitude about which VRF response arrives first. + * @dev You must review your implementation details with extreme care. + * + * @param roller address of the roller + */ + function rollDice( + address roller + ) public onlyOwner returns (uint256 requestId) { + require(s_results[roller] == 0, "Already rolled"); + // Will revert if subscription is not set and funded. + requestId = COORDINATOR.requestRandomWords( + s_keyHash, + s_subscriptionId, + requestConfirmations, + callbackGasLimit, + numWords + ); + + s_rollers[requestId] = roller; + s_results[roller] = ROLL_IN_PROGRESS; + emit DiceRolled(requestId, roller); + } + + /** + * @notice Callback function used by VRF Coordinator to return the random number to this contract. + * + * @dev Some action on the contract state should be taken here, like storing the result. + * @dev WARNING: take care to avoid having multiple VRF requests in flight if their order of arrival would result + * in contract states with different outcomes. Otherwise miners or the VRF operator would could take advantage + * by controlling the order. + * @dev The VRF Coordinator will only send this function verified responses, and the parent VRFConsumerBaseV2 + * contract ensures that this method only receives randomness from the designated VRFCoordinator. + * + * @param requestId uint256 + * @param randomWords uint256[] The random result returned by the oracle. + */ + function fulfillRandomWords( + uint256 requestId, + uint256[] memory randomWords + ) internal override { + uint256 d20Value = (randomWords[0] % 20) + 1; + s_results[s_rollers[requestId]] = d20Value; + emit DiceLanded(requestId, d20Value); + } + + /** + * @notice Get the house assigned to the player once the address has rolled + * @param player address + * @return house as a string + */ + function house(address player) public view returns (string memory) { + require(s_results[player] != 0, "Dice not rolled"); + require(s_results[player] != ROLL_IN_PROGRESS, "Roll in progress"); + return getHouseName(s_results[player]); + } + + /** + * @notice Get the house name from the id + * @param id uint256 + * @return house name string + */ + function getHouseName(uint256 id) private pure returns (string memory) { + string[20] memory houseNames = [ + "Targaryen", + "Lannister", + "Stark", + "Tyrell", + "Baratheon", + "Martell", + "Tully", + "Bolton", + "Greyjoy", + "Arryn", + "Frey", + "Mormont", + "Tarley", + "Dayne", + "Umber", + "Valeryon", + "Manderly", + "Clegane", + "Glover", + "Karstark" + ]; + return houseNames[id - 1]; + } + + modifier onlyOwner() { + require(msg.sender == s_owner); + _; + } +} diff --git a/dapps/evm2/flipper/contracts/vrf/VRFConsumerBaseV2.sol b/dapps/evm2/flipper/contracts/vrf/VRFConsumerBaseV2.sol new file mode 100644 index 0000000..f8d81a0 --- /dev/null +++ b/dapps/evm2/flipper/contracts/vrf/VRFConsumerBaseV2.sol @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.4; + +// Reference: https://github.com/smartcontractkit/chainlink/blob/master/contracts/src/v0.8/vrf/VRFConsumerBaseV2.sol + +/** **************************************************************************** + * @notice Interface for contracts using VRF randomness + * ***************************************************************************** + * @dev PURPOSE + * + * @dev Reggie the Random Oracle (not his real job) wants to provide randomness + * @dev to Vera the verifier in such a way that Vera can be sure he's not + * @dev making his output up to suit himself. Reggie provides Vera a public key + * @dev to which he knows the secret key. Each time Vera provides a seed to + * @dev Reggie, he gives back a value which is computed completely + * @dev deterministically from the seed and the secret key. + * + * @dev Reggie provides a proof by which Vera can verify that the output was + * @dev correctly computed once Reggie tells it to her, but without that proof, + * @dev the output is indistinguishable to her from a uniform random sample + * @dev from the output space. + * + * @dev The purpose of this contract is to make it easy for unrelated contracts + * @dev to talk to Vera the verifier about the work Reggie is doing, to provide + * @dev simple access to a verifiable source of randomness. It ensures 2 things: + * @dev 1. The fulfillment came from the VRFCoordinator + * @dev 2. The consumer contract implements fulfillRandomWords. + * ***************************************************************************** + * @dev USAGE + * + * @dev Calling contracts must inherit from VRFConsumerBase, and can + * @dev initialize VRFConsumerBase's attributes in their constructor as + * @dev shown: + * + * @dev contract VRFConsumer { + * @dev constructor(, address _vrfCoordinator, address _link) + * @dev VRFConsumerBase(_vrfCoordinator) public { + * @dev + * @dev } + * @dev } + * + * @dev The oracle will have given you an ID for the VRF keypair they have + * @dev committed to (let's call it keyHash). Create subscription, fund it + * @dev and your consumer contract as a consumer of it (see VRFCoordinatorInterface + * @dev subscription management functions). + * @dev Call requestRandomWords(keyHash, subId, minimumRequestConfirmations, + * @dev callbackGasLimit, numWords), + * @dev see (VRFCoordinatorInterface for a description of the arguments). + * + * @dev Once the VRFCoordinator has received and validated the oracle's response + * @dev to your request, it will call your contract's fulfillRandomWords method. + * + * @dev The randomness argument to fulfillRandomWords is a set of random words + * @dev generated from your requestId and the blockHash of the request. + * + * @dev If your contract could have concurrent requests open, you can use the + * @dev requestId returned from requestRandomWords to track which response is associated + * @dev with which randomness request. + * @dev See "SECURITY CONSIDERATIONS" for principles to keep in mind, + * @dev if your contract could have multiple requests in flight simultaneously. + * + * @dev Colliding `requestId`s are cryptographically impossible as long as seeds + * @dev differ. + * + * ***************************************************************************** + * @dev SECURITY CONSIDERATIONS + * + * @dev A method with the ability to call your fulfillRandomness method directly + * @dev could spoof a VRF response with any random value, so it's critical that + * @dev it cannot be directly called by anything other than this base contract + * @dev (specifically, by the VRFConsumerBase.rawFulfillRandomness method). + * + * @dev For your users to trust that your contract's random behavior is free + * @dev from malicious interference, it's best if you can write it so that all + * @dev behaviors implied by a VRF response are executed *during* your + * @dev fulfillRandomness method. If your contract must store the response (or + * @dev anything derived from it) and use it later, you must ensure that any + * @dev user-significant behavior which depends on that stored value cannot be + * @dev manipulated by a subsequent VRF request. + * + * @dev Similarly, both miners and the VRF oracle itself have some influence + * @dev over the order in which VRF responses appear on the blockchain, so if + * @dev your contract could have multiple VRF requests in flight simultaneously, + * @dev you must ensure that the order in which the VRF responses arrive cannot + * @dev be used to manipulate your contract's user-significant behavior. + * + * @dev Since the block hash of the block which contains the requestRandomness + * @dev call is mixed into the input to the VRF *last*, a sufficiently powerful + * @dev miner could, in principle, fork the blockchain to evict the block + * @dev containing the request, forcing the request to be included in a + * @dev different block with a different hash, and therefore a different input + * @dev to the VRF. However, such an attack would incur a substantial economic + * @dev cost. This cost scales with the number of blocks the VRF oracle waits + * @dev until it calls responds to a request. It is for this reason that + * @dev that you can signal to an oracle you'd like them to wait longer before + * @dev responding to the request (however this is not enforced in the contract + * @dev and so remains effective only in the case of unmodified oracle software). + */ +abstract contract VRFConsumerBaseV2 { + error OnlyCoordinatorCanFulfill(address have, address want); + address private immutable vrfCoordinator; + + /** + * @param _vrfCoordinator address of VRFCoordinator contract + */ + constructor(address _vrfCoordinator) { + vrfCoordinator = _vrfCoordinator; + } + + /** + * @notice fulfillRandomness handles the VRF response. Your contract must + * @notice implement it. See "SECURITY CONSIDERATIONS" above for important + * @notice principles to keep in mind when implementing your fulfillRandomness + * @notice method. + * + * @dev VRFConsumerBaseV2 expects its subcontracts to have a method with this + * @dev signature, and will call it once it has verified the proof + * @dev associated with the randomness. (It is triggered via a call to + * @dev rawFulfillRandomness, below.) + * + * @param requestId The Id initially returned by requestRandomness + * @param randomWords the VRF output expanded to the requested number of words + */ + function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) internal virtual; + + // rawFulfillRandomness is called by VRFCoordinator when it receives a valid VRF + // proof. rawFulfillRandomness then calls fulfillRandomness, after validating + // the origin of the call + function rawFulfillRandomWords(uint256 requestId, uint256[] memory randomWords) external { + if (msg.sender != vrfCoordinator) { + revert OnlyCoordinatorCanFulfill(msg.sender, vrfCoordinator); + } + fulfillRandomWords(requestId, randomWords); + } +} diff --git a/dapps/evm2/flipper/contracts/vrf/interfaces/VRFCoordinatorV2Interface.sol b/dapps/evm2/flipper/contracts/vrf/interfaces/VRFCoordinatorV2Interface.sol new file mode 100644 index 0000000..f5afd5f --- /dev/null +++ b/dapps/evm2/flipper/contracts/vrf/interfaces/VRFCoordinatorV2Interface.sol @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +// Reference: https://github.com/smartcontractkit/chainlink/blob/master/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol + +interface VRFCoordinatorV2Interface { + /** + * @notice Get configuration relevant for making requests + * @return minimumRequestConfirmations global min for request confirmations + * @return maxGasLimit global max for request gas limit + * @return s_provingKeyHashes list of registered key hashes + */ + function getRequestConfig() external view returns (uint16, uint32, bytes32[] memory); + + /** + * @notice Request a set of random words. + * @param keyHash - Corresponds to a particular oracle job which uses + * that key for generating the VRF proof. Different keyHash's have different gas price + * ceilings, so you can select a specific one to bound your maximum per request cost. + * @param subId - The ID of the VRF subscription. Must be funded + * with the minimum subscription balance required for the selected keyHash. + * @param minimumRequestConfirmations - How many blocks you'd like the + * oracle to wait before responding to the request. See SECURITY CONSIDERATIONS + * for why you may want to request more. The acceptable range is + * [minimumRequestBlockConfirmations, 200]. + * @param callbackGasLimit - How much gas you'd like to receive in your + * fulfillRandomWords callback. Note that gasleft() inside fulfillRandomWords + * may be slightly less than this amount because of gas used calling the function + * (argument decoding etc.), so you may need to request slightly more than you expect + * to have inside fulfillRandomWords. The acceptable range is + * [0, maxGasLimit] + * @param numWords - The number of uint256 random values you'd like to receive + * in your fulfillRandomWords callback. Note these numbers are expanded in a + * secure way by the VRFCoordinator from a single random value supplied by the oracle. + * @return requestId - A unique identifier of the request. Can be used to match + * a request to a response in fulfillRandomWords. + */ + function requestRandomWords( + bytes32 keyHash, + uint64 subId, + uint16 minimumRequestConfirmations, + uint32 callbackGasLimit, + uint32 numWords + ) external returns (uint256 requestId); + + /** + * @notice Create a VRF subscription. + * @return subId - A unique subscription id. + * @dev You can manage the consumer set dynamically with addConsumer/removeConsumer. + * @dev Note to fund the subscription, use transferAndCall. For example + * @dev LINKTOKEN.transferAndCall( + * @dev address(COORDINATOR), + * @dev amount, + * @dev abi.encode(subId)); + */ + function createSubscription() external returns (uint64 subId); + + /** + * @notice Get a VRF subscription. + * @param subId - ID of the subscription + * @return balance - LINK balance of the subscription in juels. + * @return reqCount - number of requests for this subscription, determines fee tier. + * @return owner - owner of the subscription. + * @return consumers - list of consumer address which are able to use this subscription. + */ + function getSubscription( + uint64 subId + ) external view returns (uint96 balance, uint64 reqCount, address owner, address[] memory consumers); + + /** + * @notice Request subscription owner transfer. + * @param subId - ID of the subscription + * @param newOwner - proposed new owner of the subscription + */ + function requestSubscriptionOwnerTransfer(uint64 subId, address newOwner) external; + + /** + * @notice Request subscription owner transfer. + * @param subId - ID of the subscription + * @dev will revert if original owner of subId has + * not requested that msg.sender become the new owner. + */ + function acceptSubscriptionOwnerTransfer(uint64 subId) external; + + /** + * @notice Add a consumer to a VRF subscription. + * @param subId - ID of the subscription + * @param consumer - New consumer which can use the subscription + */ + function addConsumer(uint64 subId, address consumer) external; + + /** + * @notice Remove a consumer from a VRF subscription. + * @param subId - ID of the subscription + * @param consumer - Consumer to remove from the subscription + */ + function removeConsumer(uint64 subId, address consumer) external; + + /** + * @notice Cancel a subscription + * @param subId - ID of the subscription + * @param to - Where to send the remaining LINK to + */ + function cancelSubscription(uint64 subId, address to) external; + + /* + * @notice Check to see if there exists a request commitment consumers + * for all consumers and keyhashes for a given sub. + * @param subId - ID of the subscription + * @return true if there exists at least one unfulfilled request for the subscription, false + * otherwise. + */ + function pendingRequestExists(uint64 subId) external view returns (bool); +} From fb3d91f6a01392b3d35796b76c6f1389bc8e9e7a Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Wed, 28 Jun 2023 06:41:11 +1000 Subject: [PATCH 3/5] wip Chainlink VRF Sepolia --- dapps/evm2/flipper/.env.example | 2 + dapps/evm2/flipper/README.md | 4 ++ .../flipper/contracts/lib/RandomNumber.sol | 44 ++++++++++++++-- ...omNumberChainlink.sol => VRFChainlink.sol} | 51 ++++--------------- .../flipper/migrations/2_deploy_contracts.js | 31 +++++------ dapps/evm2/flipper/test/test_ChainlinkVRF.js | 46 +++++++++++++++++ dapps/evm2/flipper/test/test_Flipper.js | 4 +- dapps/evm2/flipper/truffle-config.js | 11 ++++ 8 files changed, 133 insertions(+), 60 deletions(-) rename dapps/evm2/flipper/contracts/lib/{VRFRandomNumberChainlink.sol => VRFChainlink.sol} (79%) create mode 100644 dapps/evm2/flipper/test/test_ChainlinkVRF.js diff --git a/dapps/evm2/flipper/.env.example b/dapps/evm2/flipper/.env.example index fe04628..78cc6fa 100644 --- a/dapps/evm2/flipper/.env.example +++ b/dapps/evm2/flipper/.env.example @@ -3,3 +3,5 @@ MOONBASE_PRIVATE_KEY='0x' MOONSCAN_API_KEY='' # https://blastapi.io/ MOONBASE_BLASTAPI_ENDPOINT='' +# obtain from https://dashboard.alchemy.com/ under Ethereum > Ethereum Sepolia +CHAINLINK_SEPOLIA_ENDPOINT='https://rpc.sepolia.org' diff --git a/dapps/evm2/flipper/README.md b/dapps/evm2/flipper/README.md index f4bc613..c86f48e 100644 --- a/dapps/evm2/flipper/README.md +++ b/dapps/evm2/flipper/README.md @@ -110,13 +110,17 @@ shasum -a 256 moonkey * Compile full `truffle compile --compile-all` * Migrate * Migrate full `truffle migrate --reset --compile-all --network moonbase` + * Migrate full `truffle migrate --reset --compile-all --network sepolia` * Test * `truffle test --verbose-rpc --network moonbase` + * `truffle test --verbose-rpc --network sepolia` * Chainlink VRF https://docs.chain.link/getting-started/intermediates-tutorial * View token balance https://sepolia.etherscan.io/address/0x1dd907abb024e17d196de0d7fe8eb507b6ccaae7 * Create and fund a subscription https://docs.chain.link/vrf/v2/subscription/examples/get-a-random-number/#create-and-fund-a-subscription * Prepay Subscription https://vrf.chain.link/ + * Receipt https://sepolia.etherscan.io/tx/0xcc2cd9edf90e0f3351f3398b7013a7259c0acc7cfbfc38454192324fcfdb7d6a + * Reference v2 contract (not implemented): https://remix.ethereum.org/#url=https://docs.chain.link/samples/VRF/VRFv2Consumer.sol&lang=en&optimize=false&runs=200&evmVersion=null&version=soljson-v0.8.18+commit.87f61d96.js * Troubleshooting * `Client network socket disconnected before secure TLS connection was established` diff --git a/dapps/evm2/flipper/contracts/lib/RandomNumber.sol b/dapps/evm2/flipper/contracts/lib/RandomNumber.sol index 914e974..36bfaf8 100644 --- a/dapps/evm2/flipper/contracts/lib/RandomNumber.sol +++ b/dapps/evm2/flipper/contracts/lib/RandomNumber.sol @@ -25,10 +25,22 @@ contract RandomNumber is RandomnessConsumer { uint32 public VRF_BLOCKS_DELAY; bytes32 public SALT_PREFIX = "change-me-to-anything"; + uint256 private constant ROLL_IN_PROGRESS = 42; + // Storage variables for the current request uint256 public requestId; uint256[] public random; + address s_owner; + + // map rollers to requestIds + mapping(uint256 => address) private s_rollers; + // map vrf results to rollers + mapping(address => uint256) private s_results; + + event DiceRolled(uint256 indexed requestId, address indexed roller); + event DiceLanded(uint256 indexed requestId, uint256 indexed result); + constructor() payable RandomnessConsumer() { // Initialize use of Randomness dependency before trying to access it theRandomness = Randomness(randomnessPrecompileAddress); @@ -36,10 +48,14 @@ contract RandomNumber is RandomnessConsumer { // Because this contract can only perform 1 random request at a time, // We only need to have 1 required deposit. require(msg.value >= requiredDeposit); + s_owner = msg.sender; VRF_BLOCKS_DELAY = MIN_VRF_BLOCKS_DELAY; } - function requestRandomness() public payable { + function requestRandomness( + address roller + ) public onlyOwner payable { + require(s_results[roller] == 0, "Already rolled"); // Make sure that the value sent is enough require(msg.value >= MIN_FEE); // Request local VRF randomness @@ -51,6 +67,10 @@ contract RandomNumber is RandomnessConsumer { 1, // Number of random words VRF_BLOCKS_DELAY // Delay before request can be fulfilled ); + + s_rollers[requestId] = roller; + s_results[roller] = ROLL_IN_PROGRESS; + emit DiceRolled(requestId, roller); } function getRequestStatus() public view returns(Randomness.RequestStatus) { @@ -63,10 +83,28 @@ contract RandomNumber is RandomnessConsumer { } function fulfillRandomWords( - uint256, /* requestId */ + uint256 requestId, /* requestId */ uint256[] memory randomWords ) internal override { // Save the randomness results - random = randomWords; + uint256 d20Value = (randomWords[0] % 20) + 1; + s_results[s_rollers[requestId]] = d20Value; + // random = randomWords; + } + + /** + * @notice Get the value rolled by a player once the address has rolled + * @param player address + * @return id as a string + */ + function getRolledValueForPlayer(address player) public view returns (uint256) { + require(s_results[player] != 0, "Dice not rolled"); + require(s_results[player] != ROLL_IN_PROGRESS, "Roll in progress"); + return s_results[player]; + } + + modifier onlyOwner() { + require(msg.sender == s_owner); + _; } } diff --git a/dapps/evm2/flipper/contracts/lib/VRFRandomNumberChainlink.sol b/dapps/evm2/flipper/contracts/lib/VRFChainlink.sol similarity index 79% rename from dapps/evm2/flipper/contracts/lib/VRFRandomNumberChainlink.sol rename to dapps/evm2/flipper/contracts/lib/VRFChainlink.sol index 0a12fc9..306ccaa 100644 --- a/dapps/evm2/flipper/contracts/lib/VRFRandomNumberChainlink.sol +++ b/dapps/evm2/flipper/contracts/lib/VRFChainlink.sol @@ -1,8 +1,9 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.7; -import "@chainlink/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol"; -import "@chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol"; +// Reference: https://remix.ethereum.org/#url=https://docs.chain.link/samples/VRF/VRFD20.sol&lang=en&optimize=false&runs=200&evmVersion=null&version=soljson-v0.8.18+commit.87f61d96.js +import "../vrf/interfaces/VRFCoordinatorV2Interface.sol"; +import "../vrf/VRFConsumerBaseV2.sol"; /** * @notice A Chainlink VRF consumer which uses randomness to mimic the rolling @@ -26,7 +27,7 @@ contract VRFD20 is VRFConsumerBaseV2 { VRFCoordinatorV2Interface COORDINATOR; // Your subscription ID. - uint64 s_subscriptionId; + uint64 public s_subscriptionId; // Sepolia coordinator. For other networks, // see https://docs.chain.link/docs/vrf-contracts/#configurations @@ -52,7 +53,7 @@ contract VRFD20 is VRFConsumerBaseV2 { // For this example, retrieve 1 random value in one request. // Cannot exceed VRFCoordinatorV2.MAX_NUM_WORDS. uint32 numWords = 1; - address s_owner; + address public s_owner; // map rollers to requestIds mapping(uint256 => address) private s_rollers; @@ -69,8 +70,9 @@ contract VRFD20 is VRFConsumerBaseV2 { * * @param subscriptionId subscription id that this consumer contract can use */ - constructor(uint64 subscriptionId) VRFConsumerBaseV2(vrfCoordinator) { + constructor(uint64 subscriptionId) payable VRFConsumerBaseV2(vrfCoordinator) { COORDINATOR = VRFCoordinatorV2Interface(vrfCoordinator); + require(msg.value > 0); s_owner = msg.sender; s_subscriptionId = subscriptionId; } @@ -124,45 +126,14 @@ contract VRFD20 is VRFConsumerBaseV2 { } /** - * @notice Get the house assigned to the player once the address has rolled + * @notice Get the value rolled by a player once the address has rolled * @param player address - * @return house as a string + * @return id as a string */ - function house(address player) public view returns (string memory) { + function getRolledValueForPlayer(address player) public view returns (uint256) { require(s_results[player] != 0, "Dice not rolled"); require(s_results[player] != ROLL_IN_PROGRESS, "Roll in progress"); - return getHouseName(s_results[player]); - } - - /** - * @notice Get the house name from the id - * @param id uint256 - * @return house name string - */ - function getHouseName(uint256 id) private pure returns (string memory) { - string[20] memory houseNames = [ - "Targaryen", - "Lannister", - "Stark", - "Tyrell", - "Baratheon", - "Martell", - "Tully", - "Bolton", - "Greyjoy", - "Arryn", - "Frey", - "Mormont", - "Tarley", - "Dayne", - "Umber", - "Valeryon", - "Manderly", - "Clegane", - "Glover", - "Karstark" - ]; - return houseNames[id - 1]; + return s_results[player]; } modifier onlyOwner() { diff --git a/dapps/evm2/flipper/migrations/2_deploy_contracts.js b/dapps/evm2/flipper/migrations/2_deploy_contracts.js index ca64741..62e319e 100644 --- a/dapps/evm2/flipper/migrations/2_deploy_contracts.js +++ b/dapps/evm2/flipper/migrations/2_deploy_contracts.js @@ -2,28 +2,29 @@ require('dotenv').config() const { Web3 } = require('web3'); const contract = require("@truffle/contract"); +var VRFChainlink = artifacts.require("../build/contracts/VRFChainlink"); var RandomNumber = artifacts.require("../build/contracts/RandomNumber"); var Flipper = artifacts.require("../build/contracts/Flipper"); console.log('deploying...'); module.exports = async function (deployer) { - - console.log('deploy_contracts'); - let providerInstance = new Web3.providers.WebsocketProvider(process.env.MOONBASE_BLASTAPI_ENDPOINT, {}, { delay: 500, autoReconnect: true, maxAttempts: 100 }); + let providerInstance; + let web3; + console.log('deploy_contracts to Moonbase Alpha'); + + providerInstance = new Web3.providers.WebsocketProvider(process.env.MOONBASE_BLASTAPI_ENDPOINT, {}, { delay: 500, autoReconnect: true, maxAttempts: 100 }); console.log('providerInstance: ', providerInstance); - let web3 = new Web3(providerInstance); + + web3 = new Web3(providerInstance); console.log('web3.currentProvider: ', web3.currentProvider); - // let networkId = await web3.eth.net.getId(); - // console.log('networkId: ', networkId); - // RandomNumber.setNetwork(networkId); - // RandomNumber.setProvider(providerInstance); - // Flipper.setNetwork(networkId); - // Flipper.setProvider(providerInstance); - // console.log('web3.eth', web3.eth); - // const accounts = await web3.eth.getAccounts(); - // console.log('accounts: ', accounts); - // deployer.deploy(RandomNumber, { from: accounts[0], value: Web3.utils.toWei('1', 'ether') }); deployer.deploy(RandomNumber, { value: web3.utils.toWei('1', 'ether') }); - // deployer.link(RandomNumber, Flipper); deployer.deploy(Flipper, false); + + console.log('deploy_contracts to Chainlink Sepolia'); + providerInstance = new Web3.providers.WebsocketProvider(process.env.CHAINLINK_SEPOLIA_ENDPOINT, {}, { delay: 500, autoReconnect: true, maxAttempts: 100 }); + console.log('providerInstance: ', providerInstance); + web3 = new Web3(providerInstance); + console.log('web3.currentProvider: ', web3.currentProvider); + const subscriptionId = 3217; // https://vrf.chain.link/ + deployer.deploy(VRFChainlink, { subscriptionId: subscriptionId, value: web3.utils.toWei('0.001', 'ether') }); }; diff --git a/dapps/evm2/flipper/test/test_ChainlinkVRF.js b/dapps/evm2/flipper/test/test_ChainlinkVRF.js new file mode 100644 index 0000000..2b18c8f --- /dev/null +++ b/dapps/evm2/flipper/test/test_ChainlinkVRF.js @@ -0,0 +1,46 @@ +require('dotenv').config() +const { Web3 } = require('web3'); +const BN = require('bn.js'); + +// Uses Mocha and Ganache +const VRFChainlink = artifacts.require("../build/contracts/VRFChainlink"); + +console.log('test_ChainlinkVRF'); + +let providerInstance = new Web3.providers.WebsocketProvider(process.env.CHAINLINK_SEPOLIA_ENDPOINT, {}, { delay: 500, autoReconnect: true, maxAttempts: 100 }); +console.log('providerInstance: ', providerInstance); +let web3 = new Web3(providerInstance); +console.log('web3.currentProvider: ', web3.currentProvider); + +contract('VRFChainlink', accounts => { + console.log('accounts: ', accounts); + let vrfChainlinkInstance; + let gas; + let gasLimit; + let gasPrice; + + beforeEach(async () => { + console.log('beforeEach'); + + vrfChainlinkInstance = await VRFChainlink.deployed(); + console.log('vrfChainlinkInstance.address:', vrfChainlinkInstance.address); + }); + + it("requests random VRF", async () => { + try { + let s_subscriptionId = await vrfChainlinkInstance.s_subscriptionId.call(); + console.log('s_subscriptionId: ', s_subscriptionId.toString()); + console.log('s_subscriptionId is bn', BN.isBN(s_subscriptionId)); + console.log('accounts', accounts); + + let s_owner = await vrfChainlinkInstance.s_owner.call(); + console.log('s_owner: ', s_owner.toString()); + + let roller = '0x1dd907ABb024E17d196de0D7Fe8EB507b6cCaae7'; + requestId = await randomNumberInstance.rollDice(roller, { from: accounts[0], value: fulfillmentFee }); + console.log('requestId: ', requestId); + } catch (e) { + console.log('error in requests random VRF: ', e); + } + }); +}); diff --git a/dapps/evm2/flipper/test/test_Flipper.js b/dapps/evm2/flipper/test/test_Flipper.js index da8405e..8102e21 100644 --- a/dapps/evm2/flipper/test/test_Flipper.js +++ b/dapps/evm2/flipper/test/test_Flipper.js @@ -114,7 +114,6 @@ contract('Flipper', accounts => { }); it("requests randomness", async () => { - // TEMP ONLY - TRYING TO GET `requestRandomness` TO WORK try { fulfillmentFee = await randomNumberInstance.MIN_FEE.call(); console.log('fulfillmentFee: ', fulfillmentFee.toString()); @@ -129,7 +128,8 @@ contract('Flipper', accounts => { gas = Web3.utils.toHex(150000); gasLimit = Web3.utils.toHex(600000); gasPrice = Web3.utils.toHex(21000); - refundAddress = await randomNumberInstance.requestRandomness({ from: accounts[0], value: fulfillmentFee }); + let roller = '0x1dd907ABb024E17d196de0D7Fe8EB507b6cCaae7'; + refundAddress = await randomNumberInstance.requestRandomness(roller, { from: accounts[0], value: fulfillmentFee }); // refundAddress = await randomNumberInstance.requestRandomness( // { // from: accounts[0], diff --git a/dapps/evm2/flipper/truffle-config.js b/dapps/evm2/flipper/truffle-config.js index 1aa0fee..32b7c91 100644 --- a/dapps/evm2/flipper/truffle-config.js +++ b/dapps/evm2/flipper/truffle-config.js @@ -76,6 +76,17 @@ module.exports = { // deploymentPollingInterval: 8000, network_id: defaultMoonbaseNetworkId, }, + // Chainlink Sepolia + sepolia: { + provider: () => { + let args = { + privateKeys: [privateKeyMoonbase], + providerOrUrl: process.env.CHAINLINK_SEPOLIA_ENDPOINT, + }; + return new HDWalletProvider(args); + }, + network_id: 11155111, + }, // faucet for SBY https://docs.astar.network/docs/build/environment/faucet astar_shibuya: { provider: () => { From 2a2cd51b76d81e83630df8facd824e56845aa43b Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Wed, 28 Jun 2023 09:13:31 +1000 Subject: [PATCH 4/5] Uncaught Error: invalid 1st argument: block_number value was not valid block tag or block number --- dapps/evm2/flipper/.env.example | 1 + dapps/evm2/flipper/README.md | 10 +++-- .../flipper/contracts/lib/RandomNumber.sol | 22 +++++----- .../lib/{VRFChainlink.sol => VRFD20.sol} | 2 +- .../flipper/migrations/2_deploy_contracts.js | 29 +++++++----- dapps/evm2/flipper/package.json | 1 + dapps/evm2/flipper/scripts/demo.js | 44 +++++++++++++++++++ dapps/evm2/flipper/scripts/package.json | 15 +++++++ dapps/evm2/flipper/test/test_ChainlinkVRF.js | 11 +++-- dapps/evm2/flipper/truffle-config.js | 4 ++ 10 files changed, 107 insertions(+), 32 deletions(-) rename dapps/evm2/flipper/contracts/lib/{VRFChainlink.sol => VRFD20.sol} (99%) create mode 100644 dapps/evm2/flipper/scripts/demo.js create mode 100644 dapps/evm2/flipper/scripts/package.json diff --git a/dapps/evm2/flipper/.env.example b/dapps/evm2/flipper/.env.example index 78cc6fa..ac359b7 100644 --- a/dapps/evm2/flipper/.env.example +++ b/dapps/evm2/flipper/.env.example @@ -5,3 +5,4 @@ MOONSCAN_API_KEY='' MOONBASE_BLASTAPI_ENDPOINT='' # obtain from https://dashboard.alchemy.com/ under Ethereum > Ethereum Sepolia CHAINLINK_SEPOLIA_ENDPOINT='https://rpc.sepolia.org' +ALCHEMY_API_KEY='' diff --git a/dapps/evm2/flipper/README.md b/dapps/evm2/flipper/README.md index c86f48e..ea4f6aa 100644 --- a/dapps/evm2/flipper/README.md +++ b/dapps/evm2/flipper/README.md @@ -112,8 +112,11 @@ shasum -a 256 moonkey * Migrate full `truffle migrate --reset --compile-all --network moonbase` * Migrate full `truffle migrate --reset --compile-all --network sepolia` * Test - * `truffle test --verbose-rpc --network moonbase` - * `truffle test --verbose-rpc --network sepolia` + * **Important:** It is necessary to first comment-out the code that is **not being compiled** in 2_deploy_contracts.j + * `truffle test ./test/test_Flipper.js --verbose-rpc --network moonbase` + * `truffle test ./test/test_ChainlinkVRF.js --network sepolia` +* Run + * node ./scripts/demo.js * Chainlink VRF https://docs.chain.link/getting-started/intermediates-tutorial * View token balance https://sepolia.etherscan.io/address/0x1dd907abb024e17d196de0d7fe8eb507b6ccaae7 @@ -126,7 +129,8 @@ shasum -a 256 moonkey * `Client network socket disconnected before secure TLS connection was established` * Try fixing by running `unset https_proxy && unset http_proxy`, but this didn't actually work for me * If you get error `PollingBlockTracker` then try connecting to a different ISP and disable VPN and stop using a proxy and restart access to your internet - * Sometimes when you run `truffle test --network moonbase` after changing some CLI options it outputs `Error: The network id specified in the truffle config (1287) does not match the one returned by the network (4619453). Ensure that both the network and the provider are properly configured`, even though the network id in the truffle-config.js is in fact 1287, but when you run it again it might works. So just keep running the command again until it + * Sometimes when you run `truffle test --network moonbase` after changing some CLI options it outputs `Error: The network id specified in the truffle config (1287) does not match the one returned by the network (4619453). Ensure that both the network and the provider are properly configured`, even though the network id in the truffle-config.js is in fact 1287 (for some reason it confuses the block number for the network id), but when you run it again it might works. So just keep running the command again until it. Or run `truffle test --network sepolia` instead of + `truffle test --verbose-rpc --network sepolia` works or change internet connection. * References * https://github.com/trufflesuite/truffle/blob/develop/packages/contract/README.md diff --git a/dapps/evm2/flipper/contracts/lib/RandomNumber.sol b/dapps/evm2/flipper/contracts/lib/RandomNumber.sol index 36bfaf8..16bf121 100644 --- a/dapps/evm2/flipper/contracts/lib/RandomNumber.sol +++ b/dapps/evm2/flipper/contracts/lib/RandomNumber.sol @@ -31,7 +31,7 @@ contract RandomNumber is RandomnessConsumer { uint256 public requestId; uint256[] public random; - address s_owner; + // address public s_owner; // map rollers to requestIds mapping(uint256 => address) private s_rollers; @@ -48,13 +48,14 @@ contract RandomNumber is RandomnessConsumer { // Because this contract can only perform 1 random request at a time, // We only need to have 1 required deposit. require(msg.value >= requiredDeposit); - s_owner = msg.sender; + // s_owner = msg.sender; VRF_BLOCKS_DELAY = MIN_VRF_BLOCKS_DELAY; } function requestRandomness( address roller - ) public onlyOwner payable { + ) public payable { + // ) public onlyOwner payable { require(s_results[roller] == 0, "Already rolled"); // Make sure that the value sent is enough require(msg.value >= MIN_FEE); @@ -83,13 +84,14 @@ contract RandomNumber is RandomnessConsumer { } function fulfillRandomWords( - uint256 requestId, /* requestId */ + uint256 reqId, /* requestId */ uint256[] memory randomWords ) internal override { // Save the randomness results uint256 d20Value = (randomWords[0] % 20) + 1; - s_results[s_rollers[requestId]] = d20Value; - // random = randomWords; + s_results[s_rollers[reqId]] = d20Value; + // Save the latest for comparison + random = randomWords; } /** @@ -103,8 +105,8 @@ contract RandomNumber is RandomnessConsumer { return s_results[player]; } - modifier onlyOwner() { - require(msg.sender == s_owner); - _; - } + // modifier onlyOwner() { + // require(msg.sender == s_owner); + // _; + // } } diff --git a/dapps/evm2/flipper/contracts/lib/VRFChainlink.sol b/dapps/evm2/flipper/contracts/lib/VRFD20.sol similarity index 99% rename from dapps/evm2/flipper/contracts/lib/VRFChainlink.sol rename to dapps/evm2/flipper/contracts/lib/VRFD20.sol index 306ccaa..415c70c 100644 --- a/dapps/evm2/flipper/contracts/lib/VRFChainlink.sol +++ b/dapps/evm2/flipper/contracts/lib/VRFD20.sol @@ -72,7 +72,7 @@ contract VRFD20 is VRFConsumerBaseV2 { */ constructor(uint64 subscriptionId) payable VRFConsumerBaseV2(vrfCoordinator) { COORDINATOR = VRFCoordinatorV2Interface(vrfCoordinator); - require(msg.value > 0); + // require(msg.value > 0); s_owner = msg.sender; s_subscriptionId = subscriptionId; } diff --git a/dapps/evm2/flipper/migrations/2_deploy_contracts.js b/dapps/evm2/flipper/migrations/2_deploy_contracts.js index 62e319e..cb7aea3 100644 --- a/dapps/evm2/flipper/migrations/2_deploy_contracts.js +++ b/dapps/evm2/flipper/migrations/2_deploy_contracts.js @@ -1,24 +1,26 @@ require('dotenv').config() const { Web3 } = require('web3'); -const contract = require("@truffle/contract"); +const BN = require('bn.js'); -var VRFChainlink = artifacts.require("../build/contracts/VRFChainlink"); -var RandomNumber = artifacts.require("../build/contracts/RandomNumber"); -var Flipper = artifacts.require("../build/contracts/Flipper"); +// const contract = require("@truffle/contract"); + +var VRFD20 = artifacts.require("../build/contracts/VRFD20"); +// var RandomNumber = artifacts.require("../build/contracts/RandomNumber"); +// var Flipper = artifacts.require("../build/contracts/Flipper"); console.log('deploying...'); module.exports = async function (deployer) { let providerInstance; let web3; - console.log('deploy_contracts to Moonbase Alpha'); + // console.log('deploy_contracts to Moonbase Alpha'); - providerInstance = new Web3.providers.WebsocketProvider(process.env.MOONBASE_BLASTAPI_ENDPOINT, {}, { delay: 500, autoReconnect: true, maxAttempts: 100 }); - console.log('providerInstance: ', providerInstance); + // providerInstance = new Web3.providers.WebsocketProvider(process.env.MOONBASE_BLASTAPI_ENDPOINT, {}, { delay: 500, autoReconnect: true, maxAttempts: 100 }); + // console.log('providerInstance: ', providerInstance); - web3 = new Web3(providerInstance); - console.log('web3.currentProvider: ', web3.currentProvider); - deployer.deploy(RandomNumber, { value: web3.utils.toWei('1', 'ether') }); - deployer.deploy(Flipper, false); + // web3 = new Web3(providerInstance); + // console.log('web3.currentProvider: ', web3.currentProvider); + // deployer.deploy(RandomNumber, { value: web3.utils.toWei('0.000001', 'ether') }); + // deployer.deploy(Flipper, false); console.log('deploy_contracts to Chainlink Sepolia'); providerInstance = new Web3.providers.WebsocketProvider(process.env.CHAINLINK_SEPOLIA_ENDPOINT, {}, { delay: 500, autoReconnect: true, maxAttempts: 100 }); @@ -26,5 +28,8 @@ module.exports = async function (deployer) { web3 = new Web3(providerInstance); console.log('web3.currentProvider: ', web3.currentProvider); const subscriptionId = 3217; // https://vrf.chain.link/ - deployer.deploy(VRFChainlink, { subscriptionId: subscriptionId, value: web3.utils.toWei('0.001', 'ether') }); + // wants 128620983229604640 wei + const value = web3.utils.toWei('0.000001', 'ether'); + const amount = new BN(value, 10); + deployer.deploy(VRFD20, subscriptionId, { value: amount }); }; diff --git a/dapps/evm2/flipper/package.json b/dapps/evm2/flipper/package.json index 39e977e..2ec6446 100644 --- a/dapps/evm2/flipper/package.json +++ b/dapps/evm2/flipper/package.json @@ -4,6 +4,7 @@ "dependencies": { "@truffle/contract": "^4.6.25", "@truffle/hdwallet-provider": "^2.1.12", + "alchemy-sdk": "^2.9.1", "bn.js": "^5.2.1", "dotenv": "^16.3.1", "moonbeam-truffle-plugin": "github:PureStake/moonbeam-truffle-plugin", diff --git a/dapps/evm2/flipper/scripts/demo.js b/dapps/evm2/flipper/scripts/demo.js new file mode 100644 index 0000000..47ea7e8 --- /dev/null +++ b/dapps/evm2/flipper/scripts/demo.js @@ -0,0 +1,44 @@ +require('dotenv').config() +const { Network, Alchemy } = require('alchemy-sdk'); + +const config = { + apiKey: process.env.ALCHEMY_API_KEY, + network: Network.ETH_SEPOLIA, +}; + +const alchemy = new Alchemy(config); +// console.log('alchemy', alchemy); + +// Get the latest block +const latestBlock = alchemy.core.getBlockNumber(); +console.log('latestBlock', latestBlock); + +alchemy.core + .getTokenBalances("0x1dd907ABb024E17d196de0D7Fe8EB507b6cCaae7") + .then(console.log); + +// Listen to all new pending transactions +alchemy.ws.on( + { + method: "alchemy_pendingTransactions", + fromAddress: "0x1dd907ABb024E17d196de0D7Fe8EB507b6cCaae7" + }, + (res) => console.log('detected pending tx from account:', res), +); + +// Example of using the call method +const main = async () => { + // //Initialize a variable for the transaction object + // let tx = { + // to: "0x4976fb03C32e5B8cfe2b6cCB31c09Ba78EBaBa41", + // gas: "0x76c0", + // gasPrice: "0x9184e72a000", + // data: "0x3b3b57debf074faa138b72c65adbdcfb329847e4f2c04bde7f7dd7fcad5a52d2f395a558", + // } + // let response = await alchemy.core.call(tx) + + // //Logging the response to the console + // console.log(response) + }; + + main(); \ No newline at end of file diff --git a/dapps/evm2/flipper/scripts/package.json b/dapps/evm2/flipper/scripts/package.json new file mode 100644 index 0000000..e45668c --- /dev/null +++ b/dapps/evm2/flipper/scripts/package.json @@ -0,0 +1,15 @@ +{ + "name": "flipper", + "version": "1.0.0", + "description": "", + "main": "demo.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "ltfschoen", + "license": "MIT", + "dependencies": { + "alchemy-sdk": "^2.9.1", + "web3": "^4.0.2" + } +} diff --git a/dapps/evm2/flipper/test/test_ChainlinkVRF.js b/dapps/evm2/flipper/test/test_ChainlinkVRF.js index 2b18c8f..9bd18a5 100644 --- a/dapps/evm2/flipper/test/test_ChainlinkVRF.js +++ b/dapps/evm2/flipper/test/test_ChainlinkVRF.js @@ -3,7 +3,7 @@ const { Web3 } = require('web3'); const BN = require('bn.js'); // Uses Mocha and Ganache -const VRFChainlink = artifacts.require("../build/contracts/VRFChainlink"); +const VRFD20 = artifacts.require("../build/contracts/VRFD20"); console.log('test_ChainlinkVRF'); @@ -12,17 +12,16 @@ console.log('providerInstance: ', providerInstance); let web3 = new Web3(providerInstance); console.log('web3.currentProvider: ', web3.currentProvider); -contract('VRFChainlink', accounts => { +contract('VRFD20', accounts => { console.log('accounts: ', accounts); let vrfChainlinkInstance; - let gas; - let gasLimit; - let gasPrice; beforeEach(async () => { + // error `Uncaught Error: invalid 1st argument: block_number value was not valid block tag or block number` + console.log('beforeEach'); - vrfChainlinkInstance = await VRFChainlink.deployed(); + vrfChainlinkInstance = await VRFD20.deployed(); console.log('vrfChainlinkInstance.address:', vrfChainlinkInstance.address); }); diff --git a/dapps/evm2/flipper/truffle-config.js b/dapps/evm2/flipper/truffle-config.js index 32b7c91..c05ee40 100644 --- a/dapps/evm2/flipper/truffle-config.js +++ b/dapps/evm2/flipper/truffle-config.js @@ -82,9 +82,13 @@ module.exports = { let args = { privateKeys: [privateKeyMoonbase], providerOrUrl: process.env.CHAINLINK_SEPOLIA_ENDPOINT, + retryTimeout: 10000, }; return new HDWalletProvider(args); }, + websocket: true, + gasLimit: 5000000, + networkCheckTimeout: 1000000000, network_id: 11155111, }, // faucet for SBY https://docs.astar.network/docs/build/environment/faucet From dd0d6abbc167056fa094a088be71d97de0dc6ce4 Mon Sep 17 00:00:00 2001 From: Luke Schoen Date: Wed, 28 Jun 2023 09:28:49 +1000 Subject: [PATCH 5/5] success deploying chainlink VRF to Sepolia --- dapps/evm2/flipper/README.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/dapps/evm2/flipper/README.md b/dapps/evm2/flipper/README.md index ea4f6aa..27b09af 100644 --- a/dapps/evm2/flipper/README.md +++ b/dapps/evm2/flipper/README.md @@ -115,6 +115,42 @@ shasum -a 256 moonkey * **Important:** It is necessary to first comment-out the code that is **not being compiled** in 2_deploy_contracts.j * `truffle test ./test/test_Flipper.js --verbose-rpc --network moonbase` * `truffle test ./test/test_ChainlinkVRF.js --network sepolia` +* Verify Contract - Moonbase Precompile + +``` +# truffle run verify Flipper --network moonbase +Verifying contracts on moonscan + Verifying Flipper + Pass - Verified: https://moonbase.moonscan.io/address/0x1c440D264DcCBe9b7AC84edCEC99De926Db98753#code + Successfully verified 1 contract(s). +Verifying contracts on sourcify + Failed to connect to Sourcify API at url https://sourcify.dev/server/chains +root@ink:/app/dapps/evm2/flipper# truffle run verify RandomNumber --network moonbase +Verifying contracts on moonscan + Verifying RandomNumber + Pass - Verified: https://moonbase.moonscan.io/address/0x4027755C05514421fe00f4Fde0bD3F8475ce8A6b#code + Successfully verified 1 contract(s). +Verifying contracts on sourcify + Failed to connect to Sourcify API at url https://sourcify.dev/server/chains +``` + +* Verify Contract - Chainlink VRF +``` +# truffle run verify VRFD20 --network sepolia + +Verifying contracts on etherscan + No etherscan or sepolia_etherscan API Key provided +Verifying contracts on sourcify + Verifying VRFD20 + Pass - Verified: https://sourcify.dev/#/lookup/0xe22cdfA9d8C8e942B498696ef54584426d2f5Dd6 + Successfully verified 1 contract(s). +``` + +* Chainlink VRF https://docs.chain.link/getting-started/intermediates-tutorial + * View token balance https://sepolia.etherscan.io/address/0x1dd907abb024e17d196de0d7fe8eb507b6ccaae7 + * Create and fund a subscription https://docs.chain.link/vrf/v2/subscription/examples/get-a-random-number/#create-and-fund-a-subscription + * Prepay Subscription https://vrf.chain.link/ + * Run * node ./scripts/demo.js