[entropy] governance (#1154)
* governance * correct comment * add upgradability * remove unused lib * update governance and update logic * change specifiers * fix tests * add tests * rebase bug fixes * change error name * fix tests * no need of UUPSProxy * minimise the amount of code * separate file for authorized tests * add comment * correct comment
This commit is contained in:
parent
b2e4d56d36
commit
ae7610b0ab
|
@ -73,13 +73,14 @@ import "./EntropyState.sol";
|
||||||
// protocol prior to the random number being revealed (i.e., prior to step (6) above). Integrators should ensure that
|
// protocol prior to the random number being revealed (i.e., prior to step (6) above). Integrators should ensure that
|
||||||
// the user is always incentivized to reveal their random number, and that the protocol has an escape hatch for
|
// the user is always incentivized to reveal their random number, and that the protocol has an escape hatch for
|
||||||
// cases where the user chooses not to reveal.
|
// cases where the user chooses not to reveal.
|
||||||
contract Entropy is IEntropy, EntropyState {
|
abstract contract Entropy is IEntropy, EntropyState {
|
||||||
// TODO: Use an upgradeable proxy
|
function _initialize(
|
||||||
constructor(
|
address admin,
|
||||||
uint128 pythFeeInWei,
|
uint128 pythFeeInWei,
|
||||||
address defaultProvider,
|
address defaultProvider,
|
||||||
bool prefillRequestStorage
|
bool prefillRequestStorage
|
||||||
) {
|
) internal {
|
||||||
|
_state.admin = admin;
|
||||||
_state.accruedPythFeesInWei = 0;
|
_state.accruedPythFeesInWei = 0;
|
||||||
_state.pythFeeInWei = pythFeeInWei;
|
_state.pythFeeInWei = pythFeeInWei;
|
||||||
_state.defaultProvider = defaultProvider;
|
_state.defaultProvider = defaultProvider;
|
||||||
|
@ -305,6 +306,10 @@ contract Entropy is IEntropy, EntropyState {
|
||||||
return _state.providers[provider].feeInWei + _state.pythFeeInWei;
|
return _state.providers[provider].feeInWei + _state.pythFeeInWei;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getPythFee() public view returns (uint128 feeAmount) {
|
||||||
|
return _state.pythFeeInWei;
|
||||||
|
}
|
||||||
|
|
||||||
function getAccruedPythFees()
|
function getAccruedPythFees()
|
||||||
public
|
public
|
||||||
view
|
view
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
// SPDX-License-Identifier: Apache 2
|
||||||
|
pragma solidity ^0.8.0;
|
||||||
|
|
||||||
|
import "@pythnetwork/entropy-sdk-solidity/EntropyErrors.sol";
|
||||||
|
|
||||||
|
import "./EntropyState.sol";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev `Governance` defines a means to enacting changes to the Entropy contract.
|
||||||
|
*/
|
||||||
|
abstract contract EntropyGovernance is EntropyState {
|
||||||
|
event AdminSet(address oldAdmin, address newAdmin);
|
||||||
|
event PythFeeSet(uint oldPythFee, uint newPythFee);
|
||||||
|
event DefaultProviderSet(
|
||||||
|
address oldDefaultProvider,
|
||||||
|
address newDefaultProvider
|
||||||
|
);
|
||||||
|
|
||||||
|
function getAdmin() external view returns (address) {
|
||||||
|
return _state.admin;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Set the admin of the contract.
|
||||||
|
*
|
||||||
|
* Calls {_authoriseAdminAction}.
|
||||||
|
*
|
||||||
|
* Emits an {AdminSet} event.
|
||||||
|
*/
|
||||||
|
function setAdmin(address newAdmin) external {
|
||||||
|
_authoriseAdminAction();
|
||||||
|
|
||||||
|
address oldAdmin = _state.admin;
|
||||||
|
_state.admin = newAdmin;
|
||||||
|
|
||||||
|
emit AdminSet(oldAdmin, newAdmin);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Set the Pyth fee in Wei
|
||||||
|
*
|
||||||
|
* Calls {_authoriseAdminAction}.
|
||||||
|
*
|
||||||
|
* Emits an {PythFeeSet} event.
|
||||||
|
*/
|
||||||
|
function setPythFee(uint128 newPythFee) external {
|
||||||
|
_authoriseAdminAction();
|
||||||
|
|
||||||
|
uint oldPythFee = _state.pythFeeInWei;
|
||||||
|
_state.pythFeeInWei = newPythFee;
|
||||||
|
|
||||||
|
emit PythFeeSet(oldPythFee, newPythFee);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Set the default provider of the contract
|
||||||
|
*
|
||||||
|
* Calls {_authoriseAdminAction}.
|
||||||
|
*
|
||||||
|
* Emits an {DefaultProviderSet} event.
|
||||||
|
*/
|
||||||
|
function setDefaultProvider(address newDefaultProvider) external {
|
||||||
|
_authoriseAdminAction();
|
||||||
|
|
||||||
|
address oldDefaultProvider = _state.defaultProvider;
|
||||||
|
_state.defaultProvider = newDefaultProvider;
|
||||||
|
|
||||||
|
emit DefaultProviderSet(oldDefaultProvider, newDefaultProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _authoriseAdminAction() internal virtual;
|
||||||
|
}
|
|
@ -6,6 +6,8 @@ import "@pythnetwork/entropy-sdk-solidity/EntropyStructs.sol";
|
||||||
|
|
||||||
contract EntropyInternalStructs {
|
contract EntropyInternalStructs {
|
||||||
struct State {
|
struct State {
|
||||||
|
// Admin has the rights to update pyth configs
|
||||||
|
address admin;
|
||||||
// Fee charged by the pyth protocol in wei.
|
// Fee charged by the pyth protocol in wei.
|
||||||
uint128 pythFeeInWei;
|
uint128 pythFeeInWei;
|
||||||
// Total quantity of fees (in wei) earned by the pyth protocol that are currently stored in the contract.
|
// Total quantity of fees (in wei) earned by the pyth protocol that are currently stored in the contract.
|
||||||
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
// SPDX-License-Identifier: Apache 2
|
||||||
|
pragma solidity ^0.8.0;
|
||||||
|
|
||||||
|
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
|
||||||
|
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
|
||||||
|
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
|
||||||
|
import "@pythnetwork/entropy-sdk-solidity/EntropyErrors.sol";
|
||||||
|
|
||||||
|
import "./EntropyGovernance.sol";
|
||||||
|
import "./Entropy.sol";
|
||||||
|
|
||||||
|
contract EntropyUpgradable is
|
||||||
|
Initializable,
|
||||||
|
OwnableUpgradeable,
|
||||||
|
UUPSUpgradeable,
|
||||||
|
Entropy,
|
||||||
|
EntropyGovernance
|
||||||
|
{
|
||||||
|
event ContractUpgraded(
|
||||||
|
address oldImplementation,
|
||||||
|
address newImplementation
|
||||||
|
);
|
||||||
|
|
||||||
|
// The contract will have an owner and an admin
|
||||||
|
// The owner will have all the power over it.
|
||||||
|
// The admin can set some config parameters only.
|
||||||
|
function initialize(
|
||||||
|
address owner,
|
||||||
|
address admin,
|
||||||
|
uint128 pythFeeInWei,
|
||||||
|
address defaultProvider,
|
||||||
|
bool prefillRequestStorage
|
||||||
|
) public initializer {
|
||||||
|
__Ownable_init();
|
||||||
|
__UUPSUpgradeable_init();
|
||||||
|
|
||||||
|
Entropy._initialize(
|
||||||
|
admin,
|
||||||
|
pythFeeInWei,
|
||||||
|
defaultProvider,
|
||||||
|
prefillRequestStorage
|
||||||
|
);
|
||||||
|
|
||||||
|
// We need to transfer the ownership from deployer to the new owner
|
||||||
|
transferOwnership(owner);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Ensures the contract cannot be uninitialized and taken over.
|
||||||
|
/// @custom:oz-upgrades-unsafe-allow constructor
|
||||||
|
constructor() initializer {}
|
||||||
|
|
||||||
|
// Only allow the owner to upgrade the proxy to a new implementation.
|
||||||
|
function _authorizeUpgrade(address) internal override onlyOwner {}
|
||||||
|
|
||||||
|
// There are some actions which both and admin and owner can perform
|
||||||
|
function _authoriseAdminAction() internal view override {
|
||||||
|
if (msg.sender != owner() && msg.sender != _state.admin)
|
||||||
|
revert EntropyErrors.Unauthorized();
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have not overridden these methods in Pyth contracts implementation.
|
||||||
|
// But we are overriding them here because there was no owner before and
|
||||||
|
// `_authorizeUpgrade` would cause a revert for these. Now we have an owner, and
|
||||||
|
// because we want to test for the magic. We are overriding these methods.
|
||||||
|
function upgradeTo(address newImplementation) external override onlyProxy {
|
||||||
|
address oldImplementation = _getImplementation();
|
||||||
|
_authorizeUpgrade(newImplementation);
|
||||||
|
_upgradeToAndCallUUPS(newImplementation, new bytes(0), false);
|
||||||
|
|
||||||
|
magicCheck();
|
||||||
|
|
||||||
|
emit ContractUpgraded(oldImplementation, _getImplementation());
|
||||||
|
}
|
||||||
|
|
||||||
|
function upgradeToAndCall(
|
||||||
|
address newImplementation,
|
||||||
|
bytes memory data
|
||||||
|
) external payable override onlyProxy {
|
||||||
|
address oldImplementation = _getImplementation();
|
||||||
|
_authorizeUpgrade(newImplementation);
|
||||||
|
_upgradeToAndCallUUPS(newImplementation, data, true);
|
||||||
|
|
||||||
|
magicCheck();
|
||||||
|
|
||||||
|
emit ContractUpgraded(oldImplementation, _getImplementation());
|
||||||
|
}
|
||||||
|
|
||||||
|
function magicCheck() internal view {
|
||||||
|
// Calling a method using `this.<method>` will cause a contract call that will use
|
||||||
|
// the new contract. This call will fail if the method does not exists or the magic
|
||||||
|
// is different.
|
||||||
|
if (this.entropyUpgradableMagic() != 0x66697265)
|
||||||
|
revert EntropyErrors.InvalidUpgradeMagic();
|
||||||
|
}
|
||||||
|
|
||||||
|
function entropyUpgradableMagic() public pure returns (uint32) {
|
||||||
|
return 0x66697265;
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,13 +4,15 @@ pragma solidity ^0.8.0;
|
||||||
|
|
||||||
import "forge-std/Test.sol";
|
import "forge-std/Test.sol";
|
||||||
import "@pythnetwork/entropy-sdk-solidity/EntropyStructs.sol";
|
import "@pythnetwork/entropy-sdk-solidity/EntropyStructs.sol";
|
||||||
import "../contracts/entropy/Entropy.sol";
|
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
|
||||||
import "./utils/EntropyTestUtils.t.sol";
|
import "./utils/EntropyTestUtils.t.sol";
|
||||||
|
import "../contracts/entropy/EntropyUpgradable.sol";
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
// - fuzz test?
|
// - fuzz test?
|
||||||
contract EntropyTest is Test, EntropyTestUtils {
|
contract EntropyTest is Test, EntropyTestUtils {
|
||||||
Entropy public random;
|
ERC1967Proxy public proxy;
|
||||||
|
EntropyUpgradable public random;
|
||||||
|
|
||||||
uint128 pythFeeInWei = 7;
|
uint128 pythFeeInWei = 7;
|
||||||
|
|
||||||
|
@ -33,8 +35,18 @@ contract EntropyTest is Test, EntropyTestUtils {
|
||||||
uint128 MAX_UINT128 = 2 ** 128 - 1;
|
uint128 MAX_UINT128 = 2 ** 128 - 1;
|
||||||
bytes32 ALL_ZEROS = bytes32(uint256(0));
|
bytes32 ALL_ZEROS = bytes32(uint256(0));
|
||||||
|
|
||||||
|
address public owner = address(8);
|
||||||
|
address public admin = address(9);
|
||||||
|
address public admin2 = address(10);
|
||||||
|
|
||||||
function setUp() public {
|
function setUp() public {
|
||||||
random = new Entropy(pythFeeInWei, provider1, false);
|
EntropyUpgradable _random = new EntropyUpgradable();
|
||||||
|
// deploy proxy contract and point it to implementation
|
||||||
|
proxy = new ERC1967Proxy(address(_random), "");
|
||||||
|
// wrap in ABI to support easier calls
|
||||||
|
random = EntropyUpgradable(address(proxy));
|
||||||
|
|
||||||
|
random.initialize(owner, admin, pythFeeInWei, provider1, false);
|
||||||
|
|
||||||
bytes32[] memory hashChain1 = generateHashChain(
|
bytes32[] memory hashChain1 = generateHashChain(
|
||||||
provider1,
|
provider1,
|
||||||
|
|
|
@ -0,0 +1,123 @@
|
||||||
|
// SPDX-License-Identifier: Apache 2
|
||||||
|
|
||||||
|
pragma solidity ^0.8.0;
|
||||||
|
|
||||||
|
import "./utils/EntropyTestUtils.t.sol";
|
||||||
|
import "../contracts/entropy/EntropyUpgradable.sol";
|
||||||
|
import "./utils/EntropyTestContracts/EntropyDifferentMagic.t.sol";
|
||||||
|
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
|
||||||
|
import "@pythnetwork/entropy-sdk-solidity/EntropyErrors.sol";
|
||||||
|
|
||||||
|
contract EntropyAuthorized is Test, EntropyTestUtils {
|
||||||
|
ERC1967Proxy public proxy;
|
||||||
|
EntropyUpgradable public random;
|
||||||
|
EntropyUpgradable public random2;
|
||||||
|
EntropyDifferentMagic public randomDifferentMagic;
|
||||||
|
|
||||||
|
address public owner = address(1);
|
||||||
|
address public admin = address(2);
|
||||||
|
address public admin2 = address(3);
|
||||||
|
|
||||||
|
// We don't need to register providers for these tests
|
||||||
|
// We are just checking for the default provider, which
|
||||||
|
// only required an address.
|
||||||
|
address public provider1 = address(4);
|
||||||
|
address public provider2 = address(5);
|
||||||
|
|
||||||
|
uint128 pythFeeInWei = 7;
|
||||||
|
|
||||||
|
function setUp() public {
|
||||||
|
EntropyUpgradable _random = new EntropyUpgradable();
|
||||||
|
// deploy proxy contract and point it to implementation
|
||||||
|
proxy = new ERC1967Proxy(address(_random), "");
|
||||||
|
// wrap in ABI to support easier calls
|
||||||
|
random = EntropyUpgradable(address(proxy));
|
||||||
|
// to test for upgrade
|
||||||
|
random2 = new EntropyUpgradable();
|
||||||
|
randomDifferentMagic = new EntropyDifferentMagic();
|
||||||
|
|
||||||
|
random.initialize(owner, admin, pythFeeInWei, provider1, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testSetAdminByAdmin() public {
|
||||||
|
vm.prank(admin);
|
||||||
|
random.setAdmin(admin2);
|
||||||
|
assertEq(random.getAdmin(), admin2);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testSetAdminByOwner() public {
|
||||||
|
vm.prank(owner);
|
||||||
|
random.setAdmin(admin2);
|
||||||
|
assertEq(random.getAdmin(), admin2);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testExpectRevertSetAdminByUnauthorized() public {
|
||||||
|
vm.expectRevert(EntropyErrors.Unauthorized.selector);
|
||||||
|
vm.prank(admin2);
|
||||||
|
random.setAdmin(admin);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testSetPythFeeByAdmin() public {
|
||||||
|
vm.prank(admin);
|
||||||
|
random.setPythFee(10);
|
||||||
|
assertEq(random.getPythFee(), 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testSetPythFeeByOwner() public {
|
||||||
|
vm.prank(owner);
|
||||||
|
random.setPythFee(10);
|
||||||
|
assertEq(random.getPythFee(), 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testExpectRevertSetPythFeeByUnauthorized() public {
|
||||||
|
vm.expectRevert(EntropyErrors.Unauthorized.selector);
|
||||||
|
vm.prank(admin2);
|
||||||
|
random.setPythFee(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testSetDefaultProviderByOwner() public {
|
||||||
|
vm.prank(owner);
|
||||||
|
random.setDefaultProvider(provider2);
|
||||||
|
assertEq(random.getDefaultProvider(), provider2);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testSetDefaultProviderByAdmin() public {
|
||||||
|
vm.prank(admin);
|
||||||
|
random.setDefaultProvider(provider2);
|
||||||
|
assertEq(random.getDefaultProvider(), provider2);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testExpectRevertSetDefaultProviderByUnauthorized() public {
|
||||||
|
vm.expectRevert(EntropyErrors.Unauthorized.selector);
|
||||||
|
vm.prank(admin2);
|
||||||
|
random.setDefaultProvider(provider2);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testUpgradeByOwner() public {
|
||||||
|
vm.prank(owner);
|
||||||
|
random.upgradeTo(address(random2));
|
||||||
|
}
|
||||||
|
|
||||||
|
function testExpectRevertUpgradeByAdmin() public {
|
||||||
|
// The message is returned by openzepplin upgrade contracts
|
||||||
|
vm.expectRevert("Ownable: caller is not the owner");
|
||||||
|
vm.prank(admin);
|
||||||
|
random.upgradeTo(address(random2));
|
||||||
|
}
|
||||||
|
|
||||||
|
function testExpectRevertUpgradeByUnauthorized() public {
|
||||||
|
// The message is returned by openzepplin upgrade contracts
|
||||||
|
vm.expectRevert("Ownable: caller is not the owner");
|
||||||
|
vm.prank(provider1);
|
||||||
|
random.upgradeTo(address(random2));
|
||||||
|
}
|
||||||
|
|
||||||
|
// There can be another case that the magic function doesn't
|
||||||
|
// exist but it's fine. (It will revert with no reason)
|
||||||
|
// The randomDifferentMagic contract do have a magic in this case
|
||||||
|
function testExpectRevertDifferentMagicContractUpgrade() public {
|
||||||
|
vm.expectRevert(EntropyErrors.InvalidUpgradeMagic.selector);
|
||||||
|
vm.prank(owner);
|
||||||
|
random.upgradeTo(address(randomDifferentMagic));
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,14 +4,17 @@ pragma solidity ^0.8.0;
|
||||||
|
|
||||||
import "forge-std/Test.sol";
|
import "forge-std/Test.sol";
|
||||||
import "@pythnetwork/entropy-sdk-solidity/EntropyStructs.sol";
|
import "@pythnetwork/entropy-sdk-solidity/EntropyStructs.sol";
|
||||||
import "../contracts/entropy/Entropy.sol";
|
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
|
||||||
|
|
||||||
import "./utils/EntropyTestUtils.t.sol";
|
import "./utils/EntropyTestUtils.t.sol";
|
||||||
|
import "../contracts/entropy/EntropyUpgradable.sol";
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
// - what's the impact of # of in-flight requests on gas usage? More requests => more hashes to
|
// - what's the impact of # of in-flight requests on gas usage? More requests => more hashes to
|
||||||
// verify the provider's value.
|
// verify the provider's value.
|
||||||
contract EntropyGasBenchmark is Test, EntropyTestUtils {
|
contract EntropyGasBenchmark is Test, EntropyTestUtils {
|
||||||
Entropy public random;
|
ERC1967Proxy public proxy;
|
||||||
|
EntropyUpgradable public random;
|
||||||
|
|
||||||
uint128 pythFeeInWei = 7;
|
uint128 pythFeeInWei = 7;
|
||||||
|
|
||||||
|
@ -23,7 +26,19 @@ contract EntropyGasBenchmark is Test, EntropyTestUtils {
|
||||||
address public user1 = address(3);
|
address public user1 = address(3);
|
||||||
|
|
||||||
function setUp() public {
|
function setUp() public {
|
||||||
random = new Entropy(pythFeeInWei, provider1, true);
|
EntropyUpgradable _random = new EntropyUpgradable();
|
||||||
|
// deploy proxy contract and point it to implementation
|
||||||
|
proxy = new ERC1967Proxy(address(_random), "");
|
||||||
|
// wrap in ABI to support easier calls
|
||||||
|
random = EntropyUpgradable(address(proxy));
|
||||||
|
|
||||||
|
random.initialize(
|
||||||
|
address(4),
|
||||||
|
address(5),
|
||||||
|
pythFeeInWei,
|
||||||
|
provider1,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
bytes32[] memory hashChain1 = generateHashChain(
|
bytes32[] memory hashChain1 = generateHashChain(
|
||||||
provider1,
|
provider1,
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
// SPDX-License-Identifier: Apache 2
|
||||||
|
pragma solidity ^0.8.0;
|
||||||
|
|
||||||
|
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
|
||||||
|
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
|
||||||
|
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
|
||||||
|
import "@pythnetwork/entropy-sdk-solidity/EntropyErrors.sol";
|
||||||
|
|
||||||
|
contract EntropyDifferentMagic is
|
||||||
|
Initializable,
|
||||||
|
OwnableUpgradeable,
|
||||||
|
UUPSUpgradeable
|
||||||
|
{
|
||||||
|
function initialize() public initializer {
|
||||||
|
__Ownable_init();
|
||||||
|
__UUPSUpgradeable_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
// /// Ensures the contract cannot be uninitialized and taken over.
|
||||||
|
// /// @custom:oz-upgrades-unsafe-allow constructor
|
||||||
|
constructor() initializer {}
|
||||||
|
|
||||||
|
// // Only allow the owner to upgrade the proxy to a new implementation.
|
||||||
|
function _authorizeUpgrade(address) internal override onlyOwner {}
|
||||||
|
|
||||||
|
function magicCheck() internal view {
|
||||||
|
// Calling a method using `this.<method>` will cause a contract call that will use
|
||||||
|
// the new contract. This call will fail if the method does not exists or the magic
|
||||||
|
// is different.
|
||||||
|
if (this.entropyUpgradableMagic() != 0x666972)
|
||||||
|
revert EntropyErrors.InvalidUpgradeMagic();
|
||||||
|
}
|
||||||
|
|
||||||
|
function entropyUpgradableMagic() public pure returns (uint32) {
|
||||||
|
return 0x666972;
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,4 +18,8 @@ library EntropyErrors {
|
||||||
error InsufficientFee();
|
error InsufficientFee();
|
||||||
// Either the user's or the provider's revealed random values did not match their commitment.
|
// Either the user's or the provider's revealed random values did not match their commitment.
|
||||||
error IncorrectRevelation();
|
error IncorrectRevelation();
|
||||||
|
// Governance message is invalid (e.g., deserialization error).
|
||||||
|
error InvalidUpgradeMagic();
|
||||||
|
// Unauthorized (e.g., invalid admin or owner authorisation).
|
||||||
|
error Unauthorized();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue