Compare commits
4 Commits
45e730a8ce
...
3f4e6ff8f5
| Author | SHA1 | Date | |
|---|---|---|---|
| 3f4e6ff8f5 | |||
| 5f01391cb7 | |||
| de2e49c877 | |||
| 40c203a6b0 |
@ -101,10 +101,12 @@ GOVERNOR_VOTING_PERIOD=
|
|||||||
GOVERNOR_PROPOSAL_THRESHOLD=
|
GOVERNOR_PROPOSAL_THRESHOLD=
|
||||||
GOVERNOR_QUORUM_FRACTION=
|
GOVERNOR_QUORUM_FRACTION=
|
||||||
|
|
||||||
###################### Initial ghosted supply on gatekeeper ###########################
|
############################# Gatekeeper Deployment ##################################
|
||||||
## previousWeaver - previous weaver address if any to make linked list of weavers ##
|
## previousWeaver - previous weaver address if any to make linked list of weavers ##
|
||||||
#######################################################################################
|
## previousStaking - previous staking address that will initialize the gatekeeper ##
|
||||||
|
######################################################################################
|
||||||
PREVIOUS_WEAVER_ADDRESS=
|
PREVIOUS_WEAVER_ADDRESS=
|
||||||
|
PREVIOUS_STAKING_ADDRESS=
|
||||||
|
|
||||||
SEPOLIA_TEST_RPC_URL=
|
SEPOLIA_TEST_RPC_URL=
|
||||||
SEPOLIA_TEST_API_KEY=
|
SEPOLIA_TEST_API_KEY=
|
||||||
|
|||||||
@ -150,7 +150,7 @@ contract GhostBondDepository is IBondDepository, NoteKeeper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function create(
|
function create(
|
||||||
uint256[3] calldata _market,
|
uint256[4] calldata _market,
|
||||||
uint256[2] calldata _terms,
|
uint256[2] calldata _terms,
|
||||||
address _quoteToken,
|
address _quoteToken,
|
||||||
uint32[2] calldata _intervals,
|
uint32[2] calldata _intervals,
|
||||||
@ -169,19 +169,20 @@ contract GhostBondDepository is IBondDepository, NoteKeeper {
|
|||||||
|
|
||||||
// forge-lint: disable-next-line(unsafe-typecast)
|
// forge-lint: disable-next-line(unsafe-typecast)
|
||||||
uint64 maxPayout = uint64(FullMath.mulDiv(targetDebt, _intervals[0], secondsToConclusion));
|
uint64 maxPayout = uint64(FullMath.mulDiv(targetDebt, _intervals[0], secondsToConclusion));
|
||||||
uint256 maxDebt = targetDebt + FullMath.mulDiv(targetDebt, _market[2], 1e5);
|
uint256 maxDebt = targetDebt + FullMath.mulDiv(targetDebt, _market[3], 1e5);
|
||||||
uint256 controlVariable = FullMath.mulDiv(_market[1], ITreasury(TREASURY).baseSupply(), targetDebt);
|
uint256 controlVariable = FullMath.mulDiv(_market[1], ITreasury(TREASURY).baseSupply(), targetDebt);
|
||||||
|
|
||||||
id = markets.length;
|
id = markets.length;
|
||||||
|
|
||||||
markets.push(
|
markets.push(
|
||||||
Market({
|
Market({
|
||||||
|
capacity: _market[0],
|
||||||
|
purchased: 0,
|
||||||
|
minimumPrice: _market[2],
|
||||||
quoteToken: _quoteToken,
|
quoteToken: _quoteToken,
|
||||||
capacityInQuote: _booleans[0],
|
capacityInQuote: _booleans[0],
|
||||||
capacity: _market[0],
|
|
||||||
totalDebt: targetDebt,
|
totalDebt: targetDebt,
|
||||||
maxPayout: maxPayout,
|
maxPayout: maxPayout,
|
||||||
purchased: 0,
|
|
||||||
sold: 0
|
sold: 0
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@ -225,7 +226,9 @@ contract GhostBondDepository is IBondDepository, NoteKeeper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function marketPrice(uint256 id) public view override returns (uint256) {
|
function marketPrice(uint256 id) public view override returns (uint256) {
|
||||||
return FullMath.mulDiv(currentControlVariable(id), debtRatio(id), 10**metadatas[id].quoteDecimals);
|
uint256 minimumPrice = markets[id].minimumPrice;
|
||||||
|
uint256 currentPrice = FullMath.mulDiv(currentControlVariable(id), debtRatio(id), 10**metadatas[id].quoteDecimals);
|
||||||
|
return currentPrice > minimumPrice ? currentPrice : minimumPrice;
|
||||||
}
|
}
|
||||||
|
|
||||||
function payoutFor(
|
function payoutFor(
|
||||||
@ -311,7 +314,9 @@ contract GhostBondDepository is IBondDepository, NoteKeeper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function _marketPrice(uint256 _id) internal view returns (uint256) {
|
function _marketPrice(uint256 _id) internal view returns (uint256) {
|
||||||
return FullMath.mulDiv(terms[_id].controlVariable, _debtRatio(_id), 10**metadatas[_id].quoteDecimals);
|
uint256 minimumPrice = markets[_id].minimumPrice;
|
||||||
|
uint256 currentPrice = FullMath.mulDiv(terms[_id].controlVariable, _debtRatio(_id), 10**metadatas[_id].quoteDecimals);
|
||||||
|
return currentPrice > minimumPrice ? currentPrice : minimumPrice;
|
||||||
}
|
}
|
||||||
|
|
||||||
function _debtRatio(uint256 id) internal view returns (uint256) {
|
function _debtRatio(uint256 id) internal view returns (uint256) {
|
||||||
|
|||||||
@ -22,49 +22,48 @@ contract Gatekeeper is IGatekeeper, Weaver, ReentrancyGuard {
|
|||||||
using GovernancePacking for GovernancePacking.GovernancePayload;
|
using GovernancePacking for GovernancePacking.GovernancePayload;
|
||||||
|
|
||||||
uint256 public constant BOUNTY_DIVISOR = type(uint32).max;
|
uint256 public constant BOUNTY_DIVISOR = type(uint32).max;
|
||||||
uint256 public constant MAX_ALLOWED_GAS_PRICE = 3e9; // 3 gwei
|
uint256 public constant EXISTENTIAL_DEPOSIT = 500 * 1e12; // 0.005
|
||||||
uint256 public constant EXISTENTIAL_DEPOSIT = 500 * 1e12;
|
uint256 public constant FULL_GAS_RESTORATION_TIME = 3600; // 1 hour
|
||||||
uint256 public constant GAS_EXECUTION_BUFFER = 33805;
|
uint256 public constant MAX_ALLOWED_GAS_PRICE = 3e9; // 3 gwei
|
||||||
|
uint256 public constant GAS_EXECUTION_BUFFER = 21000 + 5969 + 50955;
|
||||||
uint256 public constant REGISTRY_INDEX = 0;
|
uint256 public constant REGISTRY_INDEX = 0;
|
||||||
|
|
||||||
address public override staking;
|
address public override staking;
|
||||||
address public override deployer;
|
address public override deployer;
|
||||||
address public override storageHistory;
|
address public override storageHistory;
|
||||||
|
|
||||||
|
uint256 private _lastVerificationTime;
|
||||||
address private _previousAddress;
|
address private _previousAddress;
|
||||||
bool private _initialized;
|
bool private _initialized;
|
||||||
|
|
||||||
Checkpoints.Trace256 private _aggregatedPublicKeys;
|
Checkpoints.Trace256 private _aggregatedPublicKeys;
|
||||||
mapping(bytes32 => uint256) private _packedRotationStates;
|
mapping(bytes32 => uint256) private _packedRotationStates;
|
||||||
|
|
||||||
constructor(address _storageHistory) {
|
constructor(address _storageHistory, address _staking) {
|
||||||
storageHistory = _storageHistory;
|
storageHistory = _storageHistory;
|
||||||
staking = msg.sender;
|
staking = _staking;
|
||||||
deployer = tx.origin;
|
deployer = tx.origin;
|
||||||
}
|
}
|
||||||
|
|
||||||
receive() external payable {}
|
receive() external payable {}
|
||||||
|
|
||||||
function initialize(address _previousGatekeeperAddress) external override {
|
function initialize(address _previousGatekeeperAddress) external override {
|
||||||
|
require(msg.sender == staking);
|
||||||
|
|
||||||
if (_previousGatekeeperAddress != address(0)) {
|
if (_previousGatekeeperAddress != address(0)) {
|
||||||
require(_initialized == false);
|
require(_initialized == false);
|
||||||
require(_previousGatekeeperAddress != address(this));
|
require(_previousGatekeeperAddress != address(this));
|
||||||
|
|
||||||
address previousStorage = IGatekeeper(_previousGatekeeperAddress).storageHistory();
|
address previousStorage = IGatekeeper(_previousGatekeeperAddress).storageHistory();
|
||||||
address previousStaking = IGatekeeper(_previousGatekeeperAddress).staking();
|
|
||||||
|
|
||||||
require(previousStorage != address(0));
|
require(previousStorage != address(0));
|
||||||
require(previousStaking != address(0));
|
|
||||||
|
|
||||||
storageHistory = previousStorage;
|
storageHistory = previousStorage;
|
||||||
staking = previousStaking;
|
|
||||||
deployer = IGatekeeper(_previousGatekeeperAddress).deployer();
|
deployer = IGatekeeper(_previousGatekeeperAddress).deployer();
|
||||||
Weaver._initialize(_previousGatekeeperAddress);
|
Weaver._initialize(_previousGatekeeperAddress);
|
||||||
|
|
||||||
_previousAddress = _previousGatekeeperAddress;
|
_previousAddress = _previousGatekeeperAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
require(msg.sender == staking);
|
|
||||||
_initialized = true;
|
_initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,7 +88,7 @@ contract Gatekeeper is IGatekeeper, Weaver, ReentrancyGuard {
|
|||||||
return IStorageHistory(storageHistory).bridgeImbalance();
|
return IStorageHistory(storageHistory).bridgeImbalance();
|
||||||
}
|
}
|
||||||
|
|
||||||
function latestPublicKeyInfo() external override view returns (bytes32, uint8, uint64) {
|
function latestPublicKeyInfo() external view returns (bytes32, uint8, uint64) {
|
||||||
bytes32 latestPublicKey = bytes32(_aggregatedPublicKeys.latest());
|
bytes32 latestPublicKey = bytes32(_aggregatedPublicKeys.latest());
|
||||||
uint256 packed = _packedRotationStates[latestPublicKey];
|
uint256 packed = _packedRotationStates[latestPublicKey];
|
||||||
|
|
||||||
@ -109,6 +108,16 @@ contract Gatekeeper is IGatekeeper, Weaver, ReentrancyGuard {
|
|||||||
return (publicKey, state.parity, state.session);
|
return (publicKey, state.parity, state.session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getCurrentGasPrice() public view returns (uint256) {
|
||||||
|
uint256 timePassed = block.timestamp - _lastVerificationTime;
|
||||||
|
|
||||||
|
if (timePassed >= FULL_GAS_RESTORATION_TIME) {
|
||||||
|
return MAX_ALLOWED_GAS_PRICE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FullMath.mulDiv(MAX_ALLOWED_GAS_PRICE, timePassed, FULL_GAS_RESTORATION_TIME);
|
||||||
|
}
|
||||||
|
|
||||||
function ghost(bytes32 receiver, uint256 amount) external override {
|
function ghost(bytes32 receiver, uint256 amount) external override {
|
||||||
if (msg.sender != staking) revert NotStaking();
|
if (msg.sender != staking) revert NotStaking();
|
||||||
if (amount < EXISTENTIAL_DEPOSIT) revert NonExistentAmount();
|
if (amount < EXISTENTIAL_DEPOSIT) revert NonExistentAmount();
|
||||||
@ -121,25 +130,24 @@ contract Gatekeeper is IGatekeeper, Weaver, ReentrancyGuard {
|
|||||||
bytes calldata call,
|
bytes calldata call,
|
||||||
uint256 rx,
|
uint256 rx,
|
||||||
uint256 s
|
uint256 s
|
||||||
) external nonReentrant returns (bytes memory) {
|
) external nonReentrant {
|
||||||
uint256 gasStart = gasleft();
|
uint256 gasStart = gasleft();
|
||||||
uint256 px = _extractPublicKey(call);
|
uint256 px = _extractPublicKey(call);
|
||||||
|
|
||||||
bool validSignature = Verifier.verifyGhost(call, px, rx, s);
|
bool validSignature = Verifier.verifyGhost(call, px, rx, s);
|
||||||
if (!validSignature) revert BadSignature();
|
if (!validSignature) revert BadSignature();
|
||||||
|
|
||||||
(bool success, bytes memory data) = address(this).call(call);
|
(bool success,) = address(this).call(call);
|
||||||
if (!success) revert ExecutionReverted();
|
if (!success) revert ExecutionReverted();
|
||||||
|
|
||||||
uint256 gasPrice = MAX_ALLOWED_GAS_PRICE < tx.gasprice ? MAX_ALLOWED_GAS_PRICE : tx.gasprice;
|
uint256 currentGasPrice = getCurrentGasPrice();
|
||||||
uint256 gasSpent = (gasStart - gasleft() + GAS_EXECUTION_BUFFER) * gasPrice;
|
_lastVerificationTime = block.timestamp;
|
||||||
|
|
||||||
|
uint256 gasSpent = (gasStart - gasleft() + GAS_EXECUTION_BUFFER) * currentGasPrice;
|
||||||
try IStaking(staking).phantomRefund(msg.sender, gasSpent, REGISTRY_INDEX) {}
|
try IStaking(staking).phantomRefund(msg.sender, gasSpent, REGISTRY_INDEX) {}
|
||||||
catch {
|
catch {
|
||||||
emit VoluntaryVerification(msg.sender, gasSpent);
|
emit VoluntaryVerification(msg.sender, gasSpent);
|
||||||
}
|
}
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function recall(
|
function recall(
|
||||||
@ -152,7 +160,8 @@ contract Gatekeeper is IGatekeeper, Weaver, ReentrancyGuard {
|
|||||||
RequestPacking.RequestPayload memory payload = RequestPacking.unpack(packed);
|
RequestPacking.RequestPayload memory payload = RequestPacking.unpack(packed);
|
||||||
if (payload.chainId != block.chainid) revert WrongChainId();
|
if (payload.chainId != block.chainid) revert WrongChainId();
|
||||||
|
|
||||||
uint256 bountyAmount = FullMath.mulDiv(amount, uint256(payload.bounty), BOUNTY_DIVISOR);
|
uint256 requestedBountyAmount = FullMath.mulDiv(amount, uint256(payload.bounty), BOUNTY_DIVISOR);
|
||||||
|
uint256 bountyAmount = _isContract(payload.receiver) ? 0 : requestedBountyAmount;
|
||||||
uint256 receiverAmount = amount - bountyAmount;
|
uint256 receiverAmount = amount - bountyAmount;
|
||||||
|
|
||||||
StorageHistory(storageHistory).trySetTransactionExecuted(exodusSession);
|
StorageHistory(storageHistory).trySetTransactionExecuted(exodusSession);
|
||||||
@ -163,7 +172,7 @@ contract Gatekeeper is IGatekeeper, Weaver, ReentrancyGuard {
|
|||||||
(address token, uint256 sent) = IStaking(staking).recall(bountyAmount, REGISTRY_INDEX);
|
(address token, uint256 sent) = IStaking(staking).recall(bountyAmount, REGISTRY_INDEX);
|
||||||
IWETH9(token).withdraw(sent);
|
IWETH9(token).withdraw(sent);
|
||||||
|
|
||||||
(bool sentSuccess,) = payload.receiver.call{ value: sent }("");
|
(bool sentSuccess,) = payload.receiver.call{ value: sent, gas: 3000 }("");
|
||||||
if (!sentSuccess) revert SendFailed();
|
if (!sentSuccess) revert SendFailed();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,8 +200,8 @@ contract Gatekeeper is IGatekeeper, Weaver, ReentrancyGuard {
|
|||||||
function govern(
|
function govern(
|
||||||
uint256 exodusSession,
|
uint256 exodusSession,
|
||||||
uint256 packed,
|
uint256 packed,
|
||||||
bytes calldata
|
bytes calldata call
|
||||||
) external returns (bytes memory) {
|
) external {
|
||||||
if (msg.sender != address(this)) revert NotGatekeeper();
|
if (msg.sender != address(this)) revert NotGatekeeper();
|
||||||
|
|
||||||
GovernancePacking.GovernancePayload memory payload = GovernancePacking.unpack(packed);
|
GovernancePacking.GovernancePayload memory payload = GovernancePacking.unpack(packed);
|
||||||
@ -200,10 +209,8 @@ contract Gatekeeper is IGatekeeper, Weaver, ReentrancyGuard {
|
|||||||
|
|
||||||
StorageHistory(storageHistory).trySetTransactionExecuted(exodusSession);
|
StorageHistory(storageHistory).trySetTransactionExecuted(exodusSession);
|
||||||
|
|
||||||
(bool success, bytes memory data) = payload.target.call(msg.data[132:]);
|
(bool success,) = payload.target.call(call);
|
||||||
if (!success) revert ExecutionReverted();
|
if (!success) revert ExecutionReverted();
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function _extractPublicKey(bytes calldata call) internal view returns (uint256) {
|
function _extractPublicKey(bytes calldata call) internal view returns (uint256) {
|
||||||
@ -217,4 +224,12 @@ contract Gatekeeper is IGatekeeper, Weaver, ReentrancyGuard {
|
|||||||
|
|
||||||
return uint256(publicKey);
|
return uint256(publicKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function _isContract(address account) internal view returns (bool) {
|
||||||
|
uint256 size;
|
||||||
|
assembly {
|
||||||
|
size := extcodesize(account)
|
||||||
|
}
|
||||||
|
return size > 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -62,7 +62,7 @@ contract GhostStaking is IStaking, GhostAccessControlled {
|
|||||||
|
|
||||||
GhostWarmup newWarmup = new GhostWarmup(_ghst);
|
GhostWarmup newWarmup = new GhostWarmup(_ghst);
|
||||||
StorageHistory newHistory = new StorageHistory();
|
StorageHistory newHistory = new StorageHistory();
|
||||||
Gatekeeper newGatekeeper = new Gatekeeper(address(newHistory));
|
Gatekeeper newGatekeeper = new Gatekeeper(address(newHistory), address(this));
|
||||||
|
|
||||||
IStorageHistory(newHistory).setOwner(address(newGatekeeper));
|
IStorageHistory(newHistory).setOwner(address(newGatekeeper));
|
||||||
IGatekeeper(newGatekeeper).initialize(address(0));
|
IGatekeeper(newGatekeeper).initialize(address(0));
|
||||||
|
|||||||
@ -18,12 +18,13 @@ interface IBondDepository {
|
|||||||
|
|
||||||
struct Market {
|
struct Market {
|
||||||
uint256 capacity;
|
uint256 capacity;
|
||||||
|
uint256 purchased;
|
||||||
|
uint256 minimumPrice;
|
||||||
address quoteToken;
|
address quoteToken;
|
||||||
bool capacityInQuote;
|
bool capacityInQuote;
|
||||||
uint64 totalDebt;
|
uint64 totalDebt;
|
||||||
uint64 maxPayout;
|
uint64 maxPayout;
|
||||||
uint64 sold;
|
uint64 sold;
|
||||||
uint256 purchased;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Term {
|
struct Term {
|
||||||
@ -65,7 +66,7 @@ interface IBondDepository {
|
|||||||
);
|
);
|
||||||
|
|
||||||
function create(
|
function create(
|
||||||
uint256[3] memory _market,
|
uint256[4] memory _market,
|
||||||
uint256[2] memory _terms,
|
uint256[2] memory _terms,
|
||||||
address _quoteToken,
|
address _quoteToken,
|
||||||
uint32[2] memory _intervals,
|
uint32[2] memory _intervals,
|
||||||
|
|||||||
@ -22,12 +22,8 @@ interface IGatekeeper {
|
|||||||
function deployer() external view returns (address);
|
function deployer() external view returns (address);
|
||||||
function ghostedSupply() external view returns (uint256);
|
function ghostedSupply() external view returns (uint256);
|
||||||
function storageHistory() external view returns (address);
|
function storageHistory() external view returns (address);
|
||||||
function latestPublicKeyInfo() external view returns (bytes32, uint8, uint64);
|
|
||||||
function getRotationInfoAt(uint256 session) external view returns (bytes32, uint8, uint64);
|
function getRotationInfoAt(uint256 session) external view returns (bytes32, uint8, uint64);
|
||||||
|
|
||||||
function govern(uint256 session, uint256 payload, bytes calldata call) external returns (bytes calldata);
|
|
||||||
function recall(uint256 session, uint256 amount, uint256 payload) external;
|
|
||||||
function rotate(uint256 session, bytes32 publicKey, uint8 parity) external;
|
|
||||||
function ghost(bytes32 receiver, uint256 amount) external;
|
function ghost(bytes32 receiver, uint256 amount) external;
|
||||||
function initialize(address previousAddress) external;
|
function initialize(address previousAddress) external;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -121,7 +121,7 @@ contract GhostBondDepositoryTest is Test {
|
|||||||
|
|
||||||
vm.prank(POLICY);
|
vm.prank(POLICY);
|
||||||
depository.create(
|
depository.create(
|
||||||
[CAPACITY, INITIAL_PRICE, BUFFER],
|
[CAPACITY, INITIAL_PRICE, 0, BUFFER],
|
||||||
[VESTING, conclusion],
|
[VESTING, conclusion],
|
||||||
address(reserve),
|
address(reserve),
|
||||||
[uint32(DEPOSIT_INTERVAL), uint32(TUNE_INTERVAL)], // forge-lint: disable-line(unsafe-typecast)
|
[uint32(DEPOSIT_INTERVAL), uint32(TUNE_INTERVAL)], // forge-lint: disable-line(unsafe-typecast)
|
||||||
@ -144,7 +144,7 @@ contract GhostBondDepositoryTest is Test {
|
|||||||
|
|
||||||
vm.prank(POLICY);
|
vm.prank(POLICY);
|
||||||
depository.create(
|
depository.create(
|
||||||
[CAPACITY, INITIAL_PRICE, BUFFER],
|
[CAPACITY, INITIAL_PRICE, 0, BUFFER],
|
||||||
[VESTING, conclusion],
|
[VESTING, conclusion],
|
||||||
address(weth),
|
address(weth),
|
||||||
[uint32(DEPOSIT_INTERVAL), uint32(TUNE_INTERVAL)], // forge-lint: disable-line(unsafe-typecast)
|
[uint32(DEPOSIT_INTERVAL), uint32(TUNE_INTERVAL)], // forge-lint: disable-line(unsafe-typecast)
|
||||||
@ -166,14 +166,14 @@ contract GhostBondDepositoryTest is Test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function test_shouldSetMaxPayoutToCorrectPercentageOfCapacity() public view {
|
function test_shouldSetMaxPayoutToCorrectPercentageOfCapacity() public view {
|
||||||
(, , , , uint256 maxPayout, ,) = depository.markets(0);
|
(, , , , , , uint256 maxPayout,) = depository.markets(0);
|
||||||
assertEq(maxPayout, CAPACITY / 6);
|
assertEq(maxPayout, CAPACITY / 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
function test_shouldReturnIdsOfAllMarkets() public {
|
function test_shouldReturnIdsOfAllMarkets() public {
|
||||||
vm.prank(POLICY);
|
vm.prank(POLICY);
|
||||||
depository.create(
|
depository.create(
|
||||||
[CAPACITY, INITIAL_PRICE, BUFFER],
|
[CAPACITY, INITIAL_PRICE, 0, BUFFER],
|
||||||
[VESTING, conclusion],
|
[VESTING, conclusion],
|
||||||
address(reserve),
|
address(reserve),
|
||||||
[uint32(DEPOSIT_INTERVAL), uint32(TUNE_INTERVAL)], // forge-lint: disable-line(unsafe-typecast)
|
[uint32(DEPOSIT_INTERVAL), uint32(TUNE_INTERVAL)], // forge-lint: disable-line(unsafe-typecast)
|
||||||
@ -186,10 +186,31 @@ contract GhostBondDepositoryTest is Test {
|
|||||||
assertEq(liveMarkets[1], 1);
|
assertEq(liveMarkets[1], 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function test_marketPriceShouldNeverFallBelowMinimum() public {
|
||||||
|
uint256 initialPrice = 420 * 1e9;
|
||||||
|
uint256 minPrice = 69 * 1e9;
|
||||||
|
|
||||||
|
vm.prank(POLICY);
|
||||||
|
uint256 marketId = depository.create(
|
||||||
|
[CAPACITY, initialPrice, minPrice, BUFFER],
|
||||||
|
[VESTING, TIME_TO_CONCLUSION],
|
||||||
|
address(reserve),
|
||||||
|
[uint32(DEPOSIT_INTERVAL), uint32(TUNE_INTERVAL)], // forge-lint: disable-line(unsafe-typecast)
|
||||||
|
[false, true]
|
||||||
|
);
|
||||||
|
|
||||||
|
uint256 currentPrice = depository.marketPrice(marketId);
|
||||||
|
assertEq(currentPrice, initialPrice);
|
||||||
|
|
||||||
|
vm.warp(block.timestamp + TIME_TO_CONCLUSION - 420);
|
||||||
|
uint256 priceAfterDecay = depository.marketPrice(marketId);
|
||||||
|
assertEq(priceAfterDecay, minPrice);
|
||||||
|
}
|
||||||
|
|
||||||
function test_shouldUpdateIdsOfMarkets() public {
|
function test_shouldUpdateIdsOfMarkets() public {
|
||||||
vm.startPrank(POLICY);
|
vm.startPrank(POLICY);
|
||||||
depository.create(
|
depository.create(
|
||||||
[CAPACITY, INITIAL_PRICE, BUFFER],
|
[CAPACITY, INITIAL_PRICE, 0, BUFFER],
|
||||||
[VESTING, conclusion],
|
[VESTING, conclusion],
|
||||||
address(reserve),
|
address(reserve),
|
||||||
[uint32(DEPOSIT_INTERVAL), uint32(TUNE_INTERVAL)], // forge-lint: disable-line(unsafe-typecast)
|
[uint32(DEPOSIT_INTERVAL), uint32(TUNE_INTERVAL)], // forge-lint: disable-line(unsafe-typecast)
|
||||||
@ -221,13 +242,13 @@ contract GhostBondDepositoryTest is Test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function test_shouldDecayDebt() public {
|
function test_shouldDecayDebt() public {
|
||||||
(, , , uint256 totalDebt, , ,) = depository.markets(0);
|
(, , , , , uint256 totalDebt, ,) = depository.markets(0);
|
||||||
|
|
||||||
skip(DEPOSIT_INTERVAL);
|
skip(DEPOSIT_INTERVAL);
|
||||||
vm.prank(ALICE);
|
vm.prank(ALICE);
|
||||||
depository.deposit(0, 0, INITIAL_PRICE, ALICE);
|
depository.deposit(0, 0, INITIAL_PRICE, ALICE);
|
||||||
|
|
||||||
(, , , uint256 newTotalDebt, , ,) = depository.markets(0);
|
(, , , , , uint256 newTotalDebt, ,) = depository.markets(0);
|
||||||
assertEq(totalDebt > newTotalDebt, true);
|
assertEq(totalDebt > newTotalDebt, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -432,7 +453,7 @@ contract GhostBondDepositoryTest is Test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function test_shouldDecayMaxPayoutInTargetDepositInterval() public {
|
function test_shouldDecayMaxPayoutInTargetDepositInterval() public {
|
||||||
(, , , , uint64 maxPayout, ,) = depository.markets(0);
|
(, , , , , , uint64 maxPayout,) = depository.markets(0);
|
||||||
uint256 price = depository.marketPrice(0);
|
uint256 price = depository.marketPrice(0);
|
||||||
uint256 amount = maxPayout * price;
|
uint256 amount = maxPayout * price;
|
||||||
vm.prank(ALICE);
|
vm.prank(ALICE);
|
||||||
@ -443,11 +464,11 @@ contract GhostBondDepositoryTest is Test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function test_shouldCloseMarket() public {
|
function test_shouldCloseMarket() public {
|
||||||
(uint256 cap, , , , , ,) = depository.markets(0);
|
(uint256 cap, , , , , , ,) = depository.markets(0);
|
||||||
assertEq(cap > 0, true);
|
assertEq(cap > 0, true);
|
||||||
vm.prank(POLICY);
|
vm.prank(POLICY);
|
||||||
depository.close(0);
|
depository.close(0);
|
||||||
(uint256 newCap, , , , , ,) = depository.markets(0);
|
(uint256 newCap, , , , , , ,) = depository.markets(0);
|
||||||
assertEq(newCap, 0);
|
assertEq(newCap, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -72,7 +72,7 @@ contract MockGovernance is Test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function create(
|
function create(
|
||||||
uint256[3] calldata market,
|
uint256[4] calldata market,
|
||||||
uint256[2] calldata terms,
|
uint256[2] calldata terms,
|
||||||
address quoteToken,
|
address quoteToken,
|
||||||
uint32[2] calldata intervals,
|
uint32[2] calldata intervals,
|
||||||
@ -83,6 +83,7 @@ contract MockGovernance is Test {
|
|||||||
assertEq(market[0], 69);
|
assertEq(market[0], 69);
|
||||||
assertEq(market[1], 420);
|
assertEq(market[1], 420);
|
||||||
assertEq(market[2], 1337);
|
assertEq(market[2], 1337);
|
||||||
|
assertEq(market[3], 0);
|
||||||
|
|
||||||
assertEq(terms[0], 420);
|
assertEq(terms[0], 420);
|
||||||
assertEq(terms[1], 1337);
|
assertEq(terms[1], 1337);
|
||||||
@ -146,7 +147,7 @@ contract MockStaking is Test {
|
|||||||
constructor() {
|
constructor() {
|
||||||
mockReserve = new WETH9();
|
mockReserve = new WETH9();
|
||||||
StorageHistory history = new StorageHistory();
|
StorageHistory history = new StorageHistory();
|
||||||
gatekeeper = new Gatekeeper(address(history));
|
gatekeeper = new Gatekeeper(address(history), address(this));
|
||||||
gatekeeper.initialize(address(0));
|
gatekeeper.initialize(address(0));
|
||||||
history.setOwner(address(gatekeeper));
|
history.setOwner(address(gatekeeper));
|
||||||
}
|
}
|
||||||
@ -468,12 +469,12 @@ contract GatekeeperTest is Test {
|
|||||||
0x10121ffe0cc95cf3cbb4e92d72d61feec3e94045185cd7f3c5ce0d01e3a644ea
|
0x10121ffe0cc95cf3cbb4e92d72d61feec3e94045185cd7f3c5ce0d01e3a644ea
|
||||||
);
|
);
|
||||||
|
|
||||||
// execute close, exodusSession: 10
|
// execute create, exodusSession: 10
|
||||||
vm.prank(ALICE);
|
vm.prank(ALICE);
|
||||||
gatekeeper.verify(
|
gatekeeper.verify(
|
||||||
hex"31371426000000000000000000000000000000000000000000000000000000000000000a0000000000007a6901010101010101010101010101010101010101010000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000144a0139f41000000000000000000000000000000000000000000000000000000000000004500000000000000000000000000000000000000000000000000000000000001a4000000000000000000000000000000000000000000000000000000000000053900000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000000005390000000000000000000000000101010101010101010101010101010101010101000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000230000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000",
|
hex"31371426000000000000000000000000000000000000000000000000000000000000000a0000000000007a6901010101010101010101010101010101010101010000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000164206eb0f8000000000000000000000000000000000000000000000000000000000000004500000000000000000000000000000000000000000000000000000000000001a40000000000000000000000000000000000000000000000000000000000000539000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000000005390000000000000000000000000101010101010101010101010101010101010101000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000230000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000",
|
||||||
0xb354049d0012ef7ec3edac6aba453daf4bdc2d28fe1d88138f94459799e2343f,
|
0x18c5c0b98ac8221b75b1f7bf3e36fc0d820d5866b23010f4861d8602066f93b0,
|
||||||
0x13a6f8b10007b41fa08c8efee85501fac2554571af99fe587b534fe28fdb82a3
|
0x45db6a091ddc9d19156c6d2f1d3aca7541733faeebdeed7b8572192d050e4e06
|
||||||
);
|
);
|
||||||
|
|
||||||
// execute enable, exodusSession: 13
|
// execute enable, exodusSession: 13
|
||||||
|
|||||||
@ -19,13 +19,13 @@ contract MockStaking is Test {
|
|||||||
constructor() {
|
constructor() {
|
||||||
mockReserve = new WETH9();
|
mockReserve = new WETH9();
|
||||||
StorageHistory history = new StorageHistory();
|
StorageHistory history = new StorageHistory();
|
||||||
gatekeeper = new Gatekeeper(address(history));
|
gatekeeper = new Gatekeeper(address(history), address(this));
|
||||||
gatekeeper.initialize(address(0));
|
gatekeeper.initialize(address(0));
|
||||||
history.setOwner(address(gatekeeper));
|
history.setOwner(address(gatekeeper));
|
||||||
}
|
}
|
||||||
|
|
||||||
function redoGatekeeper() external {
|
function redoGatekeeper() external {
|
||||||
Gatekeeper newGatekeeper = new Gatekeeper(address(0));
|
Gatekeeper newGatekeeper = new Gatekeeper(address(0), address(this));
|
||||||
newGatekeeper.initialize(address(gatekeeper));
|
newGatekeeper.initialize(address(gatekeeper));
|
||||||
|
|
||||||
address storageHistory = IGatekeeper(gatekeeper).storageHistory();
|
address storageHistory = IGatekeeper(gatekeeper).storageHistory();
|
||||||
|
|||||||
@ -92,6 +92,64 @@ contract GatekeeperRecallTest is Test {
|
|||||||
vm.stopPrank();
|
vm.stopPrank();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function test_gasPriceCorrectDuringRecall() public {
|
||||||
|
vm.startPrank(INITIALIZER);
|
||||||
|
Gatekeeper gatekeeper = Gatekeeper(payable(staking.gatekeeper()));
|
||||||
|
gatekeeper.updatePublicKeyMetadata(0, 0xb5cd0d028a5e1b6a4eecb113b7e49c8176385eb77c8f134bc1db4bddd7654de6, 0);
|
||||||
|
vm.stopPrank();
|
||||||
|
|
||||||
|
vm.startPrank(ALICE);
|
||||||
|
uint256 aliceBalance = ftso.balanceOf(ALICE);
|
||||||
|
ftso.approve(address(staking), type(uint256).max);
|
||||||
|
staking.stake(aliceBalance, ALICE, false, true);
|
||||||
|
|
||||||
|
uint256 ghostBalance = ghst.balanceOf(ALICE);
|
||||||
|
staking.ghost(bytes32(abi.encodePacked(ALICE)), ghostBalance);
|
||||||
|
vm.stopPrank();
|
||||||
|
|
||||||
|
vm.warp(block.timestamp + gatekeeper.FULL_GAS_RESTORATION_TIME() * 69);
|
||||||
|
|
||||||
|
uint256 bobBalanceBeforeFirst = ghst.balanceOf(BOB);
|
||||||
|
uint256 priceBeforeFirst = gatekeeper.getCurrentGasPrice();
|
||||||
|
assertEq(priceBeforeFirst, gatekeeper.MAX_ALLOWED_GAS_PRICE());
|
||||||
|
assertEq(ghst.balanceOf(BOB), 0);
|
||||||
|
|
||||||
|
vm.prank(BOB, BOB);
|
||||||
|
gatekeeper.verify(
|
||||||
|
hex"bf06188a000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000017508f1956a800000000000000000000000000000000000000000020000000000007a6980000000",
|
||||||
|
0x883302783b7f3d253d5bdeb17f39117641acdf061bf3fe457cb505df6b17dfc1,
|
||||||
|
0x8c3fc03b5cb738777ceec396ee8647f782d6670992f8f973de2dfc83379978d5
|
||||||
|
);
|
||||||
|
|
||||||
|
uint256 bobBalanceAfterFirst = ghst.balanceOf(BOB);
|
||||||
|
assertGt(bobBalanceAfterFirst, bobBalanceBeforeFirst);
|
||||||
|
assertEq(gatekeeper.getCurrentGasPrice(), 0);
|
||||||
|
|
||||||
|
vm.prank(BOB, BOB);
|
||||||
|
gatekeeper.verify(
|
||||||
|
hex"3137142600000000000000000000000000000000000000000000000000000000000000120000000000007a69010101010101010101010101010101010101010100000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000042b7ce50000000000000000000000000000000000000000000000000000000000",
|
||||||
|
0xf1f4d62d27c3d0388b2298b621b23cd5791e1b97d4423ffc16b14e81ff0df97c,
|
||||||
|
0xdbeed3eb94a829710147595c1b10f2ac6ec761c9721d8cc4711842c212ac517e
|
||||||
|
);
|
||||||
|
|
||||||
|
assertEq(ghst.balanceOf(BOB), bobBalanceAfterFirst);
|
||||||
|
assertEq(gatekeeper.getCurrentGasPrice(), 0);
|
||||||
|
|
||||||
|
vm.warp(block.timestamp + gatekeeper.FULL_GAS_RESTORATION_TIME() / 2);
|
||||||
|
uint256 gasPriceRestored = gatekeeper.getCurrentGasPrice();
|
||||||
|
assertEq(gasPriceRestored, gatekeeper.MAX_ALLOWED_GAS_PRICE() / 2);
|
||||||
|
|
||||||
|
vm.prank(BOB, BOB);
|
||||||
|
gatekeeper.verify(
|
||||||
|
hex"31371426000000000000000000000000000000000000000000000000000000000000000d0000000000007a6901010101010101010101010101010101010101010000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000064e4e33ef800000000000000000000000000000000000000000000000000000000000000010000000000000000000000000101010101010101010101010101010101010101000000000000000000000000010101010101010101010101010101010101010100000000000000000000000000000000000000000000000000000000",
|
||||||
|
0x0716f763060cfd52339544a203d0e156a42370b0e22d78ea9bf8766b0b66682b,
|
||||||
|
0xc2da93948f869c5102992bd1cbd70ef5f821ff522305c69d113faf2e89570ce7
|
||||||
|
);
|
||||||
|
|
||||||
|
assertGt(ghst.balanceOf(BOB), bobBalanceAfterFirst);
|
||||||
|
assertEq(gatekeeper.getCurrentGasPrice(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
function test_recallChainWorks() public {
|
function test_recallChainWorks() public {
|
||||||
vm.startPrank(INITIALIZER);
|
vm.startPrank(INITIALIZER);
|
||||||
Gatekeeper gatekeeper = Gatekeeper(payable(staking.gatekeeper()));
|
Gatekeeper gatekeeper = Gatekeeper(payable(staking.gatekeeper()));
|
||||||
|
|||||||
@ -15,7 +15,7 @@ contract MockStaking {
|
|||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
StorageHistory history = new StorageHistory();
|
StorageHistory history = new StorageHistory();
|
||||||
gatekeeper = new GatekeeperWeaver(address(history));
|
gatekeeper = new GatekeeperWeaver(address(history), address(this));
|
||||||
gatekeeper.initialize(address(0));
|
gatekeeper.initialize(address(0));
|
||||||
history.setOwner(address(gatekeeper));
|
history.setOwner(address(gatekeeper));
|
||||||
governor = msg.sender;
|
governor = msg.sender;
|
||||||
@ -29,7 +29,7 @@ contract MockStaking {
|
|||||||
function createNewGatekeeper() external {
|
function createNewGatekeeper() external {
|
||||||
require(msg.sender == governor);
|
require(msg.sender == governor);
|
||||||
|
|
||||||
GatekeeperWeaver newGatekeeper = new GatekeeperWeaver(address(0));
|
GatekeeperWeaver newGatekeeper = new GatekeeperWeaver(address(0), address(this));
|
||||||
newGatekeeper.initialize(address(gatekeeper));
|
newGatekeeper.initialize(address(gatekeeper));
|
||||||
|
|
||||||
address storageHistory = IGatekeeper(gatekeeper).storageHistory();
|
address storageHistory = IGatekeeper(gatekeeper).storageHistory();
|
||||||
@ -43,7 +43,7 @@ contract GatekeeperWeaver is Gatekeeper {
|
|||||||
using Checkpoints for Checkpoints.Trace256;
|
using Checkpoints for Checkpoints.Trace256;
|
||||||
using Checkpoints for Checkpoints.Trace160;
|
using Checkpoints for Checkpoints.Trace160;
|
||||||
|
|
||||||
constructor(address storageHistory) Gatekeeper(storageHistory) {}
|
constructor(address storageHistory, address staking) Gatekeeper(storageHistory, staking) {}
|
||||||
|
|
||||||
function filledEntries(uint256 session) public view returns (uint256) {
|
function filledEntries(uint256 session) public view returns (uint256) {
|
||||||
return _filledEntries[session];
|
return _filledEntries[session];
|
||||||
|
|||||||
@ -594,7 +594,7 @@ contract StakingTest is Test {
|
|||||||
vm.prank(address(previousGatekeeper));
|
vm.prank(address(previousGatekeeper));
|
||||||
IStorageHistory(storageHistory).trySetTransactionExecuted(34);
|
IStorageHistory(storageHistory).trySetTransactionExecuted(34);
|
||||||
|
|
||||||
Gatekeeper newGatekeeper = new Gatekeeper(address(0));
|
Gatekeeper newGatekeeper = new Gatekeeper(address(0), address(staking));
|
||||||
|
|
||||||
vm.prank(GOVERNOR);
|
vm.prank(GOVERNOR);
|
||||||
staking.updateGatekeeperAddress(address(newGatekeeper));
|
staking.updateGatekeeperAddress(address(newGatekeeper));
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user