// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "IShared.sol";
/**
* @title KeyManager interface
* @notice The interface for functions KeyManager implements
*/
interface IKeyManager is IShared {
event AggKeySetByAggKey(Key oldAggKey, Key newAggKey);
event AggKeySetByGovKey(Key oldAggKey, Key newAggKey);
event GovKeySetByAggKey(address oldGovKey, address newGovKey);
event GovKeySetByGovKey(address oldGovKey, address newGovKey);
event CommKeySetByAggKey(address oldCommKey, address newCommKey);
event CommKeySetByCommKey(address oldCommKey, address newCommKey);
event SignatureAccepted(SigData sigData, address signer);
event GovernanceAction(bytes32 message);
//////////////////////////////////////////////////////////////
// //
// State-changing functions //
// //
//////////////////////////////////////////////////////////////
function consumeKeyNonce(SigData memory sigData, bytes32 contractMsgHash) external;
function setAggKeyWithAggKey(SigData memory sigData, Key memory newAggKey) external;
function setAggKeyWithGovKey(Key memory newAggKey) external;
function setGovKeyWithAggKey(SigData calldata sigData, address newGovKey) external;
function setGovKeyWithGovKey(address newGovKey) external;
function setCommKeyWithAggKey(SigData calldata sigData, address newCommKey) external;
function setCommKeyWithCommKey(address newCommKey) external;
function govAction(bytes32 message) external;
//////////////////////////////////////////////////////////////
// //
// Non-state-changing functions //
// //
//////////////////////////////////////////////////////////////
function getAggregateKey() external view returns (Key memory);
function getGovernanceKey() external view returns (address);
function getCommunityKey() external view returns (address);
function isNonceUsedByAggKey(uint256 nonce) external view returns (bool);
function getLastValidateTime() external view returns (uint256);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "IERC20.sol";
/**
* @title Shared interface
* @notice Holds structs needed by other interfaces
*/
interface IShared {
/**
* @dev SchnorrSECP256K1 requires that each key has a public key part (x coordinate),
* a parity for the y coordinate (0 if the y ordinate of the public key is even, 1
* if it's odd)
*/
struct Key {
uint256 pubKeyX;
uint8 pubKeyYParity;
}
/**
* @dev Contains a signature and the nonce used to create it. Also the recovered address
* to check that the signature is valid
*/
struct SigData {
uint256 sig;
uint256 nonce;
address kTimesGAddress;
}
/**
* @param token The address of the token to be transferred
* @param recipient The address of the recipient of the transfer
* @param amount The amount to transfer, in wei (uint)
*/
struct TransferParams {
address token;
address payable recipient;
uint256 amount;
}
/**
* @param swapID The unique identifier for this swap (bytes32), used for create2
* @param token The token to be transferred
*/
struct DeployFetchParams {
bytes32 swapID;
address token;
}
/**
* @param fetchContract The address of the deployed Deposit contract
* @param token The token to be transferred
*/
struct FetchParams {
address payable fetchContract;
address token;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "IKeyManager.sol";
import "SchnorrSECP256K1.sol";
import "Shared.sol";
/**
* @title KeyManager contract
* @notice Holds the aggregate and governance keys, functions to update them, and
* consumeKeyNonce so other contracts can verify signatures and updates _lastValidateTime
*/
contract KeyManager is SchnorrSECP256K1, Shared, IKeyManager {
uint256 private constant _AGG_KEY_TIMEOUT = 2 days;
/// @dev The current (schnorr) aggregate key.
Key private _aggKey;
/// @dev The current governance key.
address private _govKey;
/// @dev The current community key.
address private _commKey;
/// @dev The last time that a sig was verified (used for a dead man's switch)
uint256 private _lastValidateTime;
mapping(uint256 => bool) private _isNonceUsedByAggKey;
constructor(
Key memory initialAggKey,
address initialGovKey,
address initialCommKey
) nzAddr(initialGovKey) nzAddr(initialCommKey) nzKey(initialAggKey) validAggKey(initialAggKey) {
_aggKey = initialAggKey;
_govKey = initialGovKey;
_commKey = initialCommKey;
_lastValidateTime = block.timestamp;
}
//////////////////////////////////////////////////////////////
// //
// State-changing functions //
// //
//////////////////////////////////////////////////////////////
/**
* @notice Checks the validity of a signature and msgHash, then updates _lastValidateTime
* @dev It would be nice to split this up, but these checks
* need to be made atomicly always. This needs to be available
* in this contract and in the Vault etc
* @param sigData Struct containing the signature data over the message
* to verify, signed by the aggregate key.
* @param msgHash The hash of the message being signed. The hash of the function
* call parameters is concatenated and hashed together with the nonce, the
* address of the caller, the chainId, and the address of this contract.
*/
function _consumeKeyNonce(SigData calldata sigData, bytes32 msgHash) internal {
Key memory key = _aggKey;
require(
verifySignature(msgHash, sigData.sig, key.pubKeyX, key.pubKeyYParity, sigData.kTimesGAddress),
"KeyManager: Sig invalid"
);
require(!_isNonceUsedByAggKey[sigData.nonce], "KeyManager: nonce already used");
_lastValidateTime = block.timestamp;
_isNonceUsedByAggKey[sigData.nonce] = true;
// Disable because tx.origin is not being used in the logic
// solhint-disable-next-line avoid-tx-origin
emit SignatureAccepted(sigData, tx.origin);
}
/**
* @notice Concatenates the contractMsgHash with the nonce, the address of the caller,
* the chainId, and the address of this contract, then hashes that and verifies the
* signature. This is done to prevent replay attacks.
* @param sigData Struct containing the signature data over the message
* to verify, signed by the aggregate key.
* @param contractMsgHash The hash of the function's call parameters. This will be hashed
* over other parameters to prevent replay attacks.
*/
function consumeKeyNonce(SigData calldata sigData, bytes32 contractMsgHash) external override {
bytes32 msgHash = keccak256(
abi.encode(contractMsgHash, sigData.nonce, msg.sender, block.chainid, address(this))
);
_consumeKeyNonce(sigData, msgHash);
}
/**
* @notice Set a new aggregate key. Requires a signature from the current aggregate key
* @param sigData Struct containing the signature data over the message
* to verify, signed by the aggregate key.
* @param newAggKey The new aggregate key to be set. The x component of the pubkey (uint256),
* the parity of the y component (uint8)
*/
function setAggKeyWithAggKey(
SigData calldata sigData,
Key calldata newAggKey
)
external
override
nzKey(newAggKey)
validAggKey(newAggKey)
consumeKeyNonceKeyManager(sigData, keccak256(abi.encode(this.setAggKeyWithAggKey.selector, newAggKey)))
{
emit AggKeySetByAggKey(_aggKey, newAggKey);
_aggKey = newAggKey;
}
/**
* @notice Set a new aggregate key. Can only be called by the current governance key
* @param newAggKey The new aggregate key to be set. The x component of the pubkey (uint256),
* the parity of the y component (uint8)
*/
function setAggKeyWithGovKey(
Key calldata newAggKey
) external override nzKey(newAggKey) validAggKey(newAggKey) timeoutEmergency onlyGovernor {
emit AggKeySetByGovKey(_aggKey, newAggKey);
_aggKey = newAggKey;
}
/**
* @notice Set a new aggregate key. Requires a signature from the current aggregate key
* @param sigData Struct containing the signature data over the message
* to verify, signed by the aggregate key.
* @param newGovKey The new governance key to be set.
*/
function setGovKeyWithAggKey(
SigData calldata sigData,
address newGovKey
)
external
override
nzAddr(newGovKey)
consumeKeyNonceKeyManager(sigData, keccak256(abi.encode(this.setGovKeyWithAggKey.selector, newGovKey)))
{
emit GovKeySetByAggKey(_govKey, newGovKey);
_govKey = newGovKey;
}
/**
* @notice Set a new governance key. Can only be called by current governance key
* @param newGovKey The new governance key to be set.
*/
function setGovKeyWithGovKey(address newGovKey) external override nzAddr(newGovKey) onlyGovernor {
emit GovKeySetByGovKey(_govKey, newGovKey);
_govKey = newGovKey;
}
/**
* @notice Set a new community key. Requires a signature from the current aggregate key
* @param sigData Struct containing the signature data over the message
* to verify, signed by the aggregate key.
* @param newCommKey The new community key to be set.
*/
function setCommKeyWithAggKey(
SigData calldata sigData,
address newCommKey
)
external
override
nzAddr(newCommKey)
consumeKeyNonceKeyManager(sigData, keccak256(abi.encode(this.setCommKeyWithAggKey.selector, newCommKey)))
{
emit CommKeySetByAggKey(_commKey, newCommKey);
_commKey = newCommKey;
}
/**
* @notice Update the Community Key. Can only be called by the current Community Key.
* @param newCommKey New Community key address.
*/
function setCommKeyWithCommKey(address newCommKey) external override onlyCommunityKey nzAddr(newCommKey) {
emit CommKeySetByCommKey(_commKey, newCommKey);
_commKey = newCommKey;
}
/**
* @notice Emit an event containing an action message. Can only be called by the governor.
*/
function govAction(bytes32 message) external override onlyGovernor {
emit GovernanceAction(message);
}
//////////////////////////////////////////////////////////////
// //
// Non-state-changing functions //
// //
//////////////////////////////////////////////////////////////
/**
* @notice Get the current aggregate key
* @return The Key struct for the aggregate key
*/
function getAggregateKey() external view override returns (Key memory) {
return _aggKey;
}
/**
* @notice Get the current governance key
* @return The Key struct for the governance key
*/
function getGovernanceKey() external view override returns (address) {
return _getGovernanceKey();
}
/**
* @notice Get the current community key
* @return The Key struct for the community key
*/
function getCommunityKey() external view override returns (address) {
return _getCommunityKey();
}
/**
* @notice Get the last time that a function was called which
* required a signature from _aggregateKeyData or _governanceKeyData
* @return The last time consumeKeyNonce was called, in unix time (uint256)
*/
function getLastValidateTime() external view override returns (uint256) {
return _lastValidateTime;
}
/**
* @notice Get whether or not the specific keyID has used this nonce before
* since it cannot be used again
* @return Whether the nonce has already been used (bool)
*/
function isNonceUsedByAggKey(uint256 nonce) external view override returns (bool) {
return _isNonceUsedByAggKey[nonce];
}
/**
* @notice Get the current governance key
* @return The Key struct for the governance key
*/
function _getGovernanceKey() internal view returns (address) {
return _govKey;
}
/**
* @notice Get the current community key
* @return The Key struct for the community key
*/
function _getCommunityKey() internal view returns (address) {
return _commKey;
}
//////////////////////////////////////////////////////////////
// //
// Modifiers //
// //
//////////////////////////////////////////////////////////////
/// @dev Check that enough time has passed for setAggKeyWithGovKey. Needs
/// to be done as a modifier so that it can happen before consumeKeyNonce
modifier timeoutEmergency() {
require(block.timestamp - _lastValidateTime >= _AGG_KEY_TIMEOUT, "KeyManager: not enough time");
_;
}
/// @dev Check that an aggregate key is capable of having its signatures
/// verified by the schnorr lib.
modifier validAggKey(Key memory key) {
verifySigningKeyX(key.pubKeyX);
_;
}
/// @dev Check that the sender is the governance address
modifier onlyGovernor() {
require(msg.sender == _getGovernanceKey(), "KeyManager: not governor");
_;
}
/// @dev Check that the caller is the Community Key address.
modifier onlyCommunityKey() {
require(msg.sender == _getCommunityKey(), "KeyManager: not Community Key");
_;
}
/// @dev For functions in this contract that require a signature from the aggregate key
// the msg.sender can't be hashed as anyone can make the call. Instead the
// address of this contract is used as the sender and hashed in the message.
modifier consumeKeyNonceKeyManager(SigData calldata sigData, bytes32 contractMsgHash) {
bytes32 msgHash = keccak256(
abi.encode(contractMsgHash, sigData.nonce, address(this), block.chainid, address(this))
);
_consumeKeyNonce(sigData, msgHash);
_;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @notice Slightly modified from https://github.com/smartcontractkit/chainlink/pull/1272/files
abstract contract SchnorrSECP256K1 {
// See https://en.bitcoin.it/wiki/Secp256k1 for this constant.
// Group order of secp256k1
uint256 private constant Q =
// solium-disable-next-line indentation
0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141;
// solium-disable-next-line zeppelin/no-arithmetic-operations
uint256 private constant HALF_Q = (Q >> 1) + 1;
/** **************************************************************************
@notice verifySignature returns true iff passed a valid Schnorr signature.
@dev See https://en.wikipedia.org/wiki/Schnorr_signature for reference.
@dev In what follows, let d be your secret key, PK be your public key,
PKx be the x ordinate of your public key, and PKyp be the parity bit for
the y ordinate (i.e., 0 if PKy is even, 1 if odd.)
**************************************************************************
@dev TO CREATE A VALID SIGNATURE FOR THIS METHOD
@dev First PKx must be less than HALF_Q. Then follow these instructions
(see evm/test/schnorr_test.js, for an example of carrying them out):
@dev 1. Hash the target message to a bytes32, called msgHash here, using
keccak256
@dev 2. Pick k uniformly and cryptographically securely randomly from
{0,...,Q-1}. It is critical that k remains confidential, as your
private key can be reconstructed from k and the signature.
@dev 3. Compute k*g in the secp256k1 group, where g is the group
generator. (This is the same as computing the public key from the
secret key k. But it's OK if k*g's x ordinate is greater than
HALF_Q.)
@dev 4. Compute the ethereum address for k*g. This is the lower 160 bits
of the keccak hash of the concatenated affine coordinates of k*g,
as 32-byte big-endians. (For instance, you could pass k to
ethereumjs-utils's privateToAddress to compute this, though that
should be strictly a development convenience, not for handling
live secrets, unless you've locked your javascript environment
down very carefully.) Call this address
nonceTimesGeneratorAddress.
@dev 5. Compute e=uint256(keccak256(PKx as a 32-byte big-endian
‖ PKyp as a single byte
‖ msgHash
‖ nonceTimesGeneratorAddress))
This value e is called "msgChallenge" in verifySignature's source
code below. Here "‖" means concatenation of the listed byte
arrays.
@dev 6. Let d be your secret key. Compute s = (k - d * e) % Q. Add Q to
it, if it's negative. This is your signature. (d is your secret
key.)
**************************************************************************
@dev TO VERIFY A SIGNATURE
@dev Given a signature (s, e) of msgHash, constructed as above, compute
S=e*PK+s*generator in the secp256k1 group law, and then the ethereum
address of S, as described in step 4. Call that
nonceTimesGeneratorAddress. Then call the verifySignature method as:
@dev verifySignature(PKx, PKyp, s, msgHash,
nonceTimesGeneratorAddress)
**************************************************************************
@dev This signging scheme deviates slightly from the classical Schnorr
signature, in that the address of k*g is used in place of k*g itself,
both when calculating e and when verifying sum S as described in the
verification paragraph above. This reduces the difficulty of
brute-forcing a signature by trying random secp256k1 points in place of
k*g in the signature verification process from 256 bits to 160 bits.
However, the difficulty of cracking the public key using "baby-step,
giant-step" is only 128 bits, so this weakening constitutes no compromise
in the security of the signatures or the key.
@dev The constraint signingPubKeyX < HALF_Q comes from Eq. (281), p. 24
of Yellow Paper version 78d7b9a. ecrecover only accepts "s" inputs less
than HALF_Q, to protect against a signature- malleability vulnerability in
ECDSA. Schnorr does not have this vulnerability, but we must account for
ecrecover's defense anyway. And since we are abusing ecrecover by putting
signingPubKeyX in ecrecover's "s" argument the constraint applies to
signingPubKeyX, even though it represents a value in the base field, and
has no natural relationship to the order of the curve's cyclic group.
**************************************************************************
@param msgHash is a 256-bit hash of the message being signed.
@param signature is the actual signature, described as s in the above
instructions.
@param signingPubKeyX is the x ordinate of the public key. This must be
less than HALF_Q.
@param pubKeyYParity is 0 if the y ordinate of the public key is even, 1
if it's odd.
@param nonceTimesGeneratorAddress is the ethereum address of k*g in the
above instructions
**************************************************************************
@return True if passed a valid signature, false otherwise. */
function verifySignature(
bytes32 msgHash,
uint256 signature,
uint256 signingPubKeyX,
uint8 pubKeyYParity,
address nonceTimesGeneratorAddress
) internal pure returns (bool) {
require(signingPubKeyX < HALF_Q, "Public-key x >= HALF_Q");
// Avoid signature malleability from multiple representations for ℤ/Qℤ elts
require(signature < Q, "Sig must be reduced modulo Q");
// Forbid trivial inputs, to avoid ecrecover edge cases. The main thing to
// avoid is something which causes ecrecover to return 0x0: then trivial
// signatures could be constructed with the nonceTimesGeneratorAddress input
// set to 0x0.
//
// solium-disable-next-line indentation
require(
nonceTimesGeneratorAddress != address(0) && signingPubKeyX > 0 && signature > 0 && msgHash > 0,
"No zero inputs allowed"
);
uint256 msgChallenge = uint256(
keccak256(abi.encodePacked(signingPubKeyX, pubKeyYParity, msgHash, nonceTimesGeneratorAddress))
);
// Verify msgChallenge * signingPubKey + signature * generator ==
// nonce * generator
//
// https://ethresear.ch/t/you-can-kinda-abuse-ecrecover-to-do-ecmul-in-secp256k1-today/2384/9
// The point corresponding to the address returned by
// ecrecover(-s*r,v,r,e*r) is (r⁻¹ mod Q)*(e*r*R-(-s)*r*g)=e*R+s*g, where R
// is the (v,r) point. See https://crypto.stackexchange.com/a/18106
//
// solium-disable-next-line indentation
address recoveredAddress = ecrecover(
// solium-disable-next-line zeppelin/no-arithmetic-operations
bytes32(Q - mulmod(signingPubKeyX, signature, Q)),
// https://ethereum.github.io/yellowpaper/paper.pdf p. 24, "The
// value 27 represents an even y value and 28 represents an odd
// y value."
(pubKeyYParity == 0) ? 27 : 28,
bytes32(signingPubKeyX),
bytes32(mulmod(msgChallenge, signingPubKeyX, Q))
);
require(recoveredAddress != address(0), "Schnorr: recoveredAddress is 0");
return nonceTimesGeneratorAddress == recoveredAddress;
}
function verifySigningKeyX(uint256 signingPubKeyX) internal pure {
require(signingPubKeyX < HALF_Q, "Public-key x >= HALF_Q");
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "IShared.sol";
/**
* @title Shared contract
* @notice Holds constants and modifiers that are used in multiple contracts
* @dev It would be nice if this could be a library, but modifiers can't be exported :(
*/
abstract contract Shared is IShared {
/// @dev The address used to indicate whether transfer should send native or a token
address internal constant _NATIVE_ADDR = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
address internal constant _ZERO_ADDR = address(0);
bytes32 internal constant _NULL = "";
uint256 internal constant _E_18 = 1e18;
/// @dev Checks that a uint isn't zero/empty
modifier nzUint(uint256 u) {
require(u != 0, "Shared: uint input is empty");
_;
}
/// @dev Checks that an address isn't zero/empty
modifier nzAddr(address a) {
require(a != _ZERO_ADDR, "Shared: address input is empty");
_;
}
/// @dev Checks that a bytes32 isn't zero/empty
modifier nzBytes32(bytes32 b) {
require(b != _NULL, "Shared: bytes32 input is empty");
_;
}
/// @dev Checks that the pubKeyX is populated
modifier nzKey(Key memory key) {
require(key.pubKeyX != 0, "Shared: pubKeyX is empty");
_;
}
}
{
"compilationTarget": {
"KeyManager.sol": "KeyManager"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 800
},
"remappings": []
}
[{"inputs":[{"components":[{"internalType":"uint256","name":"pubKeyX","type":"uint256"},{"internalType":"uint8","name":"pubKeyYParity","type":"uint8"}],"internalType":"struct IShared.Key","name":"initialAggKey","type":"tuple"},{"internalType":"address","name":"initialGovKey","type":"address"},{"internalType":"address","name":"initialCommKey","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint256","name":"pubKeyX","type":"uint256"},{"internalType":"uint8","name":"pubKeyYParity","type":"uint8"}],"indexed":false,"internalType":"struct IShared.Key","name":"oldAggKey","type":"tuple"},{"components":[{"internalType":"uint256","name":"pubKeyX","type":"uint256"},{"internalType":"uint8","name":"pubKeyYParity","type":"uint8"}],"indexed":false,"internalType":"struct IShared.Key","name":"newAggKey","type":"tuple"}],"name":"AggKeySetByAggKey","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint256","name":"pubKeyX","type":"uint256"},{"internalType":"uint8","name":"pubKeyYParity","type":"uint8"}],"indexed":false,"internalType":"struct IShared.Key","name":"oldAggKey","type":"tuple"},{"components":[{"internalType":"uint256","name":"pubKeyX","type":"uint256"},{"internalType":"uint8","name":"pubKeyYParity","type":"uint8"}],"indexed":false,"internalType":"struct IShared.Key","name":"newAggKey","type":"tuple"}],"name":"AggKeySetByGovKey","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldCommKey","type":"address"},{"indexed":false,"internalType":"address","name":"newCommKey","type":"address"}],"name":"CommKeySetByAggKey","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldCommKey","type":"address"},{"indexed":false,"internalType":"address","name":"newCommKey","type":"address"}],"name":"CommKeySetByCommKey","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldGovKey","type":"address"},{"indexed":false,"internalType":"address","name":"newGovKey","type":"address"}],"name":"GovKeySetByAggKey","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldGovKey","type":"address"},{"indexed":false,"internalType":"address","name":"newGovKey","type":"address"}],"name":"GovKeySetByGovKey","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"message","type":"bytes32"}],"name":"GovernanceAction","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint256","name":"sig","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"kTimesGAddress","type":"address"}],"indexed":false,"internalType":"struct IShared.SigData","name":"sigData","type":"tuple"},{"indexed":false,"internalType":"address","name":"signer","type":"address"}],"name":"SignatureAccepted","type":"event"},{"inputs":[{"components":[{"internalType":"uint256","name":"sig","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"kTimesGAddress","type":"address"}],"internalType":"struct IShared.SigData","name":"sigData","type":"tuple"},{"internalType":"bytes32","name":"contractMsgHash","type":"bytes32"}],"name":"consumeKeyNonce","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getAggregateKey","outputs":[{"components":[{"internalType":"uint256","name":"pubKeyX","type":"uint256"},{"internalType":"uint8","name":"pubKeyYParity","type":"uint8"}],"internalType":"struct IShared.Key","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCommunityKey","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getGovernanceKey","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastValidateTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"message","type":"bytes32"}],"name":"govAction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"nonce","type":"uint256"}],"name":"isNonceUsedByAggKey","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"sig","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"kTimesGAddress","type":"address"}],"internalType":"struct IShared.SigData","name":"sigData","type":"tuple"},{"components":[{"internalType":"uint256","name":"pubKeyX","type":"uint256"},{"internalType":"uint8","name":"pubKeyYParity","type":"uint8"}],"internalType":"struct IShared.Key","name":"newAggKey","type":"tuple"}],"name":"setAggKeyWithAggKey","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"pubKeyX","type":"uint256"},{"internalType":"uint8","name":"pubKeyYParity","type":"uint8"}],"internalType":"struct IShared.Key","name":"newAggKey","type":"tuple"}],"name":"setAggKeyWithGovKey","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"sig","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"kTimesGAddress","type":"address"}],"internalType":"struct IShared.SigData","name":"sigData","type":"tuple"},{"internalType":"address","name":"newCommKey","type":"address"}],"name":"setCommKeyWithAggKey","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newCommKey","type":"address"}],"name":"setCommKeyWithCommKey","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"sig","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"kTimesGAddress","type":"address"}],"internalType":"struct IShared.SigData","name":"sigData","type":"tuple"},{"internalType":"address","name":"newGovKey","type":"address"}],"name":"setGovKeyWithAggKey","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newGovKey","type":"address"}],"name":"setGovKeyWithGovKey","outputs":[],"stateMutability":"nonpayable","type":"function"}]