Skip to content

Commit

Permalink
Wrapper contracts (#9686)
Browse files Browse the repository at this point in the history
* feature: ethereum vrf

* fix: compilation

* chore: remove fee tiers

* feat: generalize

* fix: tests

* fix: prettier

* chore: more prettier

* chore: bump migration version

* chore: fix compilation

* fix: tests

* fix: validation tests

* chore: use new task to differentiate v2 versions

* feat: refactor to support native

* fix: lint

* chore: rename V2.5 => V2Plus

* chore: more renames

* add gethwrapper for subscription api

* Revert "add gethwrapper for subscription api"

This reverts commit 9fd32de.

* chore: revert pnpm lock change

* fix: review comments

* chore: fix comments

* Wrapper contracts

* fix: name clash

* fix: lint and foundry build

* fix: nit comments

* fix: mistake

* Remove redundant interface

* Fix LINK and LINK_ETH_FEED naming

* Readability

* VRF-508 foundry tests

* Update contracts/test/v0.8/foundry/vrf/VRFV2Plus.t.sol

Co-authored-by: Makram <makramkd@users.noreply.github.com>

* Fix foundry profile discrepencies, test typos, and remove bloated initcode

* Delete unnecessary chainspecificutil

* Revert "Readability"

This reverts commit a834f35.

* Add wrapper foundry tests

* Test cleanup

* Remove unnecessary getters

* Add wrappers

* Undo consumer changes

* Remove redundancy

* Prettier

* Add link setter

* Fix merge conflicts

* Update contracts/src/v0.8/vrf/VRFV2PlusWrapperConsumerBase.sol

Co-authored-by: Makram <makramkd@users.noreply.github.com>

* Revert "Update contracts/src/v0.8/vrf/VRFV2PlusWrapperConsumerBase.sol"

This reverts commit 1391939.

* Fix merge conflicts (2)

---------

Co-authored-by: Makram Kamaleddine <makramkd@users.noreply.github.com>
Co-authored-by: jinhoonbang <jin.bang@smartcontract.com>
  • Loading branch information
3 people authored Jul 14, 2023
1 parent 40a6d21 commit 2139327
Show file tree
Hide file tree
Showing 17 changed files with 3,816 additions and 3 deletions.
2 changes: 1 addition & 1 deletion contracts/foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ test = 'src/v0.8/functions/tests'
[profile.vrf]
optimizer_runs = 1000
src = 'src/v0.8/vrf'
test = 'src/v0.8/vrf' # skips tests for no VRF foundry tests
test = 'test/v0.8/foundry/vrf' # skips tests for no VRF foundry tests
solc_version = '0.8.6'

[profile.automation]
Expand Down
2 changes: 2 additions & 0 deletions contracts/scripts/native_solc_compile_all
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ $SCRIPTPATH/native_solc8_6_compile vrf/testhelpers/VRFV2PlusConsumerExample.sol
$SCRIPTPATH/native_solc8_6_compile vrf/VRFCoordinatorV2Plus.sol 1000
$SCRIPTPATH/native_solc8_6_compile vrf/BatchVRFCoordinatorV2Plus.sol
$SCRIPTPATH/native_solc8_6_compile vrf/VRFV2PlusSubscriptionManager.sol
$SCRIPTPATH/native_solc8_6_compile vrf/VRFV2PlusWrapper.sol
$SCRIPTPATH/native_solc8_6_compile vrf/testhelpers/VRFV2PlusWrapperConsumerExample.sol

# VRF V2 Wrapper
$SCRIPTPATH/native_solc8_6_compile vrf/VRFV2Wrapper.sol
Expand Down
78 changes: 78 additions & 0 deletions contracts/src/v0.8/dev/BlockhashStore.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.6;

import "../ChainSpecificUtil.sol";

/**
* @title BlockhashStore
* @notice This contract provides a way to access blockhashes older than
* the 256 block limit imposed by the BLOCKHASH opcode.
* You may assume that any blockhash stored by the contract is correct.
* Note that the contract depends on the format of serialized Ethereum
* blocks. If a future hardfork of Ethereum changes that format, the
* logic in this contract may become incorrect and an updated version
* would have to be deployed.
*/
contract BlockhashStore {
mapping(uint => bytes32) internal s_blockhashes;

/**
* @notice stores blockhash of a given block, assuming it is available through BLOCKHASH
* @param n the number of the block whose blockhash should be stored
*/
function store(uint256 n) public {
bytes32 h = ChainSpecificUtil.getBlockhash(uint64(n));
require(h != 0x0, "blockhash(n) failed");
s_blockhashes[n] = h;
}

/**
* @notice stores blockhash of the earliest block still available through BLOCKHASH.
*/
function storeEarliest() external {
store(ChainSpecificUtil.getBlockNumber() - 256);
}

/**
* @notice stores blockhash after verifying blockheader of child/subsequent block
* @param n the number of the block whose blockhash should be stored
* @param header the rlp-encoded blockheader of block n+1. We verify its correctness by checking
* that it hashes to a stored blockhash, and then extract parentHash to get the n-th blockhash.
*/
function storeVerifyHeader(uint256 n, bytes memory header) public {
require(keccak256(header) == s_blockhashes[n + 1], "header has unknown blockhash");

// At this point, we know that header is the correct blockheader for block n+1.

// The header is an rlp-encoded list. The head item of that list is the 32-byte blockhash of the parent block.
// Based on how rlp works, we know that blockheaders always have the following form:
// 0xf9____a0PARENTHASH...
// ^ ^ ^
// | | |
// | | +--- PARENTHASH is 32 bytes. rlpenc(PARENTHASH) is 0xa || PARENTHASH.
// | |
// | +--- 2 bytes containing the sum of the lengths of the encoded list items
// |
// +--- 0xf9 because we have a list and (sum of lengths of encoded list items) fits exactly into two bytes.
//
// As a consequence, the PARENTHASH is always at offset 4 of the rlp-encoded block header.

bytes32 parentHash;
assembly {
parentHash := mload(add(header, 36)) // 36 = 32 byte offset for length prefix of ABI-encoded array
// + 4 byte offset of PARENTHASH (see above)
}

s_blockhashes[n] = parentHash;
}

/**
* @notice gets a blockhash from the store. If no hash is known, this function reverts.
* @param n the number of the block whose blockhash should be returned
*/
function getBlockhash(uint256 n) external view returns (bytes32) {
bytes32 h = s_blockhashes[n];
require(h != 0x0, "blockhash not found in store");
return h;
}
}
70 changes: 70 additions & 0 deletions contracts/src/v0.8/interfaces/VRFV2PlusWrapperInterface.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface VRFV2PlusWrapperInterface {
/**
* @return the request ID of the most recent VRF V2 request made by this wrapper. This should only
* be relied option within the same transaction that the request was made.
*/
function lastRequestId() external view returns (uint256);

/**
* @notice Calculates the price of a VRF request with the given callbackGasLimit at the current
* @notice block.
*
* @dev This function relies on the transaction gas price which is not automatically set during
* @dev simulation. To estimate the price at a specific gas price, use the estimatePrice function.
*
* @param _callbackGasLimit is the gas limit used to estimate the price.
*/
function calculateRequestPrice(uint32 _callbackGasLimit) external view returns (uint256);

/**
* @notice Calculates the price of a VRF request in native with the given callbackGasLimit at the current
* @notice block.
*
* @dev This function relies on the transaction gas price which is not automatically set during
* @dev simulation. To estimate the price at a specific gas price, use the estimatePrice function.
*
* @param _callbackGasLimit is the gas limit used to estimate the price.
*/
function calculateRequestPriceNative(uint32 _callbackGasLimit) external view returns (uint256);

/**
* @notice Estimates the price of a VRF request with a specific gas limit and gas price.
*
* @dev This is a convenience function that can be called in simulation to better understand
* @dev pricing.
*
* @param _callbackGasLimit is the gas limit used to estimate the price.
* @param _requestGasPriceWei is the gas price in wei used for the estimation.
*/
function estimateRequestPrice(uint32 _callbackGasLimit, uint256 _requestGasPriceWei) external view returns (uint256);

/**
* @notice Estimates the price of a VRF request in native with a specific gas limit and gas price.
*
* @dev This is a convenience function that can be called in simulation to better understand
* @dev pricing.
*
* @param _callbackGasLimit is the gas limit used to estimate the price.
* @param _requestGasPriceWei is the gas price in wei used for the estimation.
*/
function estimateRequestPriceNative(
uint32 _callbackGasLimit,
uint256 _requestGasPriceWei
) external view returns (uint256);

/**
* @notice Requests randomness from the VRF V2 wrapper, paying in native token.
*
* @param _callbackGasLimit is the gas limit for the request.
* @param _requestConfirmations number of request confirmations to wait before serving a request.
* @param _numWords is the number of words to request.
*/
function requestRandomWordsInNative(
uint32 _callbackGasLimit,
uint16 _requestConfirmations,
uint32 _numWords
) external payable returns (uint256 requestId);
}
3 changes: 1 addition & 2 deletions contracts/src/v0.8/vrf/VRFCoordinatorV2Plus.sol
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ contract VRFCoordinatorV2Plus is VRF, TypeAndVersionInterface, SubscriptionAPI {
bool nativePayment,
address indexed sender
);

event RandomWordsFulfilled(
uint256 indexed requestId,
uint256 outputSeed,
Expand Down Expand Up @@ -311,7 +310,7 @@ contract VRFCoordinatorV2Plus is VRF, TypeAndVersionInterface, SubscriptionAPI {
address sender,
uint64 subId,
uint64 nonce
) private pure returns (uint256, uint256) {
) internal pure returns (uint256, uint256) {
uint256 preSeed = uint256(keccak256(abi.encode(keyHash, sender, subId, nonce)));
return (uint256(keccak256(abi.encode(keyHash, preSeed))), preSeed);
}
Expand Down
Loading

0 comments on commit 2139327

Please sign in to comment.