make gatekeeper extnesions abstract contracts

Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
This commit is contained in:
Uncle Stretch 2026-07-23 21:15:14 +03:00
parent 424535e1f1
commit f9015bf9a5
Signed by: str3tch
GPG Key ID: 84F3190747EE79AA
5 changed files with 175 additions and 151 deletions

View File

@ -1,36 +1,20 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity ^0.8.20; pragma solidity ^0.8.20;
import {Hashes} from "./libraries/Hashes.sol";
import {IGatekeeper} from "./interfaces/IGatekeeper.sol"; import {IGatekeeper} from "./interfaces/IGatekeeper.sol";
import {IGatekeeperWeaver} from "./interfaces/IGatekeeperWeaver.sol"; import {Metadata} from "./types/Metadata.sol";
import {Weaver} from "./types/Weaver.sol";
import {IGatekeeperMetadata} from "./interfaces/IGatekeeperMetadata.sol";
import {Checkpoints} from "./libraries/Checkpoints.sol";
contract Gatekeeper is IGatekeeper, IGatekeeperMetadata, IGatekeeperWeaver {
using Checkpoints for Checkpoints.Trace256;
using Checkpoints for Checkpoints.Trace160;
contract Gatekeeper is IGatekeeper, Metadata, Weaver {
uint256 public constant DIVISOR = 1e6; uint256 public constant DIVISOR = 1e6;
uint256 public constant DEPTH = 8;
uint256 public constant SLOTS = 2 ** DEPTH;
uint256 public constant ENTRIES = DEPTH * SLOTS;
uint256 public override existentialDeposit; uint256 public override existentialDeposit;
uint256 public override ghostedSupply; uint256 public override ghostedSupply;
uint256 public currentSession;
address public immutable staking; // forge-lint: disable-line(screaming-snake-case-immutable) address public immutable staking; // forge-lint: disable-line(screaming-snake-case-immutable)
GatekeeperMetadata private _metadata;
uint256 private _aggregatedPublicKey; uint256 private _aggregatedPublicKey;
mapping(uint256 => mapping(uint256 => bool)) private _executedTransaction; mapping(uint256 => mapping(uint256 => bool)) private _executedTransaction;
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( constructor(
address _staking, address _staking,
uint256 _ghostedSupply, uint256 _ghostedSupply,
@ -38,109 +22,10 @@ contract Gatekeeper is IGatekeeper, IGatekeeperMetadata, IGatekeeperWeaver {
uint48 _deployedAt, uint48 _deployedAt,
uint104 _amountIn, uint104 _amountIn,
uint104 _amountOut uint104 _amountOut
) { ) Metadata(_deployedAt, _amountIn, _amountOut) Weaver() {
existentialDeposit = _existential; existentialDeposit = _existential;
ghostedSupply = _ghostedSupply; ghostedSupply = _ghostedSupply;
staking = _staking; staking = _staking;
_metadata = GatekeeperMetadata({
deployedAt: _deployedAt,
amountIn: _amountIn,
amountOut: _amountOut
});
}
function metadata() external view returns (GatekeeperMetadata memory) {
return _metadata;
}
function getSlotValues(
uint256 globalIndex,
uint256 session,
uint256 atBlock
) external view returns (bytes32[] memory) {
uint256 slotIndex = globalIndex % SLOTS;
// forge-lint: disable-next-line(unsafe-typecast)
uint256 length = _slotLenghts[session][slotIndex].upperLookupRecent(uint96(atBlock));
bytes32[] memory values = new bytes32[](length);
uint256 i;
for (; i < length; ) {
values[i] = _slotValues[session][slotIndex][i];
unchecked { ++i; }
}
return values;
}
function getRoot(uint256 session, uint256 atBlock) public view returns (bytes32, uint256) {
uint256 currentLevelCount = SLOTS >> 1;
bytes32[] memory currentLevel = new bytes32[](currentLevelCount);
uint256 i;
for (; i < currentLevelCount;) {
uint256 j = i << 1;
bytes32 left = bytes32(_treeNodes[session][j].upperLookup(atBlock));
bytes32 right = bytes32(_treeNodes[session][j | 1].upperLookup(atBlock));
currentLevel[i] = Hashes.efficientKeccak256(left, right);
unchecked { ++i; }
}
while (currentLevelCount > 1) {
currentLevelCount >>= 1;
i = 0;
for (; i < currentLevelCount;) {
uint256 j = i << 1;
bytes32 left = currentLevel[j];
bytes32 right = currentLevel[j | 1];
currentLevel[i] = Hashes.efficientKeccak256(left, right);
unchecked { ++i; }
}
}
return (currentLevel[0], _filledEntries[session]);
}
function getProof(
uint256 globalIndex,
uint256 session,
uint256 atBlock
) external view returns (bytes32[] memory) {
uint256 currentLevelCount = SLOTS;
uint256 currentIndex = globalIndex % SLOTS;
bytes32[] memory proof = new bytes32[](DEPTH);
bytes32[] memory currentLevel = new bytes32[](currentLevelCount);
uint256 i;
for (; i < currentLevelCount;) {
currentLevel[i] = bytes32(_treeNodes[session][i].upperLookup(atBlock));
unchecked { ++i; }
}
uint256 proofIndex;
while (currentLevelCount > 1) {
currentLevelCount >>= 1;
uint256 siblingIndex = currentIndex ^ 1;
proof[proofIndex] = currentLevel[siblingIndex];
i = 0;
for (; i < currentLevelCount;) {
uint256 j = i << 1;
bytes32 left = currentLevel[j];
bytes32 right = currentLevel[j | 1];
currentLevel[i] = Hashes.efficientKeccak256(left, right);
unchecked { ++i; }
}
currentIndex >>= 1;
unchecked { ++proofIndex; }
}
return proof;
} }
function ghost(bytes32 receiver, uint256 amount) external override returns (uint256) { function ghost(bytes32 receiver, uint256 amount) external override returns (uint256) {
@ -216,34 +101,4 @@ contract Gatekeeper is IGatekeeper, IGatekeeperMetadata, IGatekeeperWeaver {
// always bad signature for now // always bad signature for now
return true; return true;
} }
function _insertTreeNode(bytes32 who, uint256 amount) private returns (uint256 globalIndex) {
uint256 session = currentSession;
globalIndex = _filledEntries[session];
if (globalIndex >= ENTRIES) {
unchecked { ++session; }
currentSession = session;
globalIndex = 0;
}
uint256 slotIndex = globalIndex % SLOTS;
uint256 valueIndex = globalIndex / SLOTS;
uint160 length = uint160(_slotValues[session][slotIndex].length + 1);
bytes32 preimage = _computeArgumentsHash(valueIndex, amount, who);
bytes32 currHash = Hashes.efficientKeccak256(preimage);
bytes32 slotHash = bytes32(_treeNodes[session][slotIndex].latest());
slotHash = Hashes.efficientKeccak256(slotHash, currHash);
_treeNodes[session][slotIndex].push(block.number, uint256(slotHash));
_slotLenghts[session][slotIndex].push(uint96(block.number), length);
_slotValues[session][slotIndex].push(preimage);
unchecked { ++_filledEntries[session]; }
}
function _computeArgumentsHash(uint256 i, uint256 a, bytes32 r) internal pure returns (bytes32) {
return Hashes.efficientKeccak256(bytes32(i), Hashes.efficientKeccak256(bytes32(a), r));
}
} }

View File

@ -1,7 +1,7 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity ^0.8.20; pragma solidity ^0.8.20;
interface IGatekeeperMetadata { interface IMetadata {
struct GatekeeperMetadata { struct GatekeeperMetadata {
uint48 deployedAt; uint48 deployedAt;
uint104 amountIn; uint104 amountIn;

View File

@ -1,7 +1,7 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity ^0.8.20; pragma solidity ^0.8.20;
interface IGatekeeperWeaver { interface IWeaver {
function getSlotValues(uint256 globalIndex, uint256 session, uint256 atBlock) external returns (bytes32[] memory); function getSlotValues(uint256 globalIndex, uint256 session, uint256 atBlock) external returns (bytes32[] memory);
function getProof(uint256 globalIndex, uint256 session, uint256 atBlock) external returns (bytes32[] memory); function getProof(uint256 globalIndex, uint256 session, uint256 atBlock) external returns (bytes32[] memory);
function getRoot(uint256 session, uint256 atBlock) external returns (bytes32, uint256); function getRoot(uint256 session, uint256 atBlock) external returns (bytes32, uint256);

24
src/types/Metadata.sol Normal file
View File

@ -0,0 +1,24 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {IMetadata} from "../interfaces/IMetadata.sol";
abstract contract Metadata is IMetadata {
GatekeeperMetadata internal _metadata;
constructor(
uint48 _deployedAt,
uint104 _amountIn,
uint104 _amountOut
) {
_metadata = GatekeeperMetadata({
deployedAt: _deployedAt,
amountIn: _amountIn,
amountOut: _amountOut
});
}
function metadata() external view returns (GatekeeperMetadata memory) {
return _metadata;
}
}

145
src/types/Weaver.sol Normal file
View File

@ -0,0 +1,145 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {IWeaver} from "../interfaces/IWeaver.sol";
import {Hashes} from "../libraries/Hashes.sol";
import {Checkpoints} from "../libraries/Checkpoints.sol";
abstract contract Weaver is IWeaver {
using Checkpoints for Checkpoints.Trace256;
using Checkpoints for Checkpoints.Trace160;
uint256 public constant DEPTH = 8;
uint256 public constant SLOTS = 2 ** DEPTH;
uint256 public constant ENTRIES = DEPTH * SLOTS;
uint256 public currentSession;
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() {}
function getSlotValues(
uint256 globalIndex,
uint256 session,
uint256 atBlock
) external view returns (bytes32[] memory) {
uint256 slotIndex = globalIndex % SLOTS;
// forge-lint: disable-next-line(unsafe-typecast)
uint256 length = _slotLenghts[session][slotIndex].upperLookupRecent(uint96(atBlock));
bytes32[] memory values = new bytes32[](length);
uint256 i;
for (; i < length; ) {
values[i] = _slotValues[session][slotIndex][i];
unchecked { ++i; }
}
return values;
}
function getRoot(uint256 session, uint256 atBlock) public view returns (bytes32, uint256) {
uint256 currentLevelCount = SLOTS >> 1;
bytes32[] memory currentLevel = new bytes32[](currentLevelCount);
uint256 i;
for (; i < currentLevelCount;) {
uint256 j = i << 1;
bytes32 left = bytes32(_treeNodes[session][j].upperLookup(atBlock));
bytes32 right = bytes32(_treeNodes[session][j | 1].upperLookup(atBlock));
currentLevel[i] = Hashes.efficientKeccak256(left, right);
unchecked { ++i; }
}
while (currentLevelCount > 1) {
currentLevelCount >>= 1;
i = 0;
for (; i < currentLevelCount;) {
uint256 j = i << 1;
bytes32 left = currentLevel[j];
bytes32 right = currentLevel[j | 1];
currentLevel[i] = Hashes.efficientKeccak256(left, right);
unchecked { ++i; }
}
}
return (currentLevel[0], _filledEntries[session]);
}
function getProof(
uint256 globalIndex,
uint256 session,
uint256 atBlock
) external view returns (bytes32[] memory) {
uint256 currentLevelCount = SLOTS;
uint256 currentIndex = globalIndex % SLOTS;
bytes32[] memory proof = new bytes32[](DEPTH);
bytes32[] memory currentLevel = new bytes32[](currentLevelCount);
uint256 i;
for (; i < currentLevelCount;) {
currentLevel[i] = bytes32(_treeNodes[session][i].upperLookup(atBlock));
unchecked { ++i; }
}
uint256 proofIndex;
while (currentLevelCount > 1) {
currentLevelCount >>= 1;
uint256 siblingIndex = currentIndex ^ 1;
proof[proofIndex] = currentLevel[siblingIndex];
i = 0;
for (; i < currentLevelCount;) {
uint256 j = i << 1;
bytes32 left = currentLevel[j];
bytes32 right = currentLevel[j | 1];
currentLevel[i] = Hashes.efficientKeccak256(left, right);
unchecked { ++i; }
}
currentIndex >>= 1;
unchecked { ++proofIndex; }
}
return proof;
}
function _insertTreeNode(bytes32 who, uint256 amount) internal returns (uint256 globalIndex) {
uint256 session = currentSession;
globalIndex = _filledEntries[session];
if (globalIndex >= ENTRIES) {
unchecked { ++session; }
currentSession = session;
globalIndex = 0;
}
uint256 slotIndex = globalIndex % SLOTS;
uint256 valueIndex = globalIndex / SLOTS;
uint160 length = uint160(_slotValues[session][slotIndex].length + 1);
bytes32 preimage = _computeArgumentsHash(valueIndex, amount, who);
bytes32 currHash = Hashes.efficientKeccak256(preimage);
bytes32 slotHash = bytes32(_treeNodes[session][slotIndex].latest());
slotHash = Hashes.efficientKeccak256(slotHash, currHash);
_treeNodes[session][slotIndex].push(block.number, uint256(slotHash));
_slotLenghts[session][slotIndex].push(uint96(block.number), length);
_slotValues[session][slotIndex].push(preimage);
unchecked { ++_filledEntries[session]; }
}
function _computeArgumentsHash(uint256 i, uint256 a, bytes32 r) internal pure returns (bytes32) {
return Hashes.efficientKeccak256(bytes32(i), Hashes.efficientKeccak256(bytes32(a), r));
}
}