verification logic into gatekeeper added, full contract inheritance added
Signed-off-by: Uncle Fatso <uncle.fatso@ghostchain.io>
This commit is contained in:
parent
379cc331e2
commit
c4f4f2e0e2
@ -1,106 +1,237 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {IStaking} from "./interfaces/IStaking.sol";
|
||||
import {IGatekeeper} from "./interfaces/IGatekeeper.sol";
|
||||
import {Metadata} from "./types/Metadata.sol";
|
||||
import {IStorageHistory} from "./interfaces/IStorageHistory.sol";
|
||||
|
||||
import {StorageHistory} from "./types/StorageHistory.sol";
|
||||
import {Weaver} from "./types/Weaver.sol";
|
||||
|
||||
contract Gatekeeper is IGatekeeper, Metadata, Weaver {
|
||||
uint256 public constant DIVISOR = 1e6;
|
||||
import {FullMath} from "./libraries/FullMath.sol";
|
||||
import {Checkpoints} from "./libraries/Checkpoints.sol";
|
||||
import {ReentrancyGuard} from "@openzeppelin-contracts/utils/ReentrancyGuard.sol";
|
||||
|
||||
contract Gatekeeper is IGatekeeper, Weaver, ReentrancyGuard {
|
||||
using Checkpoints for Checkpoints.Trace256;
|
||||
|
||||
uint256 private constant COMMISSION_DIVISOR = 2**32;
|
||||
uint256 private constant SECP256K1_N = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141;
|
||||
uint256 private constant SECP256K1_Q = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141;
|
||||
uint256 private constant SHIFT_FACTOR = (2**128) % SECP256K1_N;
|
||||
|
||||
uint256 public override existentialDeposit;
|
||||
uint256 public override ghostedSupply;
|
||||
address public override staking;
|
||||
address public override storageHistory;
|
||||
uint256 public override existentialDeposit;
|
||||
|
||||
uint256 private _aggregatedPublicKey;
|
||||
mapping(uint256 => mapping(uint256 => bool)) private _executedTransaction;
|
||||
address public deployer;
|
||||
address private _previousAddress;
|
||||
|
||||
Checkpoints.Trace256 private _aggregatedPublicKeys;
|
||||
mapping(bytes32 => RotationState) private _publicKeyMetadatas;
|
||||
|
||||
constructor(
|
||||
address _staking,
|
||||
uint256 _existentialDeposit,
|
||||
address _previousGatekeeper
|
||||
) Metadata(_previousGatekeeper) Weaver(_previousGatekeeper) {
|
||||
address _previousGatekeeperAddress
|
||||
) Weaver(_previousGatekeeperAddress) {
|
||||
existentialDeposit = _existentialDeposit;
|
||||
if (_previousGatekeeper != address(0)) {
|
||||
IGatekeeper previousGatekeeper = IGatekeeper(_previousGatekeeper);
|
||||
ghostedSupply = previousGatekeeper.ghostedSupply();
|
||||
staking = previousGatekeeper.staking();
|
||||
|
||||
if (_previousGatekeeperAddress != address(0)) {
|
||||
require(_previousGatekeeperAddress != address(0));
|
||||
require(_previousGatekeeperAddress != address(this));
|
||||
_previousAddress = _previousGatekeeperAddress;
|
||||
|
||||
storageHistory = IGatekeeper(_previousGatekeeperAddress).storageHistory();
|
||||
staking = IGatekeeper(_previousGatekeeperAddress).staking();
|
||||
} else {
|
||||
staking = _staking;
|
||||
StorageHistory newStorageHistory = new StorageHistory(msg.sender);
|
||||
storageHistory = address(newStorageHistory);
|
||||
staking = msg.sender;
|
||||
deployer = tx.origin;
|
||||
}
|
||||
}
|
||||
|
||||
function updatePublicKeyMetadata(uint256 exodusSession, bytes32 publicKey, uint8 parity) external {
|
||||
require(msg.sender == deployer);
|
||||
// TODO: uncomment line below, needed only for testing purposes
|
||||
// and should push to hardcoded exodusSession 0 in any case
|
||||
// deployer = address(0);
|
||||
|
||||
RotationState memory rotationState = RotationState({
|
||||
parity: parity,
|
||||
// forge-lint: disable-next-line(unsafe-typecast)
|
||||
session: uint64(exodusSession)
|
||||
});
|
||||
|
||||
_aggregatedPublicKeys.push(exodusSession, uint256(publicKey));
|
||||
_publicKeyMetadatas[publicKey] = rotationState;
|
||||
}
|
||||
|
||||
function previousAddress() external override view returns (address) {
|
||||
return _previousAddress;
|
||||
}
|
||||
|
||||
function ghostedSupply() external override view returns (uint256) {
|
||||
return IStorageHistory(storageHistory).bridgeImbalance();
|
||||
}
|
||||
|
||||
function latestPublicKeyInfo() external override view returns (bytes32, uint8, uint64) {
|
||||
bytes32 latestPublicKey = bytes32(_aggregatedPublicKeys.latest());
|
||||
RotationState memory state = _publicKeyMetadatas[latestPublicKey];
|
||||
return (latestPublicKey, state.parity, state.session);
|
||||
}
|
||||
|
||||
function getRotationInfoAt(uint256 exodusSession) public override view returns (bytes32, uint8, uint64) {
|
||||
bytes32 publicKey = bytes32(_aggregatedPublicKeys.upperLookup(exodusSession));
|
||||
RotationState memory rotationState = _publicKeyMetadatas[publicKey];
|
||||
|
||||
if (exodusSession < rotationState.session) {
|
||||
return IGatekeeper(_previousAddress).getRotationInfoAt(exodusSession);
|
||||
}
|
||||
|
||||
return (publicKey, rotationState.parity, rotationState.session);
|
||||
}
|
||||
|
||||
function verify(
|
||||
bytes calldata call,
|
||||
bytes calldata nonce,
|
||||
bytes32 s
|
||||
) external nonReentrant returns (bytes memory) {
|
||||
(bytes32 px, uint8 p) = _extractPublicKey(call);
|
||||
|
||||
uint8 v = p == 0 ? 27 : 28;
|
||||
bytes32 e = _challenge(call, nonce, px, p);
|
||||
|
||||
bytes32 sp = bytes32(SECP256K1_Q - mulmod(uint256(s), uint256(px), SECP256K1_Q));
|
||||
bytes32 ep = bytes32(SECP256K1_Q - mulmod(uint256(e), uint256(px), SECP256K1_Q));
|
||||
address recoveredR = ecrecover(sp, v, px, ep);
|
||||
|
||||
if (sp == 0) revert BadSignature();
|
||||
if (recoveredR == address(0)) revert BadSignature();
|
||||
if (recoveredR != _uncompressedPointToAddress(nonce)) revert BadSignature();
|
||||
|
||||
(bool success, bytes memory data) = address(this).call(call);
|
||||
if (!success) revert ExecutionReverted();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
function ghost(bytes32 receiver, uint256 amount) external override returns (uint256) {
|
||||
if (msg.sender != staking) revert NotStaking();
|
||||
if (amount < existentialDeposit) revert NonExistentAmount();
|
||||
|
||||
ghostedSupply += amount;
|
||||
_metadata.amountIn += uint104(amount); // forge-lint: disable-line(unsafe-typecast)
|
||||
IStorageHistory(storageHistory).increaseBridgeIn(amount);
|
||||
|
||||
emit Ghosted(receiver, amount);
|
||||
|
||||
return _insertTreeNode(receiver, amount);
|
||||
}
|
||||
|
||||
function materialize(
|
||||
address receiver,
|
||||
uint256 exodusSession,
|
||||
uint256 amount,
|
||||
uint256 rx,
|
||||
uint256 s
|
||||
uint256 commission,
|
||||
address receiver
|
||||
) external override {
|
||||
if (msg.sender != staking) revert NotStaking();
|
||||
_checkTransactionExistence(rx, s);
|
||||
if (msg.sender != address(this)) revert NotGatekeeper();
|
||||
|
||||
bytes4 selector = bytes4(keccak256("materialize(address,uint256)"));
|
||||
bytes32 message;
|
||||
assembly {
|
||||
let ptr := mload(0x40)
|
||||
mstore(ptr, selector)
|
||||
mstore(add(ptr, 4), receiver)
|
||||
mstore(add(ptr, 36), amount)
|
||||
message := keccak256(ptr, 68)
|
||||
StorageHistory(storageHistory).trySetTransactionExecuted(exodusSession);
|
||||
IStorageHistory(storageHistory).tryIncreaseBridgeOut(amount);
|
||||
|
||||
uint256 commissionAmount = FullMath.mulDiv(amount, commission, COMMISSION_DIVISOR);
|
||||
uint256 receiverAmount = amount - commissionAmount;
|
||||
IStaking(staking).materialize(receiver, receiverAmount);
|
||||
|
||||
if (commissionAmount > 0) {
|
||||
IStaking(staking).materialize(tx.origin, commission);
|
||||
}
|
||||
|
||||
if (_incorrectSignature(rx, s, message)) revert WrongSignature();
|
||||
ghostedSupply -= amount;
|
||||
_metadata.amountOut += uint104(amount); // forge-lint: disable-line(unsafe-typecast)
|
||||
emit Materialized(receiver, amount);
|
||||
}
|
||||
|
||||
function rotate(
|
||||
uint256 aggregatedPublicKey,
|
||||
uint256 rx,
|
||||
uint256 s
|
||||
uint256 exodusSession,
|
||||
bytes32 newPublicKey,
|
||||
uint8 newParity
|
||||
) external override {
|
||||
_checkTransactionExistence(rx, s);
|
||||
if (msg.sender != address(this)) revert NotGatekeeper();
|
||||
StorageHistory(storageHistory).trySetTransactionExecuted(exodusSession);
|
||||
|
||||
bytes4 selector = bytes4(keccak256("rotate(uint256)"));
|
||||
bytes32 message;
|
||||
RotationState memory rotationState = RotationState({
|
||||
parity: newParity,
|
||||
// forge-lint: disable-next-line(unsafe-typecast)
|
||||
session: uint64(exodusSession)
|
||||
});
|
||||
|
||||
_aggregatedPublicKeys.push(exodusSession, uint256(newPublicKey));
|
||||
_publicKeyMetadatas[newPublicKey] = rotationState;
|
||||
|
||||
emit Rotated(newPublicKey, newParity);
|
||||
}
|
||||
|
||||
function _uncompressedPointToAddress(bytes calldata nonce) internal pure returns (address) {
|
||||
if (nonce.length != 65) revert BadSignature();
|
||||
if (nonce[0] != 0x04) revert BadSignature();
|
||||
|
||||
bytes32 rx = bytes32(nonce[1:33]);
|
||||
bytes32 ry = bytes32(nonce[33:65]);
|
||||
|
||||
return address(uint160(uint256(keccak256(abi.encodePacked(rx, ry)))));
|
||||
}
|
||||
|
||||
function _extractPublicKey(bytes calldata call) internal view returns (bytes32, uint8) {
|
||||
if (call.length < 36) revert InvalidCalldata();
|
||||
uint256 exodusSession;
|
||||
assembly {
|
||||
let ptr := mload(0x40)
|
||||
mstore(ptr, selector)
|
||||
mstore(add(ptr, 4), aggregatedPublicKey)
|
||||
message := keccak256(ptr, 36)
|
||||
exodusSession := calldataload(add(call.offset, 4))
|
||||
}
|
||||
|
||||
if (_incorrectSignature(rx, s, message)) revert WrongSignature();
|
||||
_aggregatedPublicKey = aggregatedPublicKey;
|
||||
(bytes32 publicKey, uint8 parity,) = getRotationInfoAt(exodusSession);
|
||||
|
||||
emit Rotated(aggregatedPublicKey);
|
||||
return (publicKey, parity);
|
||||
}
|
||||
|
||||
function _checkTransactionExistence(uint256 rx, uint256 s) private {
|
||||
if (_executedTransaction[rx][s]) revert AlreadyExecuted();
|
||||
_executedTransaction[rx][s] = true;
|
||||
}
|
||||
function _challenge(
|
||||
bytes calldata call,
|
||||
bytes calldata r,
|
||||
bytes32 pk,
|
||||
uint8 v
|
||||
) internal pure returns (bytes32) {
|
||||
if (r.length != 65) revert BadSignature();
|
||||
|
||||
function _incorrectSignature(uint256 rx, uint256 s, bytes32 m) private pure returns (bool) {
|
||||
// no logic below, just to suppress warnings from solc
|
||||
uint256 void = rx;
|
||||
void = s;
|
||||
void = uint256(m);
|
||||
bytes32 rx = bytes32(r[1:33]);
|
||||
bytes1 rv;
|
||||
|
||||
// always bad signature for now
|
||||
return true;
|
||||
{
|
||||
bytes32 ry = bytes32(r[33:65]);
|
||||
uint8 rParityByte = (uint256(ry) & 1) == 0 ? 0x02 : 0x03;
|
||||
rv = bytes1(rParityByte);
|
||||
}
|
||||
|
||||
uint8 pv = v == 0 ? 0x02 : 0x03;
|
||||
|
||||
bytes memory message = abi.encodePacked(rv, rx, pv, pk, call);
|
||||
bytes memory domain = "FROST-secp256k1-SHA256-v1chal";
|
||||
uint8 dstlen = uint8(domain.length);
|
||||
|
||||
bytes32 b0 = sha256(abi.encodePacked(
|
||||
bytes32(0),
|
||||
bytes32(0),
|
||||
message,
|
||||
hex"0030",
|
||||
uint8(0),
|
||||
domain,
|
||||
dstlen
|
||||
));
|
||||
|
||||
bytes32 b1 = sha256(abi.encodePacked(b0, uint8(1), domain, dstlen));
|
||||
bytes32 b2 = sha256(abi.encodePacked(b0 ^ b1, uint8(2), domain, dstlen));
|
||||
|
||||
uint256 high32 = uint256(b1);
|
||||
uint256 lowPart = uint256(b2) >> 128;
|
||||
|
||||
uint256 highReduced = mulmod(high32, SHIFT_FACTOR, SECP256K1_N);
|
||||
uint256 finalChallenge = addmod(highReduced, lowPart, SECP256K1_N);
|
||||
|
||||
return bytes32(finalChallenge);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,13 +5,15 @@ import {SafeERC20} from "@openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol
|
||||
import {IERC20} from "@openzeppelin-contracts/token/ERC20/IERC20.sol";
|
||||
|
||||
import {GhostWarmup} from "./Warmup.sol";
|
||||
import {Gatekeeper} from "./Gatekeeper.sol";
|
||||
import {GhostAccessControlled} from "./types/GhostAccessControlled.sol";
|
||||
|
||||
import {ISTNK} from "./interfaces/ISTNK.sol";
|
||||
import {IGHST} from "./interfaces/IGHST.sol";
|
||||
import {IDistributor} from "./interfaces/IDistributor.sol";
|
||||
import {IStaking} from "./interfaces/IStaking.sol";
|
||||
import {IGatekeeper} from "./interfaces/IGatekeeper.sol";
|
||||
import {IDistributor} from "./interfaces/IDistributor.sol";
|
||||
import {IStorageHistory} from "./interfaces/IStorageHistory.sol";
|
||||
import {IGhostAuthority} from "./interfaces/IGhostAuthority.sol";
|
||||
import {IGhostWarmup} from "./interfaces/IGhostWarmup.sol";
|
||||
|
||||
@ -42,7 +44,8 @@ contract GhostStaking is IStaking, GhostAccessControlled {
|
||||
uint48 _epochLength,
|
||||
uint48 _firstEpochNumber,
|
||||
uint48 _firstEpochTime,
|
||||
address _authority
|
||||
address _authority,
|
||||
uint256 _existentialDeposit
|
||||
) GhostAccessControlled(IGhostAuthority(_authority)) {
|
||||
ftso = _ftso;
|
||||
stnk = _stnk;
|
||||
@ -57,6 +60,10 @@ contract GhostStaking is IStaking, GhostAccessControlled {
|
||||
|
||||
GhostWarmup newWarmup = new GhostWarmup(_ghst);
|
||||
warmup = address(newWarmup);
|
||||
|
||||
Gatekeeper newGatekeeper = new Gatekeeper(_existentialDeposit, address(0));
|
||||
gatekeeper = address(newGatekeeper);
|
||||
|
||||
_lastRebaseBlock = 1;
|
||||
}
|
||||
|
||||
@ -149,21 +156,13 @@ contract GhostStaking is IStaking, GhostAccessControlled {
|
||||
ISTNK(stnk).safeTransfer(to, balance);
|
||||
}
|
||||
|
||||
function ghost(
|
||||
bytes32 receiver,
|
||||
uint256 amount
|
||||
) external override {
|
||||
function ghost(bytes32 receiver, uint256 amount) external override {
|
||||
IGHST(ghst).burn(msg.sender, amount);
|
||||
IGatekeeper(gatekeeper).ghost(receiver, amount);
|
||||
}
|
||||
|
||||
function materialize(
|
||||
address receiver,
|
||||
uint256 amount,
|
||||
uint256 rx,
|
||||
uint256 s
|
||||
) external override {
|
||||
IGatekeeper(gatekeeper).materialize(receiver, amount, rx, s);
|
||||
function materialize(address receiver, uint256 amount) external override {
|
||||
if (gatekeeper != msg.sender) revert NotGatekeeper();
|
||||
IGHST(ghst).mint(receiver, amount);
|
||||
}
|
||||
|
||||
@ -200,9 +199,13 @@ contract GhostStaking is IStaking, GhostAccessControlled {
|
||||
emit WarmupSet(_warmupPeriod);
|
||||
}
|
||||
|
||||
function setGatekeeperAddress(address _gatekeeper) external onlyGovernor {
|
||||
gatekeeper = _gatekeeper;
|
||||
emit GatekeeperSet(_gatekeeper);
|
||||
function setGatekeeperAddress(uint256 existentialDeposit) external onlyGovernor {
|
||||
Gatekeeper newGatekeeper = new Gatekeeper(existentialDeposit, gatekeeper);
|
||||
address storageHistory = IGatekeeper(gatekeeper).storageHistory();
|
||||
IStorageHistory(storageHistory).setOwner(address(newGatekeeper));
|
||||
|
||||
gatekeeper = address(newGatekeeper);
|
||||
emit GatekeeperSet(address(newGatekeeper));
|
||||
}
|
||||
|
||||
function index() public view override returns (uint256) {
|
||||
|
||||
@ -3,18 +3,30 @@ pragma solidity ^0.8.20;
|
||||
|
||||
interface IGatekeeper {
|
||||
error NotStaking();
|
||||
error WrongSignature();
|
||||
error NotGatekeeper();
|
||||
error BadSignature();
|
||||
error AlreadyExecuted();
|
||||
error NonExistentAmount();
|
||||
error InvalidCalldata();
|
||||
error ExecutionReverted();
|
||||
|
||||
struct RotationState {
|
||||
uint8 parity;
|
||||
uint64 session;
|
||||
}
|
||||
|
||||
event Ghosted(bytes32 indexed receiver, uint256 indexed amount);
|
||||
event Materialized(address indexed receiver, uint256 indexed amount);
|
||||
event Rotated(uint256 indexed aggregatedPublicKey);
|
||||
event Rotated(bytes32 indexed aggregatedPublicKey, uint8 indexed parity);
|
||||
|
||||
function staking() external view returns (address);
|
||||
function storageHistory() external view returns (address);
|
||||
function ghostedSupply() external view returns (uint256);
|
||||
function existentialDeposit() external view returns (uint256);
|
||||
function staking() external view returns (address);
|
||||
function latestPublicKeyInfo() external view returns (bytes32, uint8, uint64);
|
||||
function getRotationInfoAt(uint256 session) external view returns (bytes32, uint8, uint64);
|
||||
|
||||
function materialize(uint256 session, uint256 amount, uint256 commission, address receiver) external;
|
||||
function rotate(uint256 session, bytes32 publicKey, uint8 parity) external;
|
||||
function ghost(bytes32 receiver, uint256 amount) external returns (uint256);
|
||||
function materialize(address receiver, uint256 amount, uint256 rx, uint256 s) external;
|
||||
function rotate(uint256 aggregatedPublicKey, uint256 rx, uint256 s) external;
|
||||
}
|
||||
|
||||
@ -1,12 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
interface IMetadata {
|
||||
struct GatekeeperMetadata {
|
||||
uint48 deployedAt;
|
||||
uint104 amountIn;
|
||||
uint104 amountOut;
|
||||
}
|
||||
|
||||
function metadata() external view returns (GatekeeperMetadata memory);
|
||||
}
|
||||
@ -5,6 +5,7 @@ interface IStaking {
|
||||
error ExternalDepositsLocked();
|
||||
error ExternalClaimsLocked();
|
||||
error InsufficientBalance();
|
||||
error NotGatekeeper();
|
||||
|
||||
event Staked(
|
||||
address sender,
|
||||
@ -67,7 +68,7 @@ interface IStaking {
|
||||
function wrap(address _to, uint256 _amount) external returns (uint256 gBalance_);
|
||||
function unwrap(address _to, uint256 _amount) external returns (uint256 sBalance_);
|
||||
function ghost(bytes32 receiver, uint256 amount) external;
|
||||
function materialize(address receiver, uint256 amount, uint256 rx, uint256 s) external;
|
||||
function materialize(address receiver, uint256 amount) external;
|
||||
function rebase() external returns (uint256);
|
||||
|
||||
function index() external view returns (uint256);
|
||||
|
||||
24
src/interfaces/IStorageHistory.sol
Normal file
24
src/interfaces/IStorageHistory.sol
Normal file
@ -0,0 +1,24 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
interface IStorageHistory {
|
||||
struct DeploymentSnapshot {
|
||||
uint48 deployedAt;
|
||||
uint104 amountIn;
|
||||
uint104 amountOut;
|
||||
}
|
||||
|
||||
error NotCreator();
|
||||
error NotDeployer();
|
||||
error AlreadyExecuted();
|
||||
error BridgeOutImpossible();
|
||||
|
||||
function isTransactionExecuted(uint256 session) external view returns (bool);
|
||||
function deploymentSnapshot() external view returns (DeploymentSnapshot memory);
|
||||
function bridgeImbalance() external view returns (uint256);
|
||||
|
||||
function trySetTransactionExecuted(uint256 session) external;
|
||||
function tryIncreaseBridgeOut(uint256 amount) external;
|
||||
function increaseBridgeIn(uint256 amount) external;
|
||||
function setOwner(address newOwner) external;
|
||||
}
|
||||
@ -2,8 +2,8 @@
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
interface IWeaver {
|
||||
function currentSession() external view returns (uint256);
|
||||
function startSession() external view returns (uint256);
|
||||
function currentWeavingSession() external view returns (uint256);
|
||||
function startWeavingSession() external view returns (uint256);
|
||||
function getSlotValues(uint256 globalIndex, uint256 session, uint256 atBlock) external view returns (bytes32[] memory);
|
||||
function getProof(uint256 globalIndex, uint256 session, uint256 atBlock) external view returns (bytes32[] memory);
|
||||
function getRoot(uint256 session, uint256 atBlock) external view returns (bytes32, uint256);
|
||||
|
||||
@ -4,7 +4,15 @@ pragma solidity ^0.8.20;
|
||||
import {Weaver} from "../types/Weaver.sol";
|
||||
|
||||
contract WeaverMock is Weaver {
|
||||
constructor(address previousWeaver) Weaver(previousWeaver) {}
|
||||
address private _previousAddress;
|
||||
|
||||
constructor(address previousWeaver) Weaver(previousWeaver) {
|
||||
_previousAddress = previousWeaver;
|
||||
}
|
||||
|
||||
function previousAddress() external override view returns (address) {
|
||||
return _previousAddress;
|
||||
}
|
||||
|
||||
function insertTreeNode(bytes32 receiver, uint256 amount) external returns (uint256) {
|
||||
return _insertTreeNode(receiver, amount);
|
||||
|
||||
@ -1,29 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {IMetadata} from "../interfaces/IMetadata.sol";
|
||||
|
||||
abstract contract Metadata is IMetadata {
|
||||
GatekeeperMetadata internal _metadata;
|
||||
|
||||
constructor(address previosMetadata) {
|
||||
if (previosMetadata == address(0)) {
|
||||
_metadata = GatekeeperMetadata({
|
||||
deployedAt: uint48(block.number),
|
||||
amountIn: 0,
|
||||
amountOut: 0
|
||||
});
|
||||
} else {
|
||||
IMetadata.GatekeeperMetadata memory previousMetadata = IMetadata(previosMetadata).metadata();
|
||||
_metadata = GatekeeperMetadata({
|
||||
deployedAt: previousMetadata.deployedAt,
|
||||
amountIn: previousMetadata.amountIn,
|
||||
amountOut: previousMetadata.amountOut
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function metadata() external view returns (GatekeeperMetadata memory) {
|
||||
return _metadata;
|
||||
}
|
||||
}
|
||||
59
src/types/StorageHistory.sol
Normal file
59
src/types/StorageHistory.sol
Normal file
@ -0,0 +1,59 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {IStorageHistory} from "../interfaces/IStorageHistory.sol";
|
||||
import {BitMaps} from "@openzeppelin-contracts/utils/structs/BitMaps.sol";
|
||||
|
||||
contract StorageHistory is IStorageHistory {
|
||||
using BitMaps for BitMaps.BitMap;
|
||||
|
||||
address private _deployer;
|
||||
address private _currentOwner;
|
||||
|
||||
DeploymentSnapshot private _snapshot;
|
||||
BitMaps.BitMap private _executedTransaction;
|
||||
|
||||
constructor(address deployer) {
|
||||
_currentOwner = msg.sender;
|
||||
_deployer = deployer;
|
||||
}
|
||||
|
||||
function deploymentSnapshot() external override view returns (DeploymentSnapshot memory) {
|
||||
return _snapshot;
|
||||
}
|
||||
|
||||
function bridgeImbalance() public override view returns (uint256) {
|
||||
DeploymentSnapshot memory snapshot = _snapshot;
|
||||
return snapshot.amountIn - snapshot.amountOut;
|
||||
}
|
||||
|
||||
function isTransactionExecuted(uint256 session) external override view returns (bool) {
|
||||
return _executedTransaction.get(session);
|
||||
}
|
||||
|
||||
function trySetTransactionExecuted(uint256 session) external override {
|
||||
if (msg.sender != _currentOwner) revert NotCreator();
|
||||
if (_executedTransaction.get(session)) revert AlreadyExecuted();
|
||||
_executedTransaction.set(session);
|
||||
}
|
||||
|
||||
function setOwner(address newOwner) external override {
|
||||
if (msg.sender != _deployer) revert NotDeployer();
|
||||
_currentOwner = newOwner;
|
||||
}
|
||||
|
||||
function increaseBridgeIn(uint256 amount) external override {
|
||||
if (msg.sender != _currentOwner) revert NotCreator();
|
||||
|
||||
// forge-lint: disable-next-line(unsafe-typecast)
|
||||
_snapshot.amountIn += uint104(amount);
|
||||
}
|
||||
|
||||
function tryIncreaseBridgeOut(uint256 amount) external override {
|
||||
if (msg.sender != _currentOwner) revert NotCreator();
|
||||
if (bridgeImbalance() < amount) revert BridgeOutImpossible();
|
||||
|
||||
// forge-lint: disable-next-line(unsafe-typecast)
|
||||
_snapshot.amountOut += uint104(amount);
|
||||
}
|
||||
}
|
||||
@ -14,31 +14,31 @@ abstract contract Weaver is IWeaver {
|
||||
uint256 public constant SLOTS = 2 ** DEPTH;
|
||||
uint256 public constant ENTRIES = DEPTH * SLOTS;
|
||||
|
||||
uint256 public override currentSession;
|
||||
uint256 public override startSession;
|
||||
address public previousWeaver;
|
||||
uint256 public override currentWeavingSession;
|
||||
uint256 public override startWeavingSession;
|
||||
|
||||
mapping(uint256 => mapping(uint256 => Checkpoints.Trace256)) internal _treeNodes;
|
||||
mapping(uint256 => mapping(uint256 => Checkpoints.Trace160)) internal _slotLenghts;
|
||||
mapping(uint256 => mapping(uint256 => bytes32[])) internal _slotValues;
|
||||
mapping(uint256 => uint256) internal _filledEntries;
|
||||
|
||||
constructor(address _previousWeaver) {
|
||||
previousWeaver = _previousWeaver;
|
||||
if (_previousWeaver != address(0)) {
|
||||
uint256 newSession = IWeaver(_previousWeaver).currentSession() + 1;
|
||||
currentSession = newSession;
|
||||
startSession = newSession;
|
||||
constructor(address _previousAddress) {
|
||||
if (_previousAddress != address(0)) {
|
||||
uint256 newSession = IWeaver(_previousAddress).currentWeavingSession() + 1;
|
||||
currentWeavingSession = newSession;
|
||||
startWeavingSession = newSession;
|
||||
}
|
||||
}
|
||||
|
||||
function previousAddress() external virtual view returns (address);
|
||||
|
||||
function getSlotValues(
|
||||
uint256 globalIndex,
|
||||
uint256 session,
|
||||
uint256 atBlock
|
||||
) external override view returns (bytes32[] memory) {
|
||||
if (session < startSession) {
|
||||
return IWeaver(previousWeaver).getSlotValues(globalIndex, session, atBlock);
|
||||
if (session < startWeavingSession) {
|
||||
return IWeaver(this.previousAddress()).getSlotValues(globalIndex, session, atBlock);
|
||||
}
|
||||
|
||||
uint256 slotIndex = globalIndex % SLOTS;
|
||||
@ -56,8 +56,8 @@ abstract contract Weaver is IWeaver {
|
||||
}
|
||||
|
||||
function getRoot(uint256 session, uint256 atBlock) public override view returns (bytes32, uint256) {
|
||||
if (session < startSession) {
|
||||
return IWeaver(previousWeaver).getRoot(session, atBlock);
|
||||
if (session < startWeavingSession) {
|
||||
return IWeaver(this.previousAddress()).getRoot(session, atBlock);
|
||||
}
|
||||
|
||||
uint256 currentLevelCount = SLOTS >> 1;
|
||||
@ -89,7 +89,7 @@ abstract contract Weaver is IWeaver {
|
||||
}
|
||||
}
|
||||
|
||||
if (session < currentSession) {
|
||||
if (session < currentWeavingSession) {
|
||||
unchecked { ++session; }
|
||||
}
|
||||
|
||||
@ -101,8 +101,8 @@ abstract contract Weaver is IWeaver {
|
||||
uint256 session,
|
||||
uint256 atBlock
|
||||
) external override view returns (bytes32[] memory) {
|
||||
if (session < startSession) {
|
||||
return IWeaver(previousWeaver).getProof(globalIndex, session, atBlock);
|
||||
if (session < startWeavingSession) {
|
||||
return IWeaver(this.previousAddress()).getProof(globalIndex, session, atBlock);
|
||||
}
|
||||
|
||||
uint256 currentLevelCount = SLOTS;
|
||||
@ -143,11 +143,11 @@ abstract contract Weaver is IWeaver {
|
||||
}
|
||||
|
||||
function _insertTreeNode(bytes32 who, uint256 amount) internal returns (uint256 globalIndex) {
|
||||
uint256 session = currentSession;
|
||||
uint256 session = currentWeavingSession;
|
||||
globalIndex = _filledEntries[session];
|
||||
if (globalIndex >= ENTRIES) {
|
||||
unchecked { ++session; }
|
||||
currentSession = session;
|
||||
currentWeavingSession = session;
|
||||
globalIndex = 0;
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user