ethereum: remove proxy

This commit is contained in:
Karl Kempe 2022-09-13 21:44:12 +00:00
parent dc98293ae5
commit 9c0a213e95
9 changed files with 97 additions and 210 deletions

View File

@ -5,13 +5,26 @@ pragma solidity ^0.8.0;
import "./GasOracleGetters.sol"; import "./GasOracleGetters.sol";
import "./GasOracleSetters.sol"; import "./GasOracleSetters.sol";
import "./GasOracleGovernance.sol";
abstract contract GasOracle is GasOracleGovernance { contract GasOracle is GasOracleGetters, GasOracleSetters {
struct UpdatePrice { struct UpdatePrice {
uint16 chainId; uint16 chainId;
uint256 gasPrice; uint128 gasPrice;
uint256 nativeCurrencyPrice; uint128 nativeCurrencyPrice;
}
constructor(address wormhole, uint16 srcChainId) {
setupInitialState(_msgSender(), wormhole, srcChainId);
}
function setupInitialState(address owner, address wormhole, uint16 srcChainId) internal {
require(owner != address(0), "owner == address(0)");
setOwner(owner);
require(srcChainId > 0, "srcChainId == 0");
setChainId(srcChainId);
// might use this later to consume price data via VAAs?
require(wormhole != address(0), "wormhole == address(0)");
setWormhole(wormhole);
} }
function getPrice(uint16 targetChainId) public view returns (uint256 quote) { function getPrice(uint16 targetChainId) public view returns (uint256 quote) {
@ -21,10 +34,10 @@ abstract contract GasOracle is GasOracleGovernance {
uint256 dstNativeCurrencyPrice = nativeCurrencyPrice(targetChainId); uint256 dstNativeCurrencyPrice = nativeCurrencyPrice(targetChainId);
require(dstNativeCurrencyPrice > 0, "dstNativeCurrencyPrice == 0"); require(dstNativeCurrencyPrice > 0, "dstNativeCurrencyPrice == 0");
quote = gasPrice(targetChainId) * dstNativeCurrencyPrice / srcNativeCurrencyPrice; quote = (gasPrice(targetChainId) * dstNativeCurrencyPrice) / srcNativeCurrencyPrice;
} }
function updatePrice(uint16 updateChainId, uint256 updateGasPrice, uint256 updateNativeCurrencyPrice) function updatePrice(uint16 updateChainId, uint128 updateGasPrice, uint128 updateNativeCurrencyPrice)
public public
onlyOwner onlyOwner
{ {
@ -43,4 +56,9 @@ abstract contract GasOracle is GasOracleGovernance {
} }
} }
} }
modifier onlyOwner() {
require(owner() == _msgSender(), "owner() != _msgSender()");
_;
}
} }

View File

@ -7,7 +7,7 @@ import "../interfaces/IWormhole.sol";
import "./GasOracleState.sol"; import "./GasOracleState.sol";
abstract contract GasOracleGetters is GasOracleState { contract GasOracleGetters is GasOracleState {
function isInitialized(address implementation) public view returns (bool) { function isInitialized(address implementation) public view returns (bool) {
return _state.initializedImplementations[implementation]; return _state.initializedImplementations[implementation];
} }
@ -20,12 +20,12 @@ abstract contract GasOracleGetters is GasOracleState {
return _state.provider.chainId; return _state.provider.chainId;
} }
function gasPrice(uint16 targetChainId) public view returns (uint256) { function gasPrice(uint16 targetChainId) public view returns (uint128) {
return _state.gasPrices[targetChainId]; return _state.data[targetChainId].gasPrice;
} }
function nativeCurrencyPrice(uint16 targetChainId) public view returns (uint256) { function nativeCurrencyPrice(uint16 targetChainId) public view returns (uint128) {
return _state.nativeCurrencyPrices[targetChainId]; return _state.data[targetChainId].nativeCurrencyPrice;
} }
function owner() public view returns (address) { function owner() public view returns (address) {

View File

@ -1,35 +0,0 @@
// contracts/Oracle.sol
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol";
import "../libraries/external/BytesLib.sol";
import "./GasOracleGetters.sol";
import "./GasOracleSetters.sol";
import "../interfaces/IWormhole.sol";
abstract contract GasOracleGovernance is GasOracleGetters, GasOracleSetters, ERC1967Upgrade {
event ContractUpgraded(address indexed oldContract, address indexed newContract);
function upgradeImplementation(address newImplementation) public onlyOwner {
require(newImplementation != address(0), "newImplementation == address(0)");
_upgradeTo(newImplementation);
// Call initialize function of the new implementation
(bool success, bytes memory reason) = newImplementation.delegatecall(abi.encodeWithSignature("initialize()"));
require(success, string(reason));
emit ContractUpgraded(_getImplementation(), newImplementation);
}
modifier onlyOwner() {
require(owner() == _msgSender(), "owner() != _msgSender()");
_;
}
}

View File

@ -1,29 +0,0 @@
// contracts/Implementation.sol
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
pragma experimental ABIEncoderV2;
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol";
import "./GasOracle.sol";
contract GasOracleImplementation is GasOracle {
function initialize() initializer public virtual {
// this function needs to be exposed for an upgrade to pass
}
modifier initializer() {
address impl = ERC1967Upgrade._getImplementation();
require(
!isInitialized(impl),
"already initialized"
);
setInitialized(impl);
_;
}
}

View File

@ -1,15 +0,0 @@
// contracts/Wormhole.sol
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
contract GasOracleProxy is ERC1967Proxy {
constructor (address implementation, bytes memory initData)
ERC1967Proxy(
implementation,
initData
)
{}
}

View File

@ -7,7 +7,7 @@ import "@openzeppelin/contracts/utils/Context.sol";
import "./GasOracleState.sol"; import "./GasOracleState.sol";
abstract contract GasOracleSetters is Context, GasOracleState { contract GasOracleSetters is Context, GasOracleState {
function setInitialized(address implementation) internal { function setInitialized(address implementation) internal {
_state.initializedImplementations[implementation] = true; _state.initializedImplementations[implementation] = true;
} }
@ -24,8 +24,8 @@ abstract contract GasOracleSetters is Context, GasOracleState {
_state.owner = owner; _state.owner = owner;
} }
function setPriceInfo(uint16 updateChainId, uint256 updateGasPrice, uint256 updateNativeCurrencyPrice) internal { function setPriceInfo(uint16 updateChainId, uint128 updateGasPrice, uint128 updateNativeCurrencyPrice) internal {
_state.gasPrices[updateChainId] = updateGasPrice; _state.data[updateChainId].gasPrice = updateGasPrice;
_state.nativeCurrencyPrices[updateChainId] = updateNativeCurrencyPrice; _state.data[updateChainId].nativeCurrencyPrice = updateNativeCurrencyPrice;
} }
} }

View File

@ -1,29 +0,0 @@
// contracts/Setup.sol
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
pragma experimental ABIEncoderV2;
import "./GasOracleGovernance.sol";
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol";
contract GasOracleSetup is GasOracleSetters, ERC1967Upgrade {
function setup(address implementation, address owner, address wormhole, uint16 srcChainId) public {
setupInitialState(owner, wormhole, srcChainId);
require(implementation != address(0), "implementation == address(0)");
_upgradeTo(implementation);
}
function setupInitialState(address owner, address wormhole, uint16 srcChainId) internal {
require(owner != address(0), "owner == address(0)");
setOwner(owner);
require(srcChainId > 0, "srcChainId == 0");
setChainId(srcChainId);
// might use this later to consume price data via VAAs?
require(wormhole != address(0), "wormhole == address(0)");
setWormhole(wormhole);
}
}

View File

@ -3,21 +3,25 @@
pragma solidity ^0.8.0; pragma solidity ^0.8.0;
abstract contract GasOracleStorage { contract GasOracleStorage {
struct Provider { struct Provider {
uint16 chainId; uint16 chainId;
address payable wormhole; address payable wormhole;
} }
struct PriceData {
uint128 gasPrice;
uint128 nativeCurrencyPrice;
}
struct State { struct State {
Provider provider; Provider provider;
address owner; address owner;
mapping(address => bool) initializedImplementations; mapping(address => bool) initializedImplementations;
mapping(uint16 => uint256) gasPrices; mapping(uint16 => PriceData) data;
mapping(uint16 => uint256) nativeCurrencyPrices;
} }
} }
abstract contract GasOracleState { contract GasOracleState {
GasOracleStorage.State _state; GasOracleStorage.State _state;
} }

View File

@ -3,112 +3,95 @@
pragma solidity ^0.8.0; pragma solidity ^0.8.0;
import "../contracts/gasOracle/GasOracle.sol"; import "../contracts/gasOracle/GasOracle.sol";
import "../contracts/gasOracle/GasOracleSetup.sol"; import "../contracts/gasOracle/GasOracleState.sol";
import "forge-std/Test.sol"; import "forge-std/Test.sol";
import "forge-std/console.sol"; import "forge-std/console.sol";
contract TestGasOracle is GasOracle, GasOracleSetup, Test { contract TestGasOracle is Test {
uint16 constant TEST_ORACLE_CHAIN_ID = 2; uint16 constant TEST_ORACLE_CHAIN_ID = 2;
//uint256 constant TEST_SRC_GAS_PRICE = 10; //uint256 constant TEST_SRC_GAS_PRICE = 10;
//uint256 constant TEST_SRC_NATIVE_CURRENCY_PRICE = 250; //uint256 constant TEST_SRC_NATIVE_CURRENCY_PRICE = 250;
function initializeGasOracle(address oracleOwner, uint16 oracleChainId) internal { GasOracle internal gasOracle;
setupInitialState(
oracleOwner, // owner function initializeGasOracle(uint16 oracleChainId) internal {
gasOracle = new GasOracle(
0xC89Ce4735882C9F0f0FE26686c53074E09B0D550, // wormhole 0xC89Ce4735882C9F0f0FE26686c53074E09B0D550, // wormhole
oracleChainId // chainId oracleChainId // chainId
); );
} }
function testSetupInitialState(address oracleOwner, address wormhole, uint16 srcChainId) public { function testSetupInitialState(address wormhole, uint16 srcChainId) public {
vm.assume(oracleOwner != address(0));
vm.assume(wormhole != address(0)); vm.assume(wormhole != address(0));
vm.assume(srcChainId > 0); vm.assume(srcChainId > 0);
setupInitialState( gasOracle = new GasOracle(
oracleOwner, // owner
wormhole, // wormhole wormhole, // wormhole
srcChainId // srcChainId srcChainId // srcChainId
); );
require(owner() == oracleOwner, "owner() != expected"); require(gasOracle.owner() == address(this), "owner() != expected");
require(chainId() == srcChainId, "chainId() != expected"); require(gasOracle.chainId() == srcChainId, "chainId() != expected");
require(_state.provider.wormhole == wormhole, "_state.provider.wormhole != expected");
// TODO: check slots? // TODO: check slots?
} }
function testCannotInitializeWithOwnerZeroAddress(uint16 srcChainId) public {
vm.assume(srcChainId > 0);
// you shall not pass
vm.expectRevert("owner == address(0)");
initializeGasOracle(
address(0), // owner
srcChainId // srcChainId
);
}
function testCannotInitializeWithChainIdZero(address oracleOwner) public { function testCannotInitializeWithChainIdZero(address oracleOwner) public {
vm.assume(oracleOwner != address(0)); vm.assume(oracleOwner != address(0));
// you shall not pass // you shall not pass
vm.expectRevert("srcChainId == 0"); vm.expectRevert("srcChainId == 0");
initializeGasOracle( initializeGasOracle(
oracleOwner, // owner
0 // srcChainId 0 // srcChainId
); );
} }
function testCannotUpdatePriceWithChainIdZero(uint256 updateGasPrice, uint256 updateNativeCurrencyPrice) public { function testCannotUpdatePriceWithChainIdZero(uint128 updateGasPrice, uint128 updateNativeCurrencyPrice) public {
vm.assume(updateGasPrice > 0); vm.assume(updateGasPrice > 0);
vm.assume(updateNativeCurrencyPrice > 0); vm.assume(updateNativeCurrencyPrice > 0);
initializeGasOracle( initializeGasOracle(
_msgSender(), // owner
TEST_ORACLE_CHAIN_ID // chainId TEST_ORACLE_CHAIN_ID // chainId
); );
// you shall not pass // you shall not pass
vm.expectRevert("updateChainId == 0"); vm.expectRevert("updateChainId == 0");
updatePrice( gasOracle.updatePrice(
0, // updateChainId 0, // updateChainId
updateGasPrice, updateGasPrice,
updateNativeCurrencyPrice updateNativeCurrencyPrice
); );
} }
function testCannotUpdatePriceWithGasPriceZero(uint16 updateChainId, uint256 updateNativeCurrencyPrice) public { function testCannotUpdatePriceWithGasPriceZero(uint16 updateChainId, uint128 updateNativeCurrencyPrice) public {
vm.assume(updateChainId > 0); vm.assume(updateChainId > 0);
vm.assume(updateNativeCurrencyPrice > 0); vm.assume(updateNativeCurrencyPrice > 0);
initializeGasOracle( initializeGasOracle(
_msgSender(), // owner
TEST_ORACLE_CHAIN_ID // chainId TEST_ORACLE_CHAIN_ID // chainId
); );
// you shall not pass // you shall not pass
vm.expectRevert("updateGasPrice == 0"); vm.expectRevert("updateGasPrice == 0");
updatePrice( gasOracle.updatePrice(
updateChainId, updateChainId,
0, // updateGasPrice == 0 0, // updateGasPrice == 0
updateNativeCurrencyPrice updateNativeCurrencyPrice
); );
} }
function testCannotUpdatePriceWithNativeCurrencyPriceZero(uint16 updateChainId, uint256 updateGasPrice) public { function testCannotUpdatePriceWithNativeCurrencyPriceZero(uint16 updateChainId, uint128 updateGasPrice) public {
vm.assume(updateChainId > 0); vm.assume(updateChainId > 0);
vm.assume(updateGasPrice > 0); vm.assume(updateGasPrice > 0);
initializeGasOracle( initializeGasOracle(
_msgSender(), // owner
TEST_ORACLE_CHAIN_ID // chainId TEST_ORACLE_CHAIN_ID // chainId
); );
// you shall not pass // you shall not pass
vm.expectRevert("updateNativeCurrencyPrice == 0"); vm.expectRevert("updateNativeCurrencyPrice == 0");
updatePrice( gasOracle.updatePrice(
updateChainId, updateChainId,
updateGasPrice, updateGasPrice,
0 // updateNativeCurrencyPrice == 0 0 // updateNativeCurrencyPrice == 0
@ -118,35 +101,31 @@ contract TestGasOracle is GasOracle, GasOracleSetup, Test {
function testCanUpdatePriceOnlyAsOwner( function testCanUpdatePriceOnlyAsOwner(
address oracleOwner, address oracleOwner,
uint16 updateChainId, uint16 updateChainId,
uint256 updateGasPrice, uint128 updateGasPrice,
uint256 updateNativeCurrencyPrice uint128 updateNativeCurrencyPrice
) )
public public
{ {
vm.assume(oracleOwner != address(0)); vm.assume(oracleOwner != address(0));
vm.assume(oracleOwner != _msgSender()); vm.assume(oracleOwner != address(this));
vm.assume(updateChainId > 0); vm.assume(updateChainId > 0);
vm.assume(updateGasPrice > 0); vm.assume(updateGasPrice > 0);
vm.assume(updateNativeCurrencyPrice > 0); vm.assume(updateNativeCurrencyPrice > 0);
initializeGasOracle( initializeGasOracle(
oracleOwner,
TEST_ORACLE_CHAIN_ID // chainId TEST_ORACLE_CHAIN_ID // chainId
); );
// you shall not pass // you shall not pass
vm.prank(oracleOwner);
vm.expectRevert("owner() != _msgSender()"); vm.expectRevert("owner() != _msgSender()");
updatePrice( gasOracle.updatePrice(updateChainId, updateGasPrice, updateNativeCurrencyPrice);
updateChainId, // chainId
updateGasPrice, // gasPrice
updateNativeCurrencyPrice // nativeCurrencyPrice
);
} }
function testCannotGetPriceBeforeUpdateSrcPrice( function testCannotGetPriceBeforeUpdateSrcPrice(
uint16 dstChainId, uint16 dstChainId,
uint256 dstGasPrice, uint128 dstGasPrice,
uint256 dstNativeCurrencyPrice uint128 dstNativeCurrencyPrice
) )
public public
{ {
@ -159,22 +138,21 @@ contract TestGasOracle is GasOracle, GasOracleSetup, Test {
vm.assume(dstNativeCurrencyPrice < 2 ** 128); vm.assume(dstNativeCurrencyPrice < 2 ** 128);
initializeGasOracle( initializeGasOracle(
_msgSender(),
TEST_ORACLE_CHAIN_ID // chainId TEST_ORACLE_CHAIN_ID // chainId
); );
// update the price with reasonable values // update the price with reasonable values
updatePrice(dstChainId, dstGasPrice, dstNativeCurrencyPrice); gasOracle.updatePrice(dstChainId, dstGasPrice, dstNativeCurrencyPrice);
// you shall not pass // you shall not pass
vm.expectRevert("srcNativeCurrencyPrice == 0"); vm.expectRevert("srcNativeCurrencyPrice == 0");
getPrice(dstChainId); gasOracle.getPrice(dstChainId);
} }
function testCannotGetPriceBeforeUpdateDstPrice( function testCannotGetPriceBeforeUpdateDstPrice(
uint16 dstChainId, uint16 dstChainId,
uint256 srcGasPrice, uint128 srcGasPrice,
uint256 srcNativeCurrencyPrice uint128 srcNativeCurrencyPrice
) )
public public
{ {
@ -187,24 +165,28 @@ contract TestGasOracle is GasOracle, GasOracleSetup, Test {
vm.assume(srcNativeCurrencyPrice < 2 ** 128); vm.assume(srcNativeCurrencyPrice < 2 ** 128);
initializeGasOracle( initializeGasOracle(
_msgSender(),
TEST_ORACLE_CHAIN_ID // chainId TEST_ORACLE_CHAIN_ID // chainId
); );
console.log("address(this)", address(this));
console.log("msg.sender", msg.sender);
console.log("msg.sender", msg.sender);
console.log("gasOracle.owner()", gasOracle.owner());
// update the price with reasonable values // update the price with reasonable values
updatePrice(TEST_ORACLE_CHAIN_ID, srcGasPrice, srcNativeCurrencyPrice); //vm.prank(gasOracle.owner());
gasOracle.updatePrice(TEST_ORACLE_CHAIN_ID, srcGasPrice, srcNativeCurrencyPrice);
// you shall not pass // you shall not pass
vm.expectRevert("dstNativeCurrencyPrice == 0"); vm.expectRevert("dstNativeCurrencyPrice == 0");
getPrice(dstChainId); gasOracle.getPrice(dstChainId);
} }
function testUpdatePrice( function testUpdatePrice(
uint16 dstChainId, uint16 dstChainId,
uint256 dstGasPrice, uint128 dstGasPrice,
uint256 dstNativeCurrencyPrice, uint128 dstNativeCurrencyPrice,
uint256 srcGasPrice, uint128 srcGasPrice,
uint256 srcNativeCurrencyPrice uint128 srcNativeCurrencyPrice
) )
public public
{ {
@ -214,32 +196,26 @@ contract TestGasOracle is GasOracle, GasOracleSetup, Test {
vm.assume(dstNativeCurrencyPrice > 0); vm.assume(dstNativeCurrencyPrice > 0);
vm.assume(srcGasPrice > 0); vm.assume(srcGasPrice > 0);
vm.assume(srcNativeCurrencyPrice > 0); vm.assume(srcNativeCurrencyPrice > 0);
// we will also assume reasonable values for gasPrice and nativeCurrencyPrice
vm.assume(dstGasPrice < 2 ** 128);
vm.assume(dstNativeCurrencyPrice < 2 ** 128);
vm.assume(srcGasPrice < 2 ** 128);
vm.assume(srcNativeCurrencyPrice < 2 ** 128);
initializeGasOracle( initializeGasOracle(
_msgSender(),
TEST_ORACLE_CHAIN_ID // chainId TEST_ORACLE_CHAIN_ID // chainId
); );
// update the prices with reasonable values // update the prices with reasonable values
updatePrice(dstChainId, dstGasPrice, dstNativeCurrencyPrice); gasOracle.updatePrice(dstChainId, dstGasPrice, dstNativeCurrencyPrice);
updatePrice(TEST_ORACLE_CHAIN_ID, srcGasPrice, srcNativeCurrencyPrice); gasOracle.updatePrice(TEST_ORACLE_CHAIN_ID, srcGasPrice, srcNativeCurrencyPrice);
// verify price // verify price
uint256 expected = dstGasPrice * dstNativeCurrencyPrice / srcNativeCurrencyPrice; uint256 expected = (uint256(dstGasPrice) * dstNativeCurrencyPrice) / srcNativeCurrencyPrice;
require(getPrice(dstChainId) == expected, "getPrice(updateChainId) != expected"); require(gasOracle.getPrice(dstChainId) == expected, "gasOracle.getPrice(updateChainId) != expected");
} }
function testUpdatePrices( function testUpdatePrices(
uint16 dstChainId, uint16 dstChainId,
uint256 dstGasPrice, uint128 dstGasPrice,
uint256 dstNativeCurrencyPrice, uint128 dstNativeCurrencyPrice,
uint256 srcGasPrice, uint128 srcGasPrice,
uint256 srcNativeCurrencyPrice uint128 srcNativeCurrencyPrice
) )
public public
{ {
@ -249,31 +225,28 @@ contract TestGasOracle is GasOracle, GasOracleSetup, Test {
vm.assume(dstNativeCurrencyPrice > 0); vm.assume(dstNativeCurrencyPrice > 0);
vm.assume(srcGasPrice > 0); vm.assume(srcGasPrice > 0);
vm.assume(srcNativeCurrencyPrice > 0); vm.assume(srcNativeCurrencyPrice > 0);
// we will also assume reasonable values for gasPrice and nativeCurrencyPrice
vm.assume(dstGasPrice < 2 ** 128);
vm.assume(dstNativeCurrencyPrice < 2 ** 128);
vm.assume(srcGasPrice < 2 ** 128);
vm.assume(srcNativeCurrencyPrice < 2 ** 128);
initializeGasOracle( initializeGasOracle(
_msgSender(),
TEST_ORACLE_CHAIN_ID // chainId TEST_ORACLE_CHAIN_ID // chainId
); );
UpdatePrice[] memory updates = new UpdatePrice[](2); GasOracle.UpdatePrice[] memory updates = new GasOracle.UpdatePrice[](2);
updates[0] = UpdatePrice({ updates[0] = GasOracle.UpdatePrice({
chainId: TEST_ORACLE_CHAIN_ID, chainId: TEST_ORACLE_CHAIN_ID,
gasPrice: srcGasPrice, gasPrice: srcGasPrice,
nativeCurrencyPrice: srcNativeCurrencyPrice nativeCurrencyPrice: srcNativeCurrencyPrice
}); });
updates[1] = updates[1] = GasOracle.UpdatePrice({
UpdatePrice({chainId: dstChainId, gasPrice: dstGasPrice, nativeCurrencyPrice: dstNativeCurrencyPrice}); chainId: dstChainId,
gasPrice: dstGasPrice,
nativeCurrencyPrice: dstNativeCurrencyPrice
});
// update the prices with reasonable values // update the prices with reasonable values
updatePrices(updates); gasOracle.updatePrices(updates);
// verify price // verify price
uint256 expected = dstGasPrice * dstNativeCurrencyPrice / srcNativeCurrencyPrice; uint256 expected = (uint256(dstGasPrice) * dstNativeCurrencyPrice) / srcNativeCurrencyPrice;
require(getPrice(dstChainId) == expected, "getPrice(updateChainId) != expected"); require(gasOracle.getPrice(dstChainId) == expected, "gasOracle.getPrice(updateChainId) != expected");
} }
} }