From c4f4f2e0e2e3246d350d6392c6ec34225e4fd0c4 Mon Sep 17 00:00:00 2001 From: Uncle Fatso Date: Mon, 24 Aug 2026 15:08:39 +0300 Subject: [PATCH] verification logic into gatekeeper added, full contract inheritance added Signed-off-by: Uncle Fatso --- src/Gatekeeper.sol | 247 ++++++++++++++++++++++------- src/Staking.sol | 35 ++-- src/interfaces/IGatekeeper.sol | 22 ++- src/interfaces/IMetadata.sol | 12 -- src/interfaces/IStaking.sol | 3 +- src/interfaces/IStorageHistory.sol | 24 +++ src/interfaces/IWeaver.sol | 4 +- src/mocks/WeaverMock.sol | 10 +- src/types/Metadata.sol | 29 ---- src/types/StorageHistory.sol | 59 +++++++ src/types/Weaver.sol | 36 ++--- 11 files changed, 339 insertions(+), 142 deletions(-) delete mode 100644 src/interfaces/IMetadata.sol create mode 100644 src/interfaces/IStorageHistory.sol delete mode 100644 src/types/Metadata.sol create mode 100644 src/types/StorageHistory.sol diff --git a/src/Gatekeeper.sol b/src/Gatekeeper.sol index a0f3cb5..6155575 100644 --- a/src/Gatekeeper.sol +++ b/src/Gatekeeper.sol @@ -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); } } diff --git a/src/Staking.sol b/src/Staking.sol index cb31205..80efc1c 100644 --- a/src/Staking.sol +++ b/src/Staking.sol @@ -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) { diff --git a/src/interfaces/IGatekeeper.sol b/src/interfaces/IGatekeeper.sol index ae98ddd..e57972a 100644 --- a/src/interfaces/IGatekeeper.sol +++ b/src/interfaces/IGatekeeper.sol @@ -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; } diff --git a/src/interfaces/IMetadata.sol b/src/interfaces/IMetadata.sol deleted file mode 100644 index 4428c63..0000000 --- a/src/interfaces/IMetadata.sol +++ /dev/null @@ -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); -} diff --git a/src/interfaces/IStaking.sol b/src/interfaces/IStaking.sol index 35f80fa..e64a9c5 100644 --- a/src/interfaces/IStaking.sol +++ b/src/interfaces/IStaking.sol @@ -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); diff --git a/src/interfaces/IStorageHistory.sol b/src/interfaces/IStorageHistory.sol new file mode 100644 index 0000000..8c57e44 --- /dev/null +++ b/src/interfaces/IStorageHistory.sol @@ -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; +} diff --git a/src/interfaces/IWeaver.sol b/src/interfaces/IWeaver.sol index 8682fb7..f6cd936 100644 --- a/src/interfaces/IWeaver.sol +++ b/src/interfaces/IWeaver.sol @@ -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); diff --git a/src/mocks/WeaverMock.sol b/src/mocks/WeaverMock.sol index b060569..8f59256 100644 --- a/src/mocks/WeaverMock.sol +++ b/src/mocks/WeaverMock.sol @@ -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); diff --git a/src/types/Metadata.sol b/src/types/Metadata.sol deleted file mode 100644 index a8e8769..0000000 --- a/src/types/Metadata.sol +++ /dev/null @@ -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; - } -} diff --git a/src/types/StorageHistory.sol b/src/types/StorageHistory.sol new file mode 100644 index 0000000..83aa351 --- /dev/null +++ b/src/types/StorageHistory.sol @@ -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); + } +} diff --git a/src/types/Weaver.sol b/src/types/Weaver.sol index 61dbe63..ddba959 100644 --- a/src/types/Weaver.sol +++ b/src/types/Weaver.sol @@ -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; }